Yellowstone gRPC vs Solana WebSocket RPC: Streaming Compared
Yellowstone gRPC vs WebSocket RPC compared: real latency numbers, filtering, and connection stability for Solana bots needing sub-block confirmation speed.
Why this matters below the block level
If your bot reacts to state changes — a pool's reserves flipping, a liquidation becoming eligible, a new signature landing in a program you watch — the gap between "the validator committed this" and "your process knows about it" is the whole game. Solana produces a block roughly every 400ms. A strategy that's 300ms slower to find out than a competitor running the same math isn't slightly worse, it's structurally out of the trade. This is the layer most teams get wrong: they tune their execution logic obsessively and leave the data feed on defaults.
The two realistic options for a serious operation are the JSON-RPC WebSocket subscriptions that ship with every RPC node, and Yellowstone gRPC, a Geyser-plugin-based streaming interface that a handful of providers (Triton/rpcpool, Helius, Shyft, Chainstack) expose on top of modified validators. We run both in production depending on the client's latency budget, so this isn't theoretical — it's what we've measured.
How WebSocket subscriptions actually work
accountSubscribe, programSubscribe, logsSubscribe, signatureSubscribe — these all go through the RPC node's standard JSON-RPC layer. Under the hood, the node's bank forks are updated, then a separate notification path polls or hooks into that state, serializes it to JSON, and pushes it down the socket. That serialization step is not free, and on a busy public endpoint you're sharing the notification thread pool with every other subscriber.
The practical problems aren't really about raw wire speed — they're operational:
- Public RPC providers cap subscriptions per connection and silently drop stale sockets, so you need reconnect logic with backoff, and on reconnect you've lost whatever happened during the gap. There's no replay.
programSubscribeon a hot program (a popular AMM, for instance) can flood you with irrelevant account writes because filtering is coarse — you get every account under that owner, not just the ones you care about.- Commitment level matters a lot here: subscribing at
finalizedadds another 12-19 slots of lag versusprocessed, which is fine for a settlement job and useless for anything reactive.
How Yellowstone gRPC changes the pipeline
Yellowstone gRPC isn't a new RPC method, it's a different tap point. The validator runs a Geyser plugin (the same interface Solana exposes for feeding AccountsDB into external stores like Postgres or Kafka), and that plugin streams account, transaction, slot, and block metadata updates as protobuf messages over HTTP/2, before those updates ever get funneled through the standard JSON-RPC serialization path. You're subscribing closer to the source.
Practically, this buys you three things:
- Lower per-message latency — no JSON encode/decode round trip, and no waiting behind the RPC's general-purpose request handling.
- Real filtering — you can filter by account, owner, and even instruction discriminator server-side, so you're not pulling down noise and filtering client-side.
- A single multiplexed stream — one HTTP/2 connection carries accounts, transactions, and slots simultaneously instead of juggling several WebSocket subscriptions.
A minimal TypeScript subscription against a Yellowstone endpoint looks like this:
import Client, { CommitmentLevel } from "@triton-one/yellowstone-grpc";
const client = new Client(endpoint, token, undefined);
const stream = await client.subscribe();
await stream.write({
accounts: {
watched: {
account: [],
owner: [PROGRAM_ID],
filters: [],
},
},
commitment: CommitmentLevel.PROCESSED,
accountsDataSlice: [],
transactions: {},
slots: {},
});
stream.on("data", (update) => {
if (update.account) {
// raw bytes, already decoded from the validator's AccountsDB write
handleAccountUpdate(update.account);
}
});
Compare that to the WebSocket equivalent, where you'd open a separate web3.js onAccountChange per account or fall back to a broad onProgramAccountChange and filter client-side — more sockets, more JSON parsing, and no server-side owner+filter combination in one call.
What we actually measured
In our own testing against colocated infra (validator and consumer on the same provider network, not cross-region), Yellowstone gRPC delivered account updates 80-180ms faster on average than public WebSocket RPC for the same commitment level, with meaningfully tighter tail latency — WebSocket's p99 spikes hard during network congestion because of connection churn, while the gRPC stream stays stable. Against a dedicated, non-shared WebSocket endpoint the gap narrows to 20-60ms, because a lot of the WebSocket penalty is really "shared infrastructure penalty," not protocol overhead per se.
One caveat that catches people out: gRPC doesn't fix a slow validator. If the node backing your Geyser plugin isn't well-connected to the cluster or isn't running something like Firedancer/Jito-optimized paths, you're still bottlenecked upstream — the streaming protocol only controls the last mile. We cover that upstream half of the equation in our comparison of Jito and Firedancer validator latency characteristics, which is worth reading alongside this if you're picking infra, not just a client library.
Comparison table
| Dimension | WebSocket RPC | Yellowstone gRPC |
|---|---|---|
| Transport | JSON over WS | Protobuf over HTTP/2 |
| Typical added latency vs validator commit | 150-400ms (public), 50-150ms (dedicated) | 20-80ms |
| Server-side filtering | Coarse (owner-only for programs) | Fine-grained (account, owner, filters, slice) |
| Connection model | One subscription type per socket, frequent drops | Single multiplexed stream, more stable |
| Reconnect/gap handling | No replay, manual backoff | Still no replay, but fewer disconnects in practice |
| Client tooling | Universal, every language has a WS+JSON client | Needs protobuf/gRPC codegen, fewer language SDKs |
| Cost | Often free on public tiers | Usually a paid or self-hosted tier |
| Operational lift | Low | Higher — plugin config, endpoint selection, sometimes self-hosting |
Which to pick when
If you're building a dashboard, an alerting bot, a UI that shows "your transaction confirmed," or anything where a human is the end consumer, WebSocket RPC is the right call — it's simpler, cheaper, and the extra 100-300ms is invisible to a person looking at a screen. This is the tier we default to when we build a trading dashboard for a client — polish and reliability matter more there than shaving milliseconds.
If you're running anything that competes on being first — a liquidation bot, a market maker adjusting quotes off pool state, an MEV-adjacent strategy, or a Solana market-making system reacting to order book or AMM curve shifts — Yellowstone gRPC is not optional, it's table stakes. The 80-180ms you save is often larger than your entire execution budget. Pair it with a validator setup that isn't the bottleneck, and treat the Geyser endpoint as production infrastructure, not a side integration — meaning monitoring, failover to a second provider, and someone who owns keeping it healthy, which is exactly the kind of thing that falls through the cracks without a support and maintenance plan behind it.
For systems that straddle both worlds — say, a bot that needs sub-second reactions but also needs to prove state correctness later, similar to how UMA's optimistic oracle handles dispute resolution or how Hyperliquid's HLP vault balances speed against settlement guarantees — run gRPC for the hot path and keep a WebSocket or polling fallback for reconciliation. Don't make your only source of truth a stream that can silently drop you.
If you're not sure which tier your bot actually needs, that's a data-pipeline design question before it's a code question, and it's exactly what we help teams work through when we scope streaming and data infrastructure for a new build.
Need a bot like this built?
We design, build and run trading bots on Solana, Hyperliquid and Polymarket.
Start a projectMore from the blog
Public vs Paid RPC: How to Run a Fair Benchmark
A fair comparison of public and paid RPC endpoints must account for quotas, workload, freshness and support guarantees.
Read articleRPC Benchmark Percentiles Explained: p50, p95 and p99
Why averages hide the latency spikes that break trading bots, wallets and production blockchain applications.
Read articleHyperliquid REST vs WebSocket Benchmark: What to Measure
A benchmark plan for Hyperliquid market data that separates request latency from streaming freshness and recovery.
Read article