.jpg)
WebSocket subscriptions (PubSub) are the nervous system of Solana applications. While HTTP requests handle state retrieval, WebSockets manage the reactive flow—notifying your backend the millisecond a trade clears or a balance shifts. In a network with 400ms slot times, polling is an anti-pattern that leads to stale UIs and missed execution windows.
So, instead of asking the network whether something changed, your application receives notifications when it happens—and all thanks to Solana WebSocket subscriptions.
For production systems, the challenge is not opening a WebSocket connection. The challenge is choosing the right subscription model, designing reliable event pipelines, handling reconnects, and knowing when WebSockets no longer fit the workload.
TL;DR
- Choose the narrowest subscription possible.
- Design reconnect and recovery workflows before production.
- Store state outside the WebSocket connection.
- Track slot lag and reconnect rates as first-class metrics.
- Move to Yellowstone gRPC when event volume becomes the bottleneck rather than waiting for outages.
Solana WebSocket subscriptions architecture
Solana exposes a PubSub interface over WebSockets through the JSON-RPC API. Clients register subscriptions, receive a subscription ID, and then receive notifications whenever matching events occur.
At a high level, the architecture looks simple:

In production, the WebSocket connection rarely lives inside the frontend.
Most teams terminate WebSocket subscriptions inside backend services where they control authentication, retries, event processing, storage, and observability. Frontends receive already-processed events from internal APIs.
Building a wallet notification system
Wallets are the most common WebSocket use case.
Users expect balances, token holdings, staking positions, and transaction statuses to update immediately after an action. Polling introduces latency and unnecessary load.
Subscriptions:
accountSubscribesignatureSubscribe
Architecture example:
.jpg)
Typical flow:
- User submits a transaction.
- Backend stores the transaction signature.
signatureSubscribetracks confirmation progress.accountSubscribemonitors affected accounts.- Backend updates wallet state.
- Frontend receives updates through an application API.
Example:
import { Connection, PublicKey } from "@solana/web3.js";
const connection = new Connection(process.env.RPC_URL!, {
wsEndpoint: process.env.WS_URL
});
const walletAccount = new PublicKey("YOUR_ACCOUNT");
let subscriptionId: number | null = null;
async function subscribe() {
subscriptionId = connection.onAccountChange(
walletAccount,
(accountInfo, context) => {
console.log("Slot:", context.slot);
console.log("Lamports:", accountInfo.lamports);
},
"confirmed"
);
}
async function reconnect() {
try {
if (subscriptionId !== null) {
await connection.removeAccountChangeListener(subscriptionId);
}
await subscribe();
} catch (err) {
console.error(err);
}
}One mistake appears repeatedly: subscribing only to the wallet address.
SPL token balances usually live inside token accounts. A wallet displaying only the main account state misses most asset changes.
Commitment level selection matters.
processeddelivers updates first.confirmedbalances speed and reliability.finalizedprioritizes settlement certainty.

