A crashed bot is easy. It stops, you notice, you restart it.
★The expensive failure is the bot that keeps running while getting worse.★ It still sends transactions, still logs successes, still reports healthy — and its fill rate has been declining for a week.
Uptime Is Not the Metric
The dashboard most teams build tracks whether the process is alive. That answers a question you rarely have.
| Common metric | What it misses |
|---|---|
| Process uptime | A running bot losing every race |
| Transactions sent | ★How many landed★ |
| Error count | Which errors matter |
| ★Average latency★ | ★The tail, where losses live★ |
| Wallet balance | Why it is changing |
★Send-to-land slot distance, as a distribution, is the single most useful number a trading bot can track.★ Everything else is context for interpreting it.
The Metrics That Earn Their Place
// ★Record on every submission, without exception.★
metrics.record({
submittedSlot,
landedSlot, // null if never landed
outcome, // success | reverted | expired
errorCode: outcome.err ? classify(outcome.err) : null,
priorityFeeLamports,
strategy, // ★attribute by source★
});
From that one record you derive everything that matters:
Landed rate. Landed divided by attempted. Not signatures returned — a signature means the RPC accepted bytes, nothing more.
Slot distance percentiles. Track p50, p90, and p99 separately. ★An average is arithmetic that describes no actual transaction.★
Outcome split. Success, reverted, expired — three states with three different causes. Collapsing them into "failed" destroys the diagnostic value.
Errors by class. Slippage, insufficient funds, exceeded CUs meant to be used, BlockhashNotFound. Each points at a different subsystem.
Fee spend against outcome. Rising fees with a flat landed rate means you are paying more for the same result, which is a signal in itself.
If your monitoring shows the submission path is the problem, a free BoltTx key is one line to compare against.
Why Percentiles and Not Averages
This deserves its own section because it is where most dashboards fail.
Bot A: every transaction lands in 3 slots
Bot B: 90% land in 1 slot, 10% land in 21 slots
★Both average 3 slots. They are not the same bot.★
Bot B loses ten percent of its races outright, and those losses cluster during congestion — which is when the opportunities are largest. An average tells you nothing about this, and a dashboard showing only averages will look stable while your worst-case behaviour deteriorates.
★Alert on p90 and p99, not on the mean.★ The mean is the last number to move when something breaks.
Silence Is a Failure Mode
The failure that kills bots quietly is the one where nothing errors.
An accountSubscribe stream stops delivering. A queue stops draining. A strategy stops triggering. ★No exception is thrown, no error is logged, and a health check on the process returns fine.★
// ★Liveness must be independent of the code path being monitored.★
let lastActivityAt = Date.now();
function onActivity() { lastActivityAt = Date.now(); }
setInterval(() => {
const quietMs = Date.now() - lastActivityAt;
if (quietMs > EXPECTED_MAX_QUIET_MS) {
alert(`No activity for ${Math.round(quietMs / 1000)}s`);
}
}, 15_000);
★The threshold has to come from the strategy's normal rhythm.★ A market maker quiet for a minute is broken. An arbitrage bot quiet for a minute may simply have found no opportunities. Set it from the observed distribution of quiet periods, not from a round number.
Alerting You Will Not Learn to Ignore
An alert that fires on every individual failure trains you to dismiss alerts. Since some failures are normal, alerting on instances guarantees noise.
★Alert on rate changes, not on events.★
// ★Compare against this bot's own recent baseline.★
if (landedRate < baseline.landedRate * 0.8) {
alert("Landed rate down 20% versus 24h baseline");
}
if (p90SlotDistance > baseline.p90 * 1.5) {
alert("p90 slot distance up 50%");
}
Tiers keep the signal meaningful:
| Severity | Example | Response |
|---|---|---|
| ★Page★ | Bot silent, balance draining, landed rate collapsed | Immediate |
| Warn | p90 degrading, fee spend rising, revert rate up | Same day |
| Log | Individual failures, lost races | Review in aggregate |
★A lost race is not an incident.★ Logging it is right; paging on it is how a team stops reading pages.
Attribution Beats Detection
Knowing something is wrong is half the job. Knowing which half is wrong is what lets you fix it before it costs another day.
// ★Separate the halves at record time, not at debug time.★
log({
detectLag: detectSlot - eventSlot, // data feed
decideLag: submitSlot - detectSlot, // your logic
landLag: landSlot - submitSlot, // ★submission path★
});
Without this split, a degrading fill rate is ambiguous between a slow feed, slow logic, and slow submission — and teams routinely buy a faster data feed to fix a submission problem.
Tag by strategy too. One strategy degrading while others hold steady is a strategy problem. All of them degrading together is infrastructure.
Reconcile Against the Chain
Your logs record what your bot believes happened. ★The chain records what happened.★
// ★Periodic reconciliation catches what logs cannot.★
const onChain = await connection.getSignaturesForAddress(wallet, { limit: 1000 });
const logged = await getLoggedSignatures(since);
const unlogged = onChain.filter((s) => !logged.has(s.signature));
if (unlogged.length) {
alert(`${unlogged.length} on-chain transactions not in logs`);
}
★Transactions on chain that your logs do not know about is the alarming direction.★ It means either a duplicate submission path, a retry that landed after you gave up on it, or something submitting with your key that you did not intend. All three are worth finding the same day.
What Landing Looks Like
Real transactions through our delivery nodes: median confirmation 336ms — under one slot.
★Your own dashboard should show more than a median★ — where the mass sits and how long the tail runs. The median tells you the typical case; the percentiles tell you whether you lose money.
Where BoltTx Fits
We handle submission. Not your monitoring stack, not your strategy.
Submissions route through our own delivery nodes in four regions with stake-weighted routing and no public mempool exposure. The property that matters for monitoring is consistency — a stable distribution makes deviations attributable to your changes rather than to network variance.
You sign locally. We never hold funds, never sign, and never modify transaction contents. The tip travels inside the transaction, paid on chain from your own wallet, and reverts with the transaction if it fails, because that is how Solana handles atomic transactions. You pay only on transactions that reach the chain.
Get a free API key. No monthly fee:
const connection = new Connection("https://la.bolttx.io/?api-key=YOUR_KEY");
FAQ
What should I monitor for a Solana trading bot? Send-to-land slot distance as a distribution, landed rate, the split between success, reverted and expired, errors by class, and fee spend against outcome. Uptime answers a question you rarely have.
Why are average latency metrics misleading? Because two bots with identical averages can have completely different tail behaviour, and losses concentrate in the tail. Track p50, p90, and p99 separately and alert on the upper percentiles.
How do I detect a bot that has silently stopped working? An independent liveness timer that fires when no activity has been recorded for longer than the strategy plausibly goes quiet. Process health checks pass while the strategy has stopped triggering.
What should trigger an urgent alert? Silence beyond the strategy's normal rhythm, a collapsed landed rate, unexpected balance movement, and on-chain transactions your logs do not know about. Individual failures belong in logs.
How do I avoid alert fatigue? Alert on rate changes against a rolling baseline rather than on individual events. Some failures are normal, so instance-level alerts guarantee noise and train people to dismiss them.
How do I tell whether my data feed or my submission path is slow? Record detect, decide, and land lags separately on every transaction. Without the split, a degrading fill rate is ambiguous, and teams often buy a faster feed to fix a submission problem.
What is a good landed rate for a Solana bot? It depends on strategy and conditions, so compare against your own recent baseline rather than an external number. A drop relative to your baseline is the signal, whatever the absolute figure.
Should reverted and expired transactions be tracked separately? Always. A revert means your instruction hit a condition on chain, while an expiry means it never executed. Combining them into "failed" removes the information you need to fix either.
How do I monitor fee efficiency? Track fee spend against landed rate over the same window. Rising fees with a flat landed rate means you are paying more for the same result, which is worth investigating before it compounds.
What does it mean if the chain shows transactions my logs do not? Either a duplicate submission path, a retry that landed after you stopped tracking it, or something submitting with your key that you did not intend. All three warrant same-day investigation.
How often should I reconcile logs against the chain? Frequently enough that a discrepancy is caught within hours rather than days. The direction that matters most is on-chain activity missing from your logs.
Should I alert on lost races? Log them, do not page on them. Losing races is expected in competitive strategies, and a rising lost-race rate is a warning-level trend rather than an incident.
How do I set the quiet-period threshold for liveness? From the observed distribution of quiet periods for that specific strategy. A market maker and an arbitrage bot have very different normal silences, so one global threshold is wrong for at least one of them.
What granularity should slot distance be recorded at? Per transaction, tagged by strategy and by network condition. Aggregating too early loses the ability to attribute a change to a specific strategy or to congestion.
Can I monitor a bot without changing its code? Partially, from chain data alone — landed rate and slot distance are derivable from signatures. What you cannot recover externally is why a transaction was sent and when the decision was made.
What is the first metric to add if I have none? Slot distance from submission to landing, recorded per transaction with the outcome. Nearly every other useful signal is either derived from it or interpreted against it.
Related Reading
- Solana Transaction Latency
- Solana Trading Bot RPC Setup
- Transaction Reliability for Solana DeFi Protocols
- Solana Transaction Retry Patterns
- Solana Transaction Landing