Skip to main content
The Realtime WebSocket is designed for long-lived connections. Plan for transient disconnects on every deploy boundary and for occasional backpressure-driven disconnects under load.

Close codes

In addition to application ping/pong, the server emits standard WebSocket control ping frames roughly every 30 seconds.

Replay with last_seq

Persist the highest seq you have fully processed (not just received). On reconnect, supply it as a query parameter:
The server resumes from last_seq + 1 if that sequence is still inside the JetStream window (~24h). If the cursor is older than retention, the server starts from DeliverNew — you must then hydrate via HTTP. When reconnecting:
  1. Open WebSocket with ?last_seq=.
  2. Wait for connected.
  3. Re-send the exact same scope.set you had before — server state does not persist across sockets.
  4. Process events; advance your stored last_seq only after each event is durable in your system.

Hydration after long gaps

If you’ve been offline longer than retention (~24h), or it is your first connect, run HTTP reads in parallel before going live. Recommended order:

Backpressure

If your consumer cannot keep up with delivery rate, the server will close the socket with 4002 rather than buffer unbounded memory. To avoid 4002:
  • Use the narrowest scope and entity filter that satisfies your use case.
  • Process events on a non-blocking queue — do not do synchronous HTTP/DB work in the WebSocket read loop.
  • Persist last_seq after each batch so 4002 reconnects are cheap.

Suggested backoff

Never retry 4001 without first re-validating credentials — a tight loop will rate-limit your firm key.