ShredStream is the fastest way to read Solana: instead of waiting for a block to be assembled, propagated, and served over RPC, you tap the shreds — the packets validators exchange while the block is still being produced. Done right, your system sees transactions while the block is still being produced, before anything downstream of an RPC blockSubscribe does.
This guide takes you from zero to a working shred feed. If you want the conceptual background first, read What Are Solana Shreds? — this post is purely practical.
Step 1: Pick your delivery mode
AllenHark ShredStream ships in two flavors, and the right one depends on how much latency you're actually paying for elsewhere:
| Shared gRPC | Direct UDP | |
|---|---|---|
| How it works | We verify and reassemble the shreds and stream you decoded entries (and the transactions inside them) over gRPC | Raw UDP packets — data and coding shreds — forwarded from our nodes straight to your server's IP |
| What you receive | Decoded entries, not raw shreds | Raw shreds; you deshred and verify |
| Integration effort | Low — a gRPC subscription | Higher — you parse shreds yourself |
| Best for | Monitoring, standard bots, testing the edge | HFT, snipers, systems that want the packets untouched |
| Pricing | $10/day (1 IP) · $59/week (2 IPs) · $199/month (3 IPs) | $199/month · dedicated $849/month |
Regions are Frankfurt and Amsterdam. Two rules of thumb. First, start with shared gRPC — the daily pass exists precisely so you can test the edge cheaply before committing. Second, direct UDP only pays off if your server is network-close to the source: if you're streaming across an ocean, the transit time swamps the parsing time you saved. That's what co-location is for.
There's also a free 1-hour trial, once per account, if you just want to see the feed.
Step 2: Get an API key
- Log in to the AllenHark Console
- Open ShredStream and choose a pass (daily/weekly/monthly)
- Copy your API key — it looks like
ak_1234567890and is sent as anx-api-key(orx-token) gRPC metadata entry on every connection
Step 3: Connect (shared gRPC)
The shared feed speaks the standard shredstream-proxy protocol on 88.216.132.50:9090. It is plaintext h2c — there is no TLS on this endpoint, so connect with http:// and insecure credentials. The service and messages are:
service ShredstreamProxy {
rpc SubscribeEntries(SubscribeEntriesRequest) returns (stream Entry);
}
message SubscribeEntriesRequest {}
message Entry {
uint64 slot = 1;
bytes entries = 2;
}
There are no server-side filters — you get every entry, votes included, in order. Filter client-side.
Rust
use tonic::{Request, transport::Channel, metadata::MetadataValue};
use shredstream_proxy_client::ShredstreamProxyClient;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let channel = Channel::from_static("http://88.216.132.50:9090")
.connect()
.await?;
let mut client = ShredstreamProxyClient::new(channel);
let mut request = Request::new(SubscribeEntriesRequest {});
let api_key = MetadataValue::from_str("YOUR_API_KEY")?;
request.metadata_mut().insert("x-api-key", api_key);
let mut stream = client.subscribe_entries(request).await?.into_inner();
while let Some(entry) = stream.message().await? {
println!("slot={} entries={} bytes", entry.slot, entry.entries.len());
// entry.entries is bincode-serialized Vec<solana_entry::entry::Entry>:
// deserialize it to get the transactions.
}
Ok(())
}
TypeScript
import * as grpc from "@grpc/grpc-js";
import * as protoLoader from "@grpc/proto-loader";
// shredstream.proto is published at https://allenhark.com/shredstream.proto
const def = protoLoader.loadSync("shredstream.proto");
const proto = grpc.loadPackageDefinition(def) as any;
// plaintext h2c — no TLS on this endpoint
const client = new proto.shredstream.ShredstreamProxy(
"88.216.132.50:9090",
grpc.credentials.createInsecure(),
{ "grpc.max_receive_message_length": 64 * 1024 * 1024 }
);
const metadata = new grpc.Metadata();
metadata.set("x-api-key", process.env.ALLENHARK_API_KEY!);
const stream = client.SubscribeEntries({}, metadata);
stream.on("data", (entry: { slot: number; entries: Buffer }) => {
console.log(`slot=${entry.slot} ${entry.entries.length} bytes`);
});
stream.on("error", (err: Error) => {
console.error("stream error, reconnecting:", err.message);
// production systems: reconnect with backoff here
});
The proto file is served from allenhark.com/shredstream.proto.
Step 4: Parse entries into transactions
Each message's entries field is a bincode-serialized Vec<solana_entry::entry::Entry>, where each Entry is { num_hashes: u64, hash: [u8; 32], transactions: Vec<VersionedTransaction> }. In Rust:
let entries: Vec<solana_entry::entry::Entry> =
bincode::deserialize(&entry.entries)?;
for e in entries {
for tx in e.transactions {
// VersionedTransaction — filter by program ID, account keys, etc.
}
}
Filter as early as possible. A busy slot carries thousands of transactions; if you only care about one program (a DEX, pump.fun, a specific pool), drop everything else before it touches your strategy code. For a worked example of program-level filtering for launch sniping, see Best Shreds Setup for Pump.fun.
Step 5 (optional): Go direct UDP
When you've validated the edge and want the parsing time back:
- Provision a server with a static IP — ideally in the same facility as the source (Frankfurt bare metal is the canonical choice)
- Give us the IP; we whitelist it and forward raw UDP shreds to your port
- Ingest with the jito-shredstream-proxy tooling or your own deshredder
You take over verification and reassembly — that's the deal: UDP gives you speed, you supply the reliability.
Common pitfalls
- Streaming across the Atlantic and wondering where the edge went. The shred edge is small; a transatlantic round trip swamps it many times over. Co-locate or pick the nearest region.
- Leaving the default 4 MiB gRPC message limit in place. A busy slot's entries blow straight through it. Raise the max receive message size on the client.
- No reconnect logic. gRPC streams drop — network blips, deploys. Reconnect with exponential backoff and expect to miss a slot or two; design the strategy to tolerate it.
- Parsing everything. Deserialize, filter by program ID, then process. The other order melts CPUs on busy slots.
- Treating shreds as confirmed data. You're seeing block production, ahead of consensus. A slot can be skipped. Act on shreds, confirm on commitment levels.
Where ShredStream fits in the stack
Shreds are the read side. If the goal is end-to-end speed you also need the write side: Slipstream for 0-slot transaction landing and Jito bundles when execution must be atomic. The full comparison of read paths — shreds vs gRPC vs RPC vs WebSockets — covers when each is the right tool.
Questions, or want the dedicated cluster? Join the Discord or head to the console and start with a $10 day pass.