Browse documentation

WebSocket sessions and recovery

Design authenticated subscriptions, sequence cursors, bounded buffers and reconnect behavior for live operational views.

On this page
Before you start
  • A subscription authorization model
  • A replay retention policy
  • A bounded consumer buffer

Resume a subscription after a disconnect

Transport reconnection and application replay are separate steps. The cursor refers to the last committed application event.

Resume a subscription after a disconnectStep 1: Browser to Socket gateway. Establish secure session. Step 2: Browser to Socket gateway. Subscribe + cursor. Step 3: Socket gateway to Replay log. Check retained position. Step 4: Socket gateway to Browser. Replay retained events. Step 5: Live publisher to Socket gateway. Publish next event. Step 6: Socket gateway to Browser. Deliver live frame.BrowserSocket gatewayReplay logLive publisherEstablish secure session1Subscribe + cursor2Check retained position3Replay retained events4Publish next event5Deliver live frame6

Scroll across the diagram to see all four systems.

Inspect each exchange

Establish secure session

Validate the origin and authenticated session under the selected deployment pattern.

Separate WebSocket transport from the event contract

RFC 6455 defines an opening handshake, framing and connection control. It does not define subscriptions, event replay, delivery acknowledgement or business ordering. Those belong to the application protocol and must be documented as such.

Use wss for a secure browser connection. Validate browser Origin according to the application’s permitted origins, and authenticate the session under the chosen deployment pattern. A browser WebSocket constructor does not let application code set an arbitrary Authorization header; cookie sessions or short lived connection tickets need their own threat review.

Authorize every requested stream

A successfully opened socket is not permission to subscribe to every tenant or topic. Resolve subscription access from trusted identity, tenant membership and the requested resource. Reevaluate permission when membership changes or when a session is renewed.

Keep a compact application envelope with type, stream, event_id, sequence, occurred_at and payload. Define whether ordering applies to a stream, object or partition. A global order is expensive and often unnecessary when independent accounts can progress separately.

Application subscription and event framesjson
{
  "subscribe": {
    "type": "subscribe",
    "stream": "tenant_a.contacts",
    "after": "cursor_1042"
  },
  "event": {
    "type": "event",
    "stream": "tenant_a.contacts",
    "event_id": "evt_1043",
    "sequence": 1043,
    "occurred_at": "2026-09-14T10:30:00Z",
    "payload": {
      "contact_id": "contact_240",
      "stage": "qualified"
    }
  }
}

Resume from a committed cursor

Advance the cursor after the client has applied an event to its intended state, not merely after bytes arrived. On reconnect, ask for events after that committed position. Apply the same event identity rules to replayed and live events so a repeated frame does not duplicate an action.

When the cursor falls outside retention, return an explicit resynchronization requirement. Fetch an authoritative snapshot with a defined stream position, then continue from that boundary. Quietly attaching to the live tail would leave an invisible data gap.

StateApplication actionVisible outcome
ConnectingAuthenticate and request authorized subscriptions.Show that the view is reconnecting.
ReplayingApply retained events after the committed cursor.Keep the last confirmed data timestamp visible.
LiveProcess frames within the consumer budget.Advance the cursor after application.
Cursor expiredLoad a fresh snapshot and new boundary.Explain that the view is resynchronizing.
Access removedClose the subscription and stop protected updates.Return a permission state rather than infinite reconnect.

Bound the work a slow consumer can accumulate

MDN notes that the browser WebSocket API does not provide incoming backpressure. If messages arrive faster than the application processes them, memory and CPU use can grow. bufferedAmount describes outbound bytes queued by send; it is not an incoming backlog control.

Define application budgets: maximum queued events, maximum frame size and a policy for a slow consumer. For a replaceable dashboard value, coalescing updates may be appropriate. For an ordered ledger, disconnecting with an explicit resume or resync path is safer than silently dropping records.

Reconnect with a deadline and an observable state

Use bounded backoff with jitter after transient disconnections. Stop automatic reconnect for a confirmed permission denial until authority changes. Coordinate refresh so a page with several widgets does not create several competing sessions unnecessarily.

Protocol ping and pong frames are distinct from application heartbeat messages. Browser JavaScript does not directly control protocol ping frames. If the application defines a heartbeat, document what it measures and avoid treating it as proof that every downstream system is healthy.

Evaluate a subscription resume

Inspect application protocol decisions after a WebSocket session is established. Decision codes below describe this reference contract, not WebSocket close codes.

WS/api/v1/events

Contract inputs

Includes request values and the server validation context defined below.

Expected outcome

Decision 200

Resume accepted

Replay can start after the committed cursor before switching to live delivery.

{
  "type": "subscribed",
  "stream": "tenant_a.contacts",
  "resume_after": "cursor_1042",
  "mode": "replay_then_live"
}

Decision path

  1. Authorize the subscription
  2. Locate the retained cursor
  3. Replay the gap
  4. Join live delivery at its boundary
Input schema 4 fields
FieldTypeMeaning
subscription_allowedRequiredbooleanCurrent permission for the requested stream.
cursor_retainedRequiredbooleanWhether the replay position is still available.
queued_eventsRequiredintegerApplication events waiting to be applied.Minimum: 0
buffer_limitRequiredintegerConfigured application queue budget.Minimum: 1
Download JSON Schema

Standards and documentation

Explore the protocol specifications and platform guidance for this topic.

Bring the contract into your operating environment.

Discuss an implementation

Image preview