gRPC examples
Copy-paste Yellowstone gRPC subscription code with token auth for accounts, transactions, and slots in TypeScript, Rust, Python, and grpcurl.
// updated 2026-08-26
Working code to connect to Supanode gRPC and subscribe to streams.
Prerequisites
- A Supanode account on a plan with gRPC (FOCUS, BUILD, GROW, or PROFESSIONAL).
- Your token, issued on provisioning. Send it as
x-token(orAuthorization: Bearer) on every connection - see Authentication. - Your gRPC endpoint - default Frankfurt:
fra.sol.supanode.xyz:10010. - Yellowstone gRPC client library for your language, plus
geyser.protoandsolana-storage.protofrom the Yellowstone repo. Server reflection is disabled, so the proto files are required.
Before you write filters, read Limits. One filter holds at most 2 000 addresses and one subscription at most 10 filters. Sending your whole address budget in a single filter is the most common first mistake.
Don't have an account yet? Get a 24-hour free trial - contact us on Telegram: @supanode_tgs.
Test connection
Before writing code, verify your endpoint is reachable using grpcurl:
grpcurl -plaintext -import-path ./proto -proto geyser.proto \
-H 'x-token: sk_your_token_here' \
-d '{}' \
fra.sol.supanode.xyz:10010 geyser.Geyser/GetVersion
If you see a version number in the response, your token and connection both work. A missing or wrong token returns PermissionDenied.
Basic subscribe example
Subscribes to all successful transactions involving a specific program. The Python example generates its stubs from the Yellowstone gRPC geyser.proto.
import Client, { CommitmentLevel, SubscribeRequest } from "@triton-one/yellowstone-grpc";
// Second argument is your token — the client sends it as x-token.
const client = new Client(
"http://fra.sol.supanode.xyz:10010",
process.env.SUPANODE_TOKEN,
{ "grpc.max_receive_message_length": 64 * 1024 * 1024 }
);
const stream = await client.subscribe();
const request: SubscribeRequest = {
commitment: CommitmentLevel.CONFIRMED,
accounts: {},
slots: {},
transactions: {
myFilter: {
vote: false,
failed: false,
accountInclude: ["YOUR_PROGRAM_ID"],
accountExclude: [],
accountRequired: [],
},
},
transactionsStatus: {},
blocks: {},
blocksMeta: {},
entry: {},
accountsDataSlice: [],
};
stream.write(request);
stream.on("data", (data) => {
if (data.transaction) {
console.log(`Transaction: ${data.transaction.signature}`);
}
});
Production tips
-
Reconnection with exponential backoff. Network blips happen. Implement retry logic that starts at 1 second and backs off to 30 seconds. On
429or503errors, always back off before retrying. -
Ping/pong for keepalive. Yellowstone server sends ping every 15 seconds. Most client libraries handle this automatically.
-
Use
accountsDataSliceto reduce bandwidth. If you only need part of an account's data, specifyaccountsDataSlice: [{offset: 0, length: 40}]. -
Choose commitment level wisely.
processedis fastest but can revert.confirmedis the practical default for trading.finalizedadds ~13 seconds of latency. -
Handle stream restart gracefully. When your stream restarts, you'll miss events during downtime. Design your application to recover from this.
-
Do not read the first message as an acceptance. The server sends a
pingimmediately, and a rejection arrives after it. Wait for a real data message or an error before you consider the subscription live - see Limits. -
Close streams you stop using. Your address budget is counted across everything open at once, and closing a subscription frees it immediately.