WebSocket examples
Copy-paste WebSocket subscription examples for slot, account, and program updates in TypeScript, Rust, and Python.
// updated 2026-08-26
Copy-paste working examples for connecting to Supanode WebSocket.
Prerequisites
- An active Supanode Bundle subscription or free trial. Don't have one? Contact @supanode_tgs on Telegram.
- Your access token, issued on provisioning - see Authentication.
- The WebSocket endpoint URL (default:
wss://fra.sol.supanode.xyz:8900).
The token goes on the handshake, either as an x-token header or as an api-key query parameter.
Use the query parameter when your client cannot set handshake headers. @solana/web3.js is the common case - its wsEndpoint takes a URL and nothing else, so append ?api-key=... to it. Anything that lets you set headers should send x-token instead, since a query string ends up in logs.
Subscribe to slot updates
The lightest possible WebSocket subscription - useful as a smoke test.
import { Connection } from "@solana/web3.js";
const token = process.env.SUPANODE_TOKEN!;
const connection = new Connection("https://fra.sol.supanode.xyz:8899", {
httpHeaders: { "x-token": token },
// web3.js cannot set headers on the WS handshake — pass the token in the URL.
wsEndpoint: `wss://fra.sol.supanode.xyz:8900/?api-key=${token}`,
});
const subscriptionId = connection.onSlotChange((slotInfo) => {
console.log("New slot:", slotInfo.slot);
});
// To unsubscribe later:
// await connection.removeSlotChangeListener(subscriptionId);
Subscribe to an account
Stream updates for a single account.
import { Connection, PublicKey } from "@solana/web3.js";
const token = process.env.SUPANODE_TOKEN!;
const connection = new Connection("https://fra.sol.supanode.xyz:8899", {
httpHeaders: { "x-token": token },
// web3.js cannot set headers on the WS handshake — pass the token in the URL.
wsEndpoint: `wss://fra.sol.supanode.xyz:8900/?api-key=${token}`,
});
const accountAddress = new PublicKey("YOUR_ACCOUNT_PUBKEY");
const subscriptionId = connection.onAccountChange(
accountAddress,
(accountInfo) => {
console.log("Balance:", accountInfo.lamports);
console.log("Data:", accountInfo.data.toString("base64"));
},
"confirmed"
);
Subscribe to a program (with required filter)
programSubscribe requires either a dataSize or memcmp filter on shared plans. Whole-program subscriptions are blocked - see Restrictions.
import { Connection, PublicKey } from "@solana/web3.js";
const token = process.env.SUPANODE_TOKEN!;
const connection = new Connection("https://fra.sol.supanode.xyz:8899", {
httpHeaders: { "x-token": token },
// web3.js cannot set headers on the WS handshake — pass the token in the URL.
wsEndpoint: `wss://fra.sol.supanode.xyz:8900/?api-key=${token}`,
});
const programId = new PublicKey("YOUR_PROGRAM_ID");
const subscriptionId = connection.onProgramAccountChange(
programId,
(keyedAccountInfo) => {
console.log("Account:", keyedAccountInfo.accountId.toBase58());
console.log("Lamports:", keyedAccountInfo.accountInfo.lamports);
},
"confirmed",
[{ dataSize: 165 }] // required filter
);
Production tips
-
Reconnect with exponential backoff. WebSocket connections can drop. Implement retry starting at 1 second, capped at 30 seconds.
-
Re-establish subscriptions on reconnect. Subscription IDs are connection-scoped. After reconnect, all subscriptions are gone - resubscribe to what you need.
-
Send a ping every 30-60 seconds. Idle timeout is 10 minutes, but a periodic ping keeps the connection healthy and detects half-open sockets.
-
Watch your subscription budget. Total subs per plan is a hard cap. See Limits.
-
Switch to gRPC for high throughput. If you need many account / transaction streams at once, gRPC is the right tool.