Team Shyft
· January 24, 2026
Learn how to modify your yellowstone gRPC Subscribe Requests on Solana without stopping your stream or losing data

Solana Yellowstone gRPCs provide a powerful way to stream real-time blockchain events like transactions, account updates, and blocks using gRPC-based subscriptions. The type of data received from the stream is specified through a Subscribe Request, which allows developers to filter for particular updates such as transactions, accounts, or slots.
While Yellowstone gRPCs are a reliable technology for production applications that depend on continuous, real-time data streams, practical use cases often demand dynamic adaptability. In several use-cases, the information you first asked for when you started getting data isn’t exactly what you need later on, especially as your application or its users change. Modifying subscription requests on the fly — without disconnecting and re-connecting the stream — can be essential for several use-cases.
In this article, we will explore how we can modify a Subscribe request without disconnecting the stream.
To get started, we will need a few things.
**Authentication: gRPC endpoint and gRPC token
**Shyft’s gRPC nodes are available in various locations all across EU and the US region. To access, we would require a region-specific gRPC endpoint and an access token, which is available to purchase on your Shyft Dashboard.
**A server-side backend (like NodeJS) to receive gRPC data
**As gRPC services are unsupported in web-browsers, you would need a backend application such as C#, Go, Java, Python etc. to receive gRPC data.
The complete code for this article is available in our docs and on Replit — feel free to explore and test it out. We’ve also shared a collection of example use cases covering gRPC and DeFi on GitHub, which you can clone and experiment with.
Here is an example, which uses the client.subscribe() request to send a subscription, and the uses another client.write() to write the same subscribe request.
import Client, { CommitmentLevel, SubscribeRequestAccountsDataSlice, SubscribeRequestFilterAccounts, SubscribeRequestFilterBlocks, SubscribeRequestFilterBlocksMeta, SubscribeRequestFilterEntry, SubscribeRequestFilterSlots, SubscribeRequestFilterTransactions,} from "@triton-one/yellowstone-grpc";import { SubscribeRequestPing } from "@triton-one/yellowstone-grpc/dist/grpc/geyser";interface SubscribeRequest { accounts: { [key: string]: SubscribeRequestFilterAccounts }; slots: { [key: string]: SubscribeRequestFilterSlots }; transactions: { [key: string]: SubscribeRequestFilterTransactions }; transactionsStatus: { [key: string]: SubscribeRequestFilterTransactions }; blocks: { [key: string]: SubscribeRequestFilterBlocks }; blocksMeta: { [key: string]: SubscribeRequestFilterBlocksMeta }; entry: { [key: string]: SubscribeRequestFilterEntry }; commitment?: CommitmentLevel; accountsDataSlice: SubscribeRequestAccountsDataSlice[]; ping?: SubscribeRequestPing;}const subscribedWalletsA: string[] = [ "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", "5n2WeFEQbfV65niEP63sZc3VA7EgC4gxcTzsGGuXpump", "4oJh9x5Cr14bfaBtUsXN1YUZbxRhuae9nrkSyWGSpump", "GBpE12CEBFY9C74gRBuZMTPgy2BGEJNCn4cHbEPKpump", "oraim8c9d1nkfuQk9EzGYEUGxqL3MHQYndRw1huVo5h",];const subscribedWalletsB: string[] = [ "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P",];const subscribeRequest1: SubscribeRequest = { accounts: {}, slots: {}, transactions: { modifying_A: { vote: false, failed: false, signature: undefined, accountInclude: subscribedWalletsA, accountExclude: [], accountRequired: [], }, }, transactionsStatus: {}, entry: {}, blocks: {}, blocksMeta: {}, accountsDataSlice: [], ping: undefined, commitment: CommitmentLevel.PROCESSED,};const subscribeRequest2: SubscribeRequest = { accounts: { modifying_B: { account: [], filters: [], owner: subscribedWalletsB, }, }, slots: {}, transactions: {}, transactionsStatus: {}, blocks: {}, blocksMeta: { block: [], }, entry: {}, accountsDataSlice: [], ping: undefined, commitment: CommitmentLevel.PROCESSED,};async function updateSubscription(stream: any, args: SubscribeRequest) { try { stream.write(args); } catch (error) { console.error("Failed to send updated subscription request:", error); }}async function handleStream(client: Client, args: SubscribeRequest) { const stream = await client.subscribe(); const streamClosed = new Promise<void>((resolve, reject) => { stream.on("error", (error) => { console.error("Stream Error:", error); reject(error); stream.end(); }); stream.on("end", resolve); stream.on("close", resolve); }); setTimeout(async () => { console.log("🔁 Switching to second subscription request..."); await updateSubscription(stream, subscribeRequest2); }, 10000); stream.on("data", async (data) => { try { console.log("📦 Streamed Data:", data); } catch (error) { console.error("Error processing stream data:", error); } }); await new Promise<void>((resolve, reject) => { stream.write(args, (err: any) => (err ? reject(err) : resolve())); }).catch((reason) => { console.error("Initial stream write failed:", reason); throw reason; }); await streamClosed;}async function subscribeCommand(client: Client, args: SubscribeRequest) { while (true) { try { await handleStream(client, args); } catch (error) { console.error("Stream error. Retrying in 1 second...", error); await new Promise((resolve) => setTimeout(resolve, 1000)); } }}const client = new Client("YOUR-GRPC-URL", "YOUR-GRPC-TOKEN", undefined);subscribeCommand(client, subscribeRequest1);
In the above illustrated example we can see that we have two different subscribe requests. The stream begins with subscribeRequest1, which listens for transactions involving a predefined set of wallet addresses (subscribedWalletsA).
**Dynamic update
**After 10 seconds, the code calls updateSubscription() with subscribeRequest2, which switches the stream to monitor accounts owned by another wallet set (subscribedWalletsB) and starts listening for blocksMeta.
Join Medium for free to get updates from this writer.
This is done without ending or restarting the stream, thanks to the stream.write() method which sends a new SubscribeRequest mid-connection.
**Robust Error Handling
**The handleStream() function listens for error, close, or end events. If the stream breaks, the subscribeCommand() wrapper retries the connection after a 1-second delay—ensuring resilience in unstable network conditions or during backend hiccups.
Modifying a SubscribeRequest mid-stream in Solana Yellowstone gRPC is a critical feature for building responsive, production-ready applications that rely on real-time blockchain data. Here’s why this approach is so powerful:
In case you missed out, the complete code for this article is available in our docs and on Replit — feel free to explore and test it out. We’ve also shared a collection of example use cases covering gRPC and DeFi on GitHub, which you can clone and experiment with.
You can explore our other related articles: Streaming Real-Time Data on Solana, Real-Time Data Streaming with gRPC: Accounts, Transactions, Blocks, How to Stream Real-Time Pump.fun Updates on Solana, and Tracking New Pools on Raydium.

In this article you will learn how to implement a reconnect logic for your Solana gRPC streams with replay functionality...
January 24, 2026

A comprehensive guide on how to stream Transactions, Accounts, and Block updates swiftly using Shyft’s gRPC Services ...
January 22, 2026

A step-by-step guide to launch token, maximize token’s visibility and trading volume using Jito bundles on Raydium In th...
January 22, 2026
Get in touch with our discord community and keep up with the latest feature
releases. Get help from our developers who are always here to help you take off.