Skip to main content

Session Replay

Session replay records a visitor’s web session — a DOM snapshot plus the sequence of on-page interactions — while they’re on a page with the Orbit chat widget installed, and stores it against the conversation that visitor starts. When a support agent picks up that conversation later, they can play the recording back in the inbox and see exactly what the visitor saw and clicked, instead of relying on the visitor to describe it. It’s the asynchronous counterpart to live co-browse: co-browse is watching in real time, session replay is watching after the fact. This page covers the operator side — retention and size limits, playback in the inbox, purging recordings, and configuring what gets masked before it’s ever uploaded. The widget-side capture itself is automatic once the widget is installed; there’s nothing to integrate to start recording. For the full request/response schema, see the Session Replay API reference.

Retention and limits

There is no automatic TTL: a recording persists until you purge it. Deleting the conversation also removes its stored recording, so conversation retention and recording retention move together. Storage is bounded per recording, in two tiers:
  • Inline head — the first 5,000 events (up to 4 MB) are kept on the conversation row for instant preview. Long sessions don’t truncate: once the head fills, every further batch spills to durable object storage as an ordered chunk, and playback reassembles head plus chunks into the full stream.
  • Abuse backstop — a recording is hard-capped at roughly 1 GiB of serialized events (5 million events). Only a pathological or hostile recorder can reach it; when it trips, the recording’s status becomes capped and its truncated flag is set to true. Normal multi-hour support sessions stay well below the ceiling.
Each upload batch may carry at most 500 events — larger batches are rejected by the widget capture endpoint. There is no per-org cap or configurable retention policy today; purging is explicit via the API. To gauge usage, the list endpoint returns total_size_bytes and total_event_count per recording, so you can spot the conversations consuming the most storage.

Watching a recording in the inbox

In the dashboard, open the Inbox. Web-chat conversations that have a stored recording show a session-replay banner above the message thread. The banner lists the conversation’s recordings (page URL, start time, event count), and pressing play opens the rrweb player inline. Agents with conversations:read can list and play recordings; the banner’s delete control (purge) and the masking settings are restricted to owner, admin, or developer roles with conversations:write. The banner only appears on web/chat conversations — SMS, WhatsApp, voice, and email threads can never carry a widget recording, so the player surface is gated to where a recording can exist. Visibility isn’t gated on conversation status: replay is meant to be watched after the session, often on a closed thread. The masking policy also has a dashboard surface: Settings → Channels → Native chat includes a session-replay masking panel backed by the same GET/PUT /session-replay/privacy API — the toggles and selector lists below map one-to-one to the panel’s controls.

Failure modes to expect

  • Nothing recorded. The widget captures only after a visitor starts a conversation on a page with the widget installed. If no session-replay row ever appears, capture isn’t running — verify with the steps below before assuming data was lost.
  • Playback shows only the start of a long session. The recording offloaded its tail to durable storage and reassembly failed (a transient storage read error). The API serves the inline head rather than failing the request; retry, and the full stream usually returns. Persistent head-only responses on offloaded recordings (offloaded: true in the summary) are worth a support ticket.
  • A capped / truncated recording. The abuse backstop fired. Treat it as a signal that the recorder or page is emitting far more events than a real session produces — for example a page script in a rapid DOM-mutation loop.
  • Purging during erasure. DELETE /session-replay/{conversationId} removes the recording’s durable chunks first, then drops the row pointer, and writes an audit entry (session_replay.deleted). The conversation and messages are untouched. If the conversation itself is later deleted, any still-attached recording goes with it — purge recordings first when the erasure request covers the recording but not the thread.

Privacy posture and compliance

Masking happens in the visitor’s browser, before any event is uploaded — masked content never leaves the page. The default posture is fail-closed: every input is masked and built-in PII heuristics are on, until you explicitly relax them.
The policy is account-wide and applies to new capture sessions from the next widget bootstrap — it doesn’t retroactively change recordings you’ve already stored. Set block_selectors on your checkout or account-settings pages before you rely on session replay in production. Session replay is a tenant-owned control, and which knobs matter depends on the compliance surface your organization answers to:
  • GDPR / DSAR — session recordings of EU visitors are personal data. Your DPO should review the masking policy (what leaves the browser), the purge endpoint (your right-to-erasure mechanism), and the audit entries both produce. See GDPR posture guide and DSAR handling for how erasure requests map to Orbit’s purge surfaces.
  • Sector controls (PCI, health data) — if your pages render card data or regulated identifiers, rely on block_selectors for the hard “never serialized” cut rather than text masking, and document the selectors you set as part of your own control evidence.

Verifying capture

To confirm the widget is actually recording before you depend on it:
  1. Install the widget on a test page, open that page, and start a conversation as a visitor.
  2. Browse a little — click, scroll, navigate across one or two pages.
  3. Call GET /api/v1/session-replay (or open the conversation in the Inbox). A row for your test conversation with a growing total_event_count means capture is live.
  4. Fetch GET /api/v1/session-replay/{conversationId} and check that session_replay.status is recording (or ended once the visitor leaves) rather than capped.
An empty list after step 3 almost always means the widget script isn’t on the page the visitor started from — capture begins automatically at widget bootstrap and needs no extra integration.

Endpoints

See also