Documentation

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.

NOTE

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

  1. Reconnect with exponential backoff. WebSocket connections can drop. Implement retry starting at 1 second, capped at 30 seconds.

  2. Re-establish subscriptions on reconnect. Subscription IDs are connection-scoped. After reconnect, all subscriptions are gone - resubscribe to what you need.

  3. 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.

  4. Watch your subscription budget. Total subs per plan is a hard cap. See Limits.

  5. Switch to gRPC for high throughput. If you need many account / transaction streams at once, gRPC is the right tool.

Where to go next

Limits
Connection caps and subscription totals.
Restrictions
Blocked subscriptions.
Free Trials
24-hour trial.
Switch to gRPC
For high-throughput streams.