> ## Documentation Index
> Fetch the complete documentation index at: https://docs.parlayx.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Reconnection & lifecycle

> Keepalive, automatic resubscribe, and terminal disconnects

The client keeps the connection healthy and recovers from drops on its own. In
the normal case you never write reconnect logic — you subscribe once, and your
subscriptions survive across disconnects. This page covers what happens
underneath so you know when to intervene.

## Keepalive

The client runs an application-level ping/pong on the open socket. If pongs stop
coming back it treats the connection as dead and tears it down, which kicks off a
reconnect. A single dropped pong is tolerated, so a brief network blip doesn't
cause a needless reconnect. This is layered on top of the server's own
connection-level keepalive — see
[Connection lifecycle](/streaming/connection).

## Reconnect with resubscribe

When the socket closes unexpectedly, the client reconnects with exponential
backoff and jitter, emitting a [`reconnecting`](/sdk/stream/events#lifecycle-events)
event before each attempt:

```ts theme={null}
stream.on("reconnecting", ({ attempt, delayMs }) =>
  console.warn(`reconnecting (attempt ${attempt}) in ${delayMs}ms`),
);
```

Server-assigned `subscriptionId`s are scoped to a single connection and don't
survive a reconnect, so the client replays your **active subscriptions** — the
`(market, channel)` pairs you asked for — on every new connection. You'll receive
a fresh `subscribed` ack and a new `snapshot` for each. Because resubscribe is
automatic, subscriptions you create before the socket is even open are honored too
(they're sent once the connection is ready).

The backoff budget resets only once a connection is **confirmed** by a `welcome`
frame — so a transient drop after a healthy session gets the full retry budget,
while an endpoint that never establishes a session is bounded (see below).

Subscriptions the server permanently retires are **not** replayed: a `status`
frame with `state: "closed"` or `"unsupported"`, or an `error` frame rejecting a
market at subscription time, prunes that entry so it isn't retried on reconnect.

## `goodbye` and terminal disconnects

Before closing a connection the server sends a [`goodbye`](/sdk/stream/events#server-frames)
frame with a `reason`. The client treats these two ways:

* **Recoverable** — `shutdown`, `ttl`, `idleTimeout`, and `noActiveSubs` (when you
  still have subscriptions to replay). The client reconnects normally.
* **Terminal** — `authRevoked` and `kicked` (and `noActiveSubs` when there's
  nothing left to resubscribe). Reconnecting with the same key would be futile, so
  the client stops.

When the client stops for good it emits a `terminated` event. This also fires if
reconnecting repeatedly fails without ever establishing a session (e.g. a bad
stream key or an unreachable endpoint), instead of looping forever.

`terminated` is final: that client will not reconnect. A fresh client starts with
none of your handlers or subscriptions, so wrap setup in a `start` function that
creates the client, registers handlers, and subscribes — then call it both
initially and from the `terminated` handler to resume:

```ts theme={null}
function start(streamKey: string) {
  const stream = createStreamClient({ streamKey });

  stream.on("snapshot", (frame) => {
    /* apply the snapshot to your local book */
  });

  stream.on("terminated", ({ reason }) => {
    /* final for this client — e.g. "goodbye:authRevoked" or "maxReconnectAttempts" */
    console.error(`stream terminated: ${reason}`);
    /* start fresh with a new key to resume */
    start(reloadStreamKey());
  });

  stream.subscribe([{ venue: "polymarket", outcomeId: "71045620195867637" }]);
  return stream;
}

const stream = start(process.env.PARLAYX_STREAM_KEY!);
```

## Closing intentionally

Calling `close()` yourself is not a disconnect the client recovers from — it
closes the socket and stops all reconnect attempts. Use it on shutdown or when
you're done streaming.

```ts theme={null}
stream.close();
```