For most consumer wallets, confirmed provides the best experience.
Dedicated WebSocket endpoints reduce dependency on public infrastructure and improve consistency during traffic spikes.
Building a transaction status tracker
Exchanges, payment systems, custody platforms, and wallets—all need visibility into transaction progress. signatureSubscribe exists specifically for this purpose.
Transaction lifecycle:
.jpg)
A tracking service typically stores signatures immediately after submission and subscribes to updates. Example:
const signature = "YOUR_SIGNATURE";
const id = connection.onSignature(
signature,
(result, context) => {
console.log("Status update:", result);
console.log("Slot:", context.slot);
if (result.err) {
console.error("Transaction failed");
}
},
"confirmed"
);Why use subscriptions instead of polling? Polling introduces two operational problems:
- Additional RPC traffic.
- Delayed status updates.
At scale, thousands of transactions per minute create a significant volume of unnecessary HTTP requests.
Building a token activity feed
Activity feeds power protocol dashboards, market intelligence platforms, and alerting systems. The goal is to detect protocol activity.
logsSubscribe is usually the correct choice.
Architecture:
%201%20(1).jpg)
Example:
const subscription = connection.onLogs(
"RAYDIUM_PROGRAM_ID",
(logInfo) => {
if (logInfo.err) return;
console.log("Signature:", logInfo.signature);
for (const log of logInfo.logs) {
console.log(log);
}
},
"confirmed"
);Why not use accountSubscribe?
Because protocols often update thousands of accounts. Monitoring individual account changes becomes operationally expensive and difficult to maintain.
logsSubscribe tells you that an activity occurred.
What it does not do:
- Decode protocol-specific events;
- Parse instructions;
- Reconstruct business logic.
Think of logsSubscribe as a detection mechanism rather than a complete data source.A common production workflow looks like this:
.png)
Scaling bottleneck
Raw log parsing becomes CPU-intensive during volatile periods. Many teams push logs into Kafka, NATS, or Redis Streams before decoding.
Building a blockchain explorer or analytics dashboard
Explorers need a broader view of the network. Instead of tracking a specific wallet or protocol, they continuously monitor chain activity.
Subscriptions:
blockSubscribeslotSubscribe
Architecture:
%201.jpg)
Why both? WebSockets provide live updates. HTTP RPC fills gaps after:
- Connection interruptions;
- Validator restarts;
- Infrastructure upgrades.
Just assume gaps exist. A resilient explorer treats subscriptions as a live stream and HTTP RPC as the source of recovery.
Other teams often make mistakes when relying on subscriptions as the only source of truth. After a reconnect, missing blocks create permanent holes in their analytics datasets.
Building validator and RPC monitoring systems
This is one of the most valuable WebSocket use cases and one of the least documented. Infrastructure teams need to answer questions such as:
- Is my RPC node falling behind?
- Is finalization progressing normally?
- Did a validator stop processing slots?
- Are subscriptions lagging?
Subscriptions:
slotSubscriberootSubscribeslotsUpdatesSubscribe
Architecture:
%201%20(1).jpg)
Monitoring example:
connection.onSlotChange((slotInfo) => {
console.log({
slot: slotInfo.slot,
parent: slotInfo.parent,
root: slotInfo.root
});
});Metrics worth collecting:
- Slot lag
- Root lag
- Reconnect count
- Event throughput
- Processing latency
- Message queue depth
A useful alert: Current slot—latest observed slot > threshold
This quickly identifies stale nodes.
Monitoring root progression often reveals network health issues earlier than application-level metrics.
Scaling issue
Many monitoring systems collect slot data but ignore processing latency. A node producing updates 30 seconds late appears healthy while serving stale data.
The framework for choosing the right subscription method
Most architecture problems start with choosing the wrong subscription. Use this framework:
When WebSockets stop scaling
WebSockets are limited by bandwidth and the overhead of maintaining thousands of individual filters. When your system needs to monitor the entire chain—or more than 50 active programs—you have outgrown WebSockets.
If you reach these limits, evaluate the RPC Fast Yellowstone gRPC implementation. It streams data directly from the geyser plugin, removing the JSON-RPC translation layer and providing the lowest latency possible on Solana.
Production pitfalls teams encounter
- Reconnect storms
Connection instability triggers repeated reconnect attempts. Without rate limiting, reconnect traffic becomes a self-inflicted outage.
- Duplicate notifications
Applications should assume duplicate delivery. Use idempotent processing keyed by signature and slot.
- Subscription state loss
Subscriptions disappear after reconnects. Maintain subscription definitions separately and restore them automatically.
- Commitment mismatches
Combining processed and finalized data sources often creates inconsistent application state. Choose commitments intentionally.
- Missing backfill logic
Every disconnect creates a potential gap. Track the last processed slot and replay missing data after recovery.
Excessive use of programSubscribe
programSubscribe appears attractive because one subscription covers an entire protocol. Without filters, message volume grows rapidly and overwhelms consumers.
Operational playbook:
- Store the last processed slot.
- Detect a disconnect.
- Reconnect.
- Recreate subscriptions.
- Backfill missing data.
- Resume processing.
If your architecture lacks these six steps, outages eventually create data loss.
Building real-time Solana applications with RPC Fast
Real-time Solana systems depend on reliable event delivery, low-latency RPC access, and a clear scaling path as workloads grow.
RPC Fast provides dedicated Solana RPC infrastructure, WebSocket endpoints, and Yellowstone gRPC services within the same ecosystem. This allows teams to start with account-level and protocol-level subscriptions and later adopt higher-throughput streaming architectures without redesigning infrastructure from scratch.
If your application depends on real-time Solana state, establish dedicated event infrastructure early, monitor event volume continuously, and design recovery workflows before production traffic arrives.
Further reading and references
The most effective Solana teams treat WebSocket subscriptions as an event ingestion layer, not as application state itself. That distinction is what separates a demo from a system that survives network upgrades, reconnects, and production traffic.


