Solana Transaction Latency: Measuring the Wrong Thing

RPC round-trip time is not transaction latency. The four segments between your code and a block, how to instrument each, and which one usually costs you money.

BoltTx Team··9 min read
solanalatencytransaction-landingmonitoringrpctrading-bot

Most people measure Solana transaction latency by timing the sendTransaction call. That number tells you how long your RPC took to say "received." It says almost nothing about when the transaction landed.

The two can differ by several slots, and the difference is where money is lost.

Four Segments, Not One Number

What people call latency is really four separate things stacked:

① build and sign          local, sub-millisecond
② your process → RPC      one network round trip
③ RPC → block producer    invisible to you
④ inclusion in a block    depends on fee and contention

Timing sendTransaction measures segment 2 and stops. ★Segments 3 and 4 are where the slots accumulate, and neither one appears in your client-side metrics.★

This is why a bot can report a low average latency and still consistently arrive after the price has moved.

The Only Measurement That Matters

Slot distance from submission to inclusion. Everything else is a proxy.

const submitSlot = await connection.getSlot("processed");
const sig = await connection.sendRawTransaction(raw, {
  skipPreflight: true,
  maxRetries: 0,
});

// Later, once it lands:
const status = await connection.getSignatureStatuses([sig], {
  searchTransactionHistory: true,
});
const landSlot = status.value[0]?.slot;

log({
  sig,
  submitSlot,
  landSlot,
  slotGap: landSlot ? landSlot - submitSlot : null, // null = never landed
});

★Slot distance is the metric because it is what the chain actually cares about.★ Milliseconds are a description of your network; slots are a description of your outcome.

Track the distribution, not the average. An average of two slots made up of half at one and half at three is a different system from one that is reliably at two.

If you have already measured this and the slot gap is the problem, a free BoltTx key is a one-line change to test against.

Instrumenting Each Segment

When the total is worse than you want, per-segment timing tells you where to look. Most teams measure only the total and end up guessing.

const t0 = performance.now();
const { blockhash, lastValidBlockHeight } =
  await connection.getLatestBlockhash("confirmed");
const t1 = performance.now();

const tx = buildAndSign(blockhash);
const t2 = performance.now();

const sig = await connection.sendRawTransaction(tx.serialize(), {
  skipPreflight: true,
  maxRetries: 0,
});
const t3 = performance.now();

log({
  blockhashFetch: t1 - t0,   // segment 2, inbound
  buildAndSign: t2 - t1,     // segment 1
  submitCall: t3 - t2,       // segment 2, outbound
  blockhashAge: t3 - t1,     // ★how much validity you already spent★
});

blockhashAge is the one almost nobody tracks and should. It is the portion of your validity window consumed before the transaction even reached an RPC. If it is large, your effective retry budget is much shorter than you assume.

Why Averages Mislead

Latency distributions on Solana are not symmetric. Most transactions cluster tightly; a minority take noticeably longer. An average sits between the two and describes neither.

If your strategy has an opportunity window of a slot or two, ★you live in the slow minority, not at the average★ — because the slow cases correlate with congestion, and congestion correlates with the moments worth trading.

This is also why provider latency comparisons tend to be uninformative. Under light load every path performs about the same. The differences appear when block space is contested, which is exactly when a benchmark run on a quiet afternoon will not capture them.

Connection Reuse Is Free Latency

One thing in segment 2 that is entirely under your control and frequently ignored.

Opening a fresh TLS connection per transaction means a full handshake before your bytes move at all. On a reused connection that cost disappears, and HTTPS on a warm connection costs essentially the same as plain HTTP.

import { Agent } from "undici";

// Keep connections warm across sends instead of handshaking each time.
const agent = new Agent({
  keepAliveTimeout: 60_000,
  connections: 8,
});

For a bot sending continuously, ★this is latency you are otherwise paying on every single transaction★ for no reason.

What Landing Looks Like

Real transactions through our delivery nodes: median confirmation 336ms — under one slot.

If your own distribution is materially wider than this, the gap is in segment 3 or 4 — routing or fees — rather than in your code.

Fixing Latency, In Order

Work top to bottom. The early items are cheap and explain most cases.

Reuse connections. Free, immediate, and frequently the largest single win in segment 2.

Refresh blockhashes in the background. Fetching on demand adds a round trip in the hot path. Cache and refresh on a timer.

Turn on skipPreflight. Preflight costs a round trip and simulates against a slot you will not land in, so it can pass and tell you nothing.

Derive priority fees from live conditions. A hardcoded value is wrong in both directions — wasteful when quiet, insufficient when contested.

Then look at the submission path. If the four above are clean and the slot gap still widens under load, what remains is the route toward a block producer and the stake weight behind it.

★That last one is the only item you cannot fix in application code★, which is why it belongs at the end rather than the beginning.

Where BoltTx Fits

We work on segment 3. Not indexing, not parsed history, not NFT metadata.

Submissions route through our own delivery nodes in four regions with stake-weighted routing and no public mempool exposure, so a transaction is not observable in transit before it lands. 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. If the transaction reverts, the tip reverts with it, 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:

// Pick the region closest to where your bot runs
const connection = new Connection("https://la.bolttx.io/?api-key=YOUR_KEY");

Then log slot distance for a week and compare distributions rather than averages.

FAQ

What is Solana transaction latency? The time between submitting a signed transaction and it being included in a block. It is usually measured in slot distance rather than milliseconds, because slots are the unit the chain actually schedules in.

How do I measure Solana transaction latency correctly? Record the slot at submission and the slot where the transaction landed, then track the difference. Timing the sendTransaction call only measures the round trip to your RPC, which is one of four segments.

Why is my RPC latency low but my transactions still slow? Because RPC latency measures your round trip to the endpoint, not what happens after. Forwarding toward a block producer and the wait for inclusion are separate segments that client-side timing never sees.

What is a good slot distance for a Solana transaction? Landing within two slots is a reasonable target for latency-sensitive workloads. What matters more is consistency — a tight distribution beats a low average with a long tail.

Why should I track the distribution instead of the average? Because Solana latency distributions are skewed. Most transactions cluster; a minority take much longer, and those correlate with congestion. If your opportunity window is short, you live in the slow minority rather than at the average.

Does connection reuse actually reduce latency? Yes, measurably. A fresh TLS connection requires a full handshake before any transaction bytes move. On a reused connection that cost is gone, and HTTPS costs essentially the same as plain HTTP.

What is blockhash age and why does it matter? It is how much of the roughly 150-block validity window was already consumed before your transaction reached an RPC. A large value means your effective retry budget is much shorter than you think.

Should I use skipPreflight to reduce latency? For production senders, usually yes. Preflight costs a network round trip and simulates against the current slot rather than the slot you land in, so it spends time without predicting your outcome.

Why does my latency get worse during congestion? Block space becomes contested, priority fees rise, and any weakness in the submission path stops being hidden. Latency does not degrade evenly — the distribution widens rather than shifting.

How do I compare two RPC providers on latency? Send alternating transactions through both and compare slot-distance distributions, bucketed by network condition. A comparison run during quiet periods measures the case where every path behaves the same.

Is latency or landing rate more important? They are the same measurement viewed differently. A transaction that takes too many slots eventually does not land at all, because the blockhash expires. Track slot distance and treat never-landed as the tail of the same distribution.

Does a dedicated node reduce transaction latency? It can help segment 2 by removing shared-capacity queuing. It does not change segment 3, where validator acceptance depends on stake weight rather than on whether the node is exclusively yours.

What tools can measure Solana transaction latency? You do not need one beyond your own logging. Record submit slot, land slot, and blockhash age per transaction, then aggregate. Third-party benchmarks measure someone else's network position, not yours.

Why do my latency numbers differ from a provider's published figures? Published numbers usually measure a round trip from a well-placed test machine under normal conditions. Your number includes your own geography, your connection handling, and the congestion you actually trade in.

How much does geography affect Solana transaction latency? Enough to matter for latency-sensitive workloads. Network round trip is often the largest term you directly control, which is why submitting to a nearby endpoint is usually a bigger win than micro-optimising your code.

Back to all posts