Solana Shred stream: deshredded transactions over WebSocket, before they execute
Last updated:
Raw shreds or deshredded transactions?
Choose by what your application consumes. Raw shreds let a node reconstruct data itself; deshredded transactions let a bot or research pipeline inspect signatures, accounts and instructions without operating that infrastructure.
| Requirement | Raw shred feed (UDP) | Triport Shred stream |
|---|---|---|
| What arrives | Shred packets | Complete transactions as JSON |
| Transport | UDP to an IP:port | Outbound WebSocket |
| Your infrastructure | Reachable public IPv4, UDP firewall rules, no NAT; deshredding and FEC recovery | One WebSocket client; no public IP, UDP or deshredder required |
| Account filter | Whole feed; filter after decoding | Server-side: up to 50 accounts on Pro, 200 on Business |
| Billing model | Provider-specific; check IP and region terms | Included in Pro and Business; no per-GB charge |
| Replay | No replay in the live UDP feed | No replay |
The raw-side setup follows the documented Jito proxy model, including its UDP and NAT requirements (Jito setup reference, checked ). Verify a replacement provider's requirements before moving a node. Triport's fmt=raw option means protobuf messages over WebSocket; it does not turn this product into a raw shred feed. If your node needs the raw UDP packets, compare the providers that sell raw UDP shreds by IP, region and price.
If you were on Jito ShredStream
Jito ShredStream closed on ; its sunset notice directs users to DoubleZero Edge (checked 2026-10-25). If you used shredstream-proxy to decode entries or transactions, the Shred stream can cover transaction delivery without running that proxy. Update your consumer for Triport's WebSocket JSON schema. If you fed raw shreds into your validator or RPC node, you still need a raw shred provider; this product does not supply those packets.
Plans that include the Shred stream
| Plan | Account filter | Concurrent streams per key |
|---|---|---|
| Pro | Required, up to 50 accounts | 2 |
| Business | Optional, up to 200 accounts | 4 |
| Enterprise | Included; limits set by contract | |
Not in the 7-day trial or Basic. Compare plans and pricing, then create a Pro or Business key with sol.preexec scope. No data-volume quota does not remove connection, filter or API RPS limits.
How it works
The leader broadcasts shreds; validators reconstruct transactions before execution. Triport subscribes to independent sources exposing that data, forwards the first arriving copy and de-duplicates later copies by signature. This covers individual source stalls without making you maintain several clients. Delivery begins after a source supplies a transaction, not before; this is not a shred pipeline of our own. For the mechanism, read how shreds and Turbine work, or the short definition of a Solana shred.
What you do not get
There is no execution status, error, logs, inner instructions, pre/post balances or compute-unit accounting. A transaction may fail or be dropped, and its slot may be skipped. The frame carries signature, slot, is_vote, account_keys including lookup-table addresses, pre_exec: true and ts. These fields describe observed intent, not a settled trade.
tx_pb_base64 is protobuf, not Solana's wire transaction format. Do not pass it directly to sendTransaction; decoding and re-encoding are required. There is no pre-execution equivalent on our Yellowstone gRPC endpoint.
Connect and handle close code 4029
Set TRIPORT_API_KEY and SOLANA_ACCOUNTS to your key and a comma-separated list of base58 public keys. The filter matches any listed account, including resolved lookup-table addresses. It stays fixed until you reconnect.
wscat -c "wss://triport.io/ws/sol-preexec?accounts=$SOLANA_ACCOUNTS" \
-H "x-token: $TRIPORT_API_KEY"For Node.js, install ws and run this as an ES module:
import WebSocket from "ws";
const url = new URL("wss://triport.io/ws/sol-preexec");
url.searchParams.set("accounts", process.env.SOLANA_ACCOUNTS);
let retry = 1000;
let socket;
let timer;
let stopping = false;
function connect() {
socket = new WebSocket(url, {
headers: { "x-token": process.env.TRIPORT_API_KEY },
});
socket.on("message", (data) => {
retry = 1000;
const tx = JSON.parse(data.toString());
console.log(tx.signature, tx.slot, tx.pre_exec);
});
socket.on("error", (error) => console.error(error.message));
socket.on("close", (code, reason) => {
const text = reason.toString();
let error = text;
try { error = JSON.parse(text).error ?? text; } catch {}
if (code === 4029) {
console.error(error === "superseded_by_new_connection"
? "Replaced by a newer connection on this key."
: error === "stream_limit"
? "New connection refused: stream limit."
: "Stream capacity refusal: " + text);
return; // Coordinate processes / free a slot before restarting.
}
if (stopping || code === 4001 || code === 4003) return;
timer = setTimeout(connect, retry + Math.random() * 1000);
retry = Math.min(retry * 2, 30000);
});
}
connect();
process.on("SIGINT", () => {
stopping = true;
clearTimeout(timer);
socket.close(1000);
});At capacity, 4029 superseded_by_new_connection closes the oldest connection after a newer one is accepted; 4029 with JSON {"error":"stream_limit"} refuses the new connection. The example stops on either capacity refusal so competing processes cannot keep displacing each other. Coordinate ownership, free a slot, then restart with backoff. Fix credentials on 4001; on 4003, check the tier, required filter and account count before retrying.
Read continuously and move expensive processing off the socket handler. Delivery is at-most-once: under backpressure, new frames are dropped when your buffer fills. Reconnection resumes live data without replaying gaps. Keep consumers idempotent by signature and close cleanly on shutdown to release the stream slot.
Confirm the outcome
React on intent, confirm on a commitment channel. Follow the account-filtering and signatureSubscribe guide to pair Shred stream signatures with WebSocket (Pub/Sub) confirmation. Reconcile failures and missing outcomes before recording a successful trade. For a separate submission path, see sending Solana transactions with sendBundle.
How much earlier?
This page gives no timing figure yet. Measure from your region: record local receive times for the same signature on this stream and a gRPC processed transaction subscription. Report the observation window, client region, filters and missing matches. The ts field is our server clock when building the delivery frame; comparing it directly with your clock includes clock skew. It is not the leader's timestamp.
When Triport is the wrong choice
Choose another delivery model if you need raw shreds for your node, replay after disconnection, or guaranteed delivery to a slow consumer. Pro cannot deliver an unfiltered feed; that requires Business. Standard Pro and Business regions are EU and US; Asia or a custom location requires a separate arrangement. For executed data with commitment filters, use Solana gRPC (Yellowstone).
FAQ
- Is this a Solana ShredStream?
- At the transaction level, yes: the Shred stream delivers complete deshredded transactions as JSON over WebSocket. It does not deliver raw UDP shred packets for a validator or RPC node.
- How is this different from a mempool stream?
- Solana has no public mempool. This feed observes transactions reconstructed from leader shreds after sequencing, before execution results exist. It is an intent signal, not a pending-transaction queue or a promise of successful execution.
- Does this replace Jito ShredStream?
- It can replace the transaction-consumption step if you previously decoded shreds in a proxy. It requires a WebSocket integration change. If your node needs raw shreds, use a raw feed; Jito's sunset notice directs users to DoubleZero Edge.
- Can I send the transactions I see?
- Do not pass tx_pb_base64 directly to sendTransaction. It contains a protobuf transaction, not Solana's canonical wire encoding. Re-encoding is required, and observing a transaction does not guarantee it will execute or land.
- Can I change the account filter without reconnecting?
- No. The accounts query parameter is fixed for the connection. Close the old socket cleanly and reconnect with the replacement list; there is no in-stream filter update.
- How many streams can one key hold?
- Pro allows 2 concurrent Shred stream connections per key; Business allows 4. Enterprise limits are contractual. A connected standby also uses a slot. At the limit, handle both 4029 reasons: superseded_by_new_connection and stream_limit.