How to Improve Solana Transaction Landing Rate
Getting a transaction submitted is only half the battle on Solana. The other half is making sure it actually lands in a block. This guide covers the key factors that affect transaction landing rate and how to optimize them.
Why Transactions Fail to Land
Solana transactions can fail to land for several reasons:
| Reason | Frequency | Fixable? |
|---|---|---|
| Stale blockhash | Very common | Yes — use recent blockhash, retry quickly |
| Insufficient priority fee | Common | Yes — set appropriate compute unit price |
| Slippage exceeded | Common | Yes — widen slippage or execute faster |
| Compute budget exceeded | Occasional | Yes — set correct compute units |
| Network congestion | Periodic | Partially — use Jito bundles |
| Validator not reached | Occasional | Yes — multi-region submission |
Most failed transactions come down to three things: timing, fees, and submission method.
1. Use Jito Bundles Instead of sendTransaction
The single biggest improvement you can make is switching from sendTransaction on a standard public path to Jito bundle submission.
Why Bundles Land Better
- Direct block-engine path — bundles include a tip that goes directly to the block producer, which can be more reliable than compute unit price bidding alone.
- Atomic execution — the bundle either fully executes or is dropped. No partial execution, no wasted fees on failed txs.
- Direct submission — bundles go directly to the block engine instead of relying on the usual public submission path.
- Multi-region submission — sending to multiple block engines increases the chance of reaching the current leader.
Standard RPC vs Jito Bundles
// Standard RPC — standard public submission path
const sig = await connection.sendRawTransaction(tx.serialize(), {
skipPreflight: true,
});
// Jito bundles — direct to block engine
const result = await fetch('https://api.venum.dev/v1/swap', {
method: 'POST',
headers: { 'Content-Type': 'application/json', 'x-api-key': API_KEY },
body: JSON.stringify({
transaction: Buffer.from(tx.serialize()).toString('base64'),
quoteId: build.quoteId,
}),
}).then(r => r.json());Teams that care about landing quality often prefer bundles or other dedicated submission paths instead of relying on a single public RPC endpoint.
2. Set Compute Budget Correctly
Every Solana transaction has a compute unit (CU) budget. If your transaction exceeds it, it fails. If you set it too high, you waste priority fee.
Common Mistakes
- Default CU limit (200K) — some swap transactions need 300-500K CU. If you don't set it, the default may not be enough.
- Excessive CU limit (1.4M) — setting the max wastes your priority fee since
fee = CU_limit * CU_price.
Right Approach
Simulate first, then set CU slightly above what the simulation consumed:
// Venum handles this automatically — the returned transaction
// already has optimized compute budget instructions
const { transaction, computeUnits } = await fetch(
'https://api.venum.dev/v1/swap/build',
{ /* ... */ }
).then(r => r.json());
// computeUnits tells you exactly what was allocated3. Optimize Priority Fees
Priority fees (compute unit price) determine where your transaction lands in the block. Too low and you get dropped during congestion. Too high and you overpay.
Fee Strategy
| Network Condition | CU Price | Notes |
|---|---|---|
| Low congestion | 1,000-10,000 micro-lamports | Most txs land easily |
| Normal | 10,000-100,000 | Safe for most operations |
| High congestion | 100,000-1,000,000+ | Spikes during popular mints, market moves |
Dynamic Fee Estimation
Rather than hardcoding, use recent block data to estimate appropriate fees:
// Get recent priority fee levels
const fees = await connection.getRecentPrioritizationFees();
const median = fees
.map(f => f.prioritizationFee)
.sort((a, b) => a - b)[Math.floor(fees.length / 2)];When using Jito bundles, the tip is separate from compute unit price.
4. Handle Blockhash Expiry
Solana blockhashes expire after ~60 seconds (150 slots). If your transaction isn't included by then, it's gone.
Best Practices
- Get the blockhash as late as possible — right before signing, not minutes ahead
- Use
maxRetries: 0withsendRawTransactionand handle retries yourself — the default retry logic can keep resending with a stale blockhash - Set
lastValidBlockHeightand check it before retrying
// Get fresh blockhash right before signing
const { blockhash, lastValidBlockHeight } =
await connection.getLatestBlockhash('confirmed');
// Set it on the transaction
tx.message.recentBlockhash = blockhash;
tx.sign([wallet]);
// When retrying, check if blockhash is still valid
const currentHeight = await connection.getBlockHeight();
if (currentHeight > lastValidBlockHeight) {
// Blockhash expired — rebuild with new blockhash
}When using Venum's /v1/swap/build, the transaction comes with a fresh blockhash. Submit it promptly after signing.
5. Multi-Region Submission
Solana's leader schedule rotates among validators worldwide. If you only submit to one RPC endpoint, your transaction might need to hop across the network to reach the current leader.
Why This Matters
- Solana block time is ~400ms
- Network propagation between regions can take 50-100ms
- Missing one leader slot means waiting for the next one
Solution: Submit to Multiple Endpoints
Submitting through multiple viable channels can improve the odds of reaching the right path in time. If you do not want to build that plumbing yourself, Venum's transaction sending endpoint can help handle the submission step.
6. Fast Confirmation with Pre-Confirmation Stream
Don't poll RPC for confirmation — it adds 1-3 seconds of latency. Venum's transaction stream gives you a fast processed signal and an optimistic early landed signal, both well before finalized RPC state.
// Slow: polling RPC
const confirmation = await connection.confirmTransaction(signature); // 1-3s
// Fast: pre-confirmation via Venum SSE
const source = new EventSource(
`https://api.venum.dev/v1/stream/tx?signatures=${signature}&events=landed,processed&apiKey=${API_KEY}`
);
source.addEventListener('tx', (e) => {
const { status } = JSON.parse(e.data);
if (status === 'processed') {
// fast post-submit visibility without raw RPC polling
}
});Faster transaction visibility means faster retry on failure, which means higher effective landing rate.
7. Retry Strategy
When a transaction fails, how you retry matters:
Do
- Re-quote before retrying — pool state changes every block. Your original quote may be stale.
- Get a fresh blockhash — never retry with the same blockhash.
- Back off on rate limits — if you're hitting 429s, slow down.
- Check the error — some failures aren't retryable (insufficient balance, invalid account).
Don't
- Don't retry the exact same transaction — if it failed on-chain, the same inputs will fail again.
- Don't retry indefinitely — set a max retry count (2-3 is usually enough).
- Don't retry on slippage errors without re-quoting — the price has moved, your original route is stale.
Summary: Landing Rate Checklist
- Use Jito bundles instead of relying only on a standard public submission path
- Set compute budget correctly (not default, not max)
- Optimize priority fees based on current network conditions
- Submit to multiple regions simultaneously
- Use fresh blockhashes and submit immediately after signing
- Confirm via pre-confirmation stream for faster retry loops
- Re-quote on retry — don't resubmit stale transactions
Venum can help with the submission path and transaction lifecycle plumbing so you do not have to build all of that yourself.
Next Steps
- Jito Bundles guide — deep dive into bundle mechanics
- Transaction Submission reference — API details
- TX stream reference — real-time confirmation tracking
