Skip to main content
The real-time channels are straightforward to subscribe to, but there are a few patterns worth following to avoid dropped or duplicated data. This page covers the essentials — see Real-time Data for full code examples.

Snapshot + subscribe

Don’t rely on the live feed alone to build initial state. Subscribe first, then seed from REST inside the subscribed handler. This closes the gap between “when you fetched the snapshot” and “when your first publication arrives”:
  1. Create a subscription with positioned: true, recoverable: true
  2. In the subscribed handler, fetch current state from REST
  3. Apply live updates as publications arrive
On reconnects, the same subscribed handler fires — check wasRecovering and recovered to decide whether you need to re-seed (see Recovery).

Recovery flags

Pass both flags together on channels with history enabled:
client.newSubscription("order_book:market_abc123", {
  positioned: true,
  recoverable: true,
});
positioned bookmarks your place in the stream. recoverable uses that bookmark to replay missed messages on reconnect. Either flag alone does nothing useful — you need both. For channels without history (best_odds, parlay_markets), omit both and re-seed from REST on every reconnect. See Namespace history capabilities for which channels support recovery.

Recovery

After a reconnect, the subscribed event tells you whether your local state is still consistent:
wasRecoveringrecoveredWhat happenedAction
truetrueHistory replay filled the gapNothing — state is consistent
truefalseHistory window expired before reconnectRe-seed from REST
falseFresh connectSeed from REST
The recovery window is 5 minutes. After that, or if the server stream was reset, recovered will be false and you must re-seed.

Deduplication

At-least-once delivery means a message can be replayed more than once during recovery. Every publication includes a messageId in ctx.tags — track seen IDs and skip duplicates:
const seen = new Set();
sub.on("publication", (ctx) => {
  const id = ctx.tags?.messageId;
  if (seen.has(id)) return;
  seen.add(id);
  applyUpdate(ctx.data);
});
For long-running processes, cap your dedup set (e.g. last 1,000 IDs) to avoid unbounded memory growth.

512 channel limit

Each connection supports a maximum of 512 simultaneous subscriptions. If you exceed this, the subscribe call returns error code 106. Create additional client instances for additional channels — each gets its own connection and its own 512-slot budget.

Slow consumer

The server buffers up to 1 MB per connection. If your publication handler is slow, the buffer fills faster than it drains and the server closes the connection. Hand off incoming messages to a queue immediately — do not do heavy work inline. Unexpected disconnects that aren’t auth errors are often a saturated buffer.

Real-time Data →

Full code examples for all patterns above, plus common failures and error codes.