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

# Session Replay

> Reconnect to the WebSocket stream and replay missed events with zero gaps

When a WebSocket connection drops, you typically lose every event that happened while you were disconnected. hypernode solves this with **session replay**: pass a `session_id` and `since_seq` cursor on reconnect, and the server replays every missed event that matches your subscription filter before resuming the live stream.

## When to use this

* **Production trading systems** where gaps in the event stream can cause desync between your local state and the real chain state
* **Fill monitors** that track PnL and positions by watching `fill` events
* **Builder analytics** tracking every fill attributed to your builder address
* **Compliance and audit** pipelines that need to prove they received every event in a window
* **Any client that cares about reliability** — brief network blips, client crashes, container restarts, load balancer reconnects

If you don't care about gaps (sampling use cases, dashboards that refresh periodically), you don't need session replay. It's optional. Clients that don't pass `session_id` work exactly as before.

## How it works for the client

Every event on the WebSocket stream now carries a `seq` field. It's a monotonically increasing integer — each event gets a unique seq one higher than the last. Track the highest `seq` you've processed, and on reconnect you'll get exactly what you missed.

Example event with seq:

```json theme={null}
{
  "seq": 4404497,
  "type": "fill",
  "timestamp": 1776229763378,
  "consensus": "confirmed",
  "asset": "BTC",
  "user": "0x4b53ec7251039454d057757b6fde7e39e48b49a1",
  "data": {
    "coin": "BTC",
    "side": "B",
    "px": "74207.0",
    "sz": "0.02644",
    "dir": "Close Short",
    "closedPnl": "1.70538",
    "fee": "0.784813",
    "oid": 382009563898,
    "tid": 1094600066756112
  },
  "network": "mainnet"
}
```

## Reconnect flow

Pass `session_id` and `since_seq` as query params when reconnecting:

```
wss://hyper.polynode.dev/ws?key=YOUR_KEY&session_id=<uuid>&since_seq=<last_seq>
```

After you send your `subscribe` message, the server responds with:

1. A normal `subscribed` ack
2. A `reconnected` notification listing how many events will be replayed
3. The replayed events themselves (ordered by seq, already filtered)
4. A `replay_complete` message
5. Live events resume

### Subscribed ack

```json theme={null}
{
  "action": "subscribed",
  "id": "default",
  "sub_id": 5,
  "total_subs": 2,
  "newest_seq": 4423387,
  "session_id": "84391b47-cc77-4b01-97df-ff0944d94d9f"
}
```

### Reconnected notification

```json theme={null}
{
  "action": "reconnected",
  "id": "default",
  "from_seq": 4412795,
  "to_seq": 4423117,
  "total_events": 218,
  "total_chunks": 1
}
```

### Replay complete

```json theme={null}
{
  "action": "replay_complete",
  "id": "default",
  "replayed": 218,
  "resume_seq": 4423117
}
```

## Retention window

hypernode keeps up to **30 seconds** of recent events available for replay. If you reconnect within that window, every missed event that matches your subscription filter is delivered before live events resume. If your cursor is older than the window, you'll receive a gap signal instead.

### Gap signal

```json theme={null}
{
  "action": "reconnected",
  "id": "default",
  "gap": true,
  "oldest_available_seq": 4423117,
  "newest_available_seq": 4612394,
  "message": "cursor too old, gap detected — reload snapshot state"
}
```

When you see `gap: true`, your cursor was older than the oldest replayable event. Reload any snapshot state you were maintaining (positions, order book, etc.) from REST and start fresh. In practice this rarely happens — most clients reconnect within a few seconds.

## Full Python client

A reconnect-safe client that tracks the last seq and resumes automatically:

```python theme={null}
import asyncio, json, uuid, websockets

API_KEY = "pn_live_..."
SESSION = str(uuid.uuid4())

async def stream(last_seq=0):
    url = f"wss://hyper.polynode.dev/ws?key={API_KEY}&session_id={SESSION}"
    if last_seq > 0:
        url += f"&since_seq={last_seq}"

    async with websockets.connect(url) as ws:
        await ws.send(json.dumps({
            "action": "subscribe",
            "filters": {"action_types": ["fill"]}
        }))

        async for raw in ws:
            event = json.loads(raw)
            action = event.get("action")

            if action == "subscribed":
                print(f"Subscribed, newest_seq={event.get('newest_seq')}")
                continue
            if action == "reconnected":
                if event.get("gap"):
                    print("Gap detected — reload snapshot state")
                    # Reload positions, orderbook, etc. from REST here
                else:
                    print(f"Replaying {event['total_events']} missed events")
                continue
            if action == "replay_complete":
                print(f"Replay done, live at seq {event['resume_seq']}")
                continue

            # Normal event
            if event.get("seq"):
                last_seq = event["seq"]
            if event.get("type") == "fill":
                d = event["data"]
                print(f"{d['coin']} {d['sz']}@{d['px']} seq={event['seq']}")

    return last_seq

async def main():
    last = 0
    while True:
        try:
            last = await stream(last)
        except Exception as e:
            print(f"Disconnected ({e}), reconnecting with cursor {last}")
            await asyncio.sleep(1)

asyncio.run(main())
```

This client tracks the last seq it processed, and whenever the connection drops — for any reason — it reconnects with the cursor and receives exactly the events it missed.

## Limits

| Limit                 | Value      |
| --------------------- | ---------- |
| Retention window      | 30 seconds |
| Max events per replay | 10,000     |
| Max events per chunk  | 500        |

If you need longer retention or higher replay caps, reach out and we can tune these.
