Overview
OrbitFlare supports persistent WebSocket connections for real-time Solana data. WebSocket subscriptions push updates to your client as they occur on-chain — no polling required.
WebSocket endpoints use the wss:// scheme with the same region codes as the HTTP API:
wss://{region}.rpc.orbitflare.com?api_key=YOUR_LICENSE_KEY
For the auto-routed mainnet endpoint:
wss://mainnet.rpc.orbitflare.com?api_key=YOUR_LICENSE_KEY
Your license key is found in the Licenses section of your OrbitFlare Dashboard. Pass it as the api_key query parameter — the same key used for HTTP RPC.
Connecting
const WebSocket = require("ws");
const ws = new WebSocket(
"wss://mainnet.rpc.orbitflare.com?api_key=YOUR_LICENSE_KEY"
);
ws.on("open", () => {
console.log("Connected");
});
ws.on("message", (data) => {
const msg = JSON.parse(data);
console.log("Received:", msg);
});
ws.on("error", (err) => {
console.error("WebSocket error:", err);
});
ws.on("close", (code, reason) => {
console.log(`Connection closed: ${code} ${reason}`);
});
WebSocket connections idle for more than 60 seconds without any message exchange are closed by the server. Send a ping or keep your subscriptions active to maintain the connection.
Subscription Methods
accountSubscribe
Receive updates whenever a specific account’s lamport balance or data changes.
ws.on("open", () => {
ws.send(JSON.stringify({
jsonrpc: "2.0",
id: 1,
method: "accountSubscribe",
params: [
"83astBRguLMdt2h5U1Tpdq5tjFoJ6noeGwaY3mDLVcri",
{ encoding: "base64", commitment: "confirmed" }
],
}));
});
Update fields:
| Field | Description |
|---|
lamports | Current lamport balance |
data | Account data (encoding determined by the encoding param) |
owner | Owning program public key |
executable | Whether the account is an executable program |
rentEpoch | Epoch at which rent is next owed |
logsSubscribe
Receive transaction log messages in real time. Optionally filter to a specific program.
// All transactions
ws.send(JSON.stringify({
jsonrpc: "2.0",
id: 2,
method: "logsSubscribe",
params: ["all"],
}));
// Filter to a specific program
ws.send(JSON.stringify({
jsonrpc: "2.0",
id: 3,
method: "logsSubscribe",
params: [
{ mentions: ["675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8"] }, // Raydium AMM
{ commitment: "confirmed" }
],
}));
Update fields:
| Field | Description |
|---|
signature | Transaction signature (base-58) |
err | null if successful, error object if failed |
logs | Array of log message strings |
slotSubscribe
Receive a notification each time a slot is processed.
ws.send(JSON.stringify({
jsonrpc: "2.0",
id: 4,
method: "slotSubscribe",
params: [],
}));
Update fields:
| Field | Description |
|---|
slot | Current slot number |
parent | Parent slot number |
root | Highest confirmed root slot |
signatureSubscribe
Receive a one-time notification when a specific transaction signature reaches a given commitment level.
ws.send(JSON.stringify({
jsonrpc: "2.0",
id: 5,
method: "signatureSubscribe",
params: [
"TRANSACTION_SIGNATURE_HERE",
{ commitment: "finalized" }
],
}));
The subscription automatically closes after the first notification is sent.
programSubscribe
Receive updates for all accounts owned by a specific program.
ws.send(JSON.stringify({
jsonrpc: "2.0",
id: 6,
method: "programSubscribe",
params: [
"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", // SPL Token
{
encoding: "jsonParsed",
commitment: "confirmed",
filters: [{ dataSize: 165 }], // Standard token account size
}
],
}));
blockSubscribe
Receive full block data as each block is confirmed. Requires an add-on — contact support to enable.
ws.send(JSON.stringify({
jsonrpc: "2.0",
id: 7,
method: "blockSubscribe",
params: ["all", { commitment: "confirmed", encoding: "base64" }],
}));
rootSubscribe
Receive the highest confirmed root slot each time it advances.
ws.send(JSON.stringify({
jsonrpc: "2.0",
id: 8,
method: "rootSubscribe",
params: [],
}));
voteSubscribe
Receive raw vote transactions as they are observed in the gossip network. High volume — filter carefully.
ws.send(JSON.stringify({
jsonrpc: "2.0",
id: 9,
method: "voteSubscribe",
params: [],
}));
Unsubscribing
Each subscription method has a corresponding Unsubscribe method. Pass the subscription ID returned in the initial subscription response.
// Subscribe and capture the subscription ID
ws.on("message", (data) => {
const msg = JSON.parse(data);
// Subscription confirmation contains the subscription ID
if (msg.id === 1 && msg.result !== undefined) {
const subscriptionId = msg.result;
console.log("Subscribed, ID:", subscriptionId);
// Unsubscribe later
ws.send(JSON.stringify({
jsonrpc: "2.0",
id: 10,
method: "accountUnsubscribe",
params: [subscriptionId],
}));
}
});
Available unsubscribe methods: accountUnsubscribe, logsUnsubscribe, slotUnsubscribe, signatureUnsubscribe, programUnsubscribe, blockUnsubscribe, rootUnsubscribe, voteUnsubscribe.
Keepalive
WebSocket connections are closed after 60 seconds of inactivity. Send a JSON-RPC ping periodically to keep the connection alive:
const pingInterval = setInterval(() => {
if (ws.readyState === WebSocket.OPEN) {
ws.send(JSON.stringify({ jsonrpc: "2.0", id: 0, method: "ping" }));
}
}, 30_000);
ws.on("close", () => clearInterval(pingInterval));
Reconnection
Implement automatic reconnection with exponential backoff for production applications:
function connect(url, onMessage) {
let ws;
let delay = 1000;
let attempt = 0;
function createConnection() {
ws = new WebSocket(url);
ws.on("open", () => {
console.log("Connected (attempt", attempt + 1, ")");
delay = 1000; // reset backoff on successful connection
attempt = 0;
// re-subscribe to all channels here
});
ws.on("message", onMessage);
ws.on("close", () => {
attempt++;
const nextDelay = Math.min(delay * 2, 30_000);
console.log(`Reconnecting in ${delay}ms...`);
setTimeout(createConnection, delay);
delay = nextDelay;
});
ws.on("error", (err) => console.error("WebSocket error:", err));
}
createConnection();
return () => ws?.close();
}
const disconnect = connect(
"wss://mainnet.rpc.orbitflare.com?api_key=YOUR_LICENSE_KEY",
(data) => {
const msg = JSON.parse(data);
console.log("Update:", msg);
}
);
Connection Limits
WebSocket connections share the same per-IP limit as gRPC connections. See Authentication & Limits for details.
See Also