Dozor
Replays

Player & scrubbing

Click any session row in the Replays list to open the player at /replays/{sessionId}. The page stacks vertically:

  1. Compact header — badges with session id, user, project, duration, screen size, date.
  2. Viewport + side panel — rrweb player on the left, side panel on the right with two tabs (History, Console).
  3. Control bar — playback controls + the seek bar.

Compact header

A row of small badges above the player. Each badge shows one piece of session metadata via an icon + value:

  • Session id — the SDK-side externalId (UUID) with a copy button.
  • User — the identified user (if any), linked to their detail page at /users/[id].
  • Project — project label.
  • DurationMM:SS total.
  • Screen size — e.g. 1920×1080.
  • Date — when the session was created.

A separate Reload button (orange, pulsing) appears in the header when background polling detects new events or that the session has just ended. Clicking it remounts the player against the fresh snapshot — playback resets to t=0. The button stays hidden when there's nothing to act on, so the orange signal carries weight when it appears.

History — derived in the browser

The replay plays the full session as one continuous stream — there is no chunking on the playback side. The side panel's History tab turns the same stream into a chronological feed of timeline annotations the user can click to seek. Folding happens at read time in a pure module (src/lib/history/) over the decompressed events.

Four item kinds appear in the feed:

  • init — first item. Spans from the session start up to the first navigation (or the session end, whichever comes first).
  • navigation — opens whenever a dozor:url rrweb custom event (type=5) lands. Hash-only and query-only changes don't fire (?utm=… rewrites and anchor jumps stay inside the current section).
  • idle — emitted when the gap between two consecutive events exceeds the threshold (30s by default). Sits as a marker inside the surrounding section's range, not as a separate section.
  • identify — point marker for dozor:identity events. Zero duration; never highlighted, but clickable to jump to the moment the user was identified.

Sections (init / navigation) chain head-to-tail and cover the full session. The currently-playing section is highlighted in the feed and auto-scrolled into view; clicking any item seeks the replayer to its start timestamp. Markers (idle, identify) take priority over sections in the active-item lookup so playing through an idle gap visibly highlights the gap itself.

Event loading

The session-detail endpoint (GET /api/sessions/{sessionId}) returns metadata + a marker list (timeline anchors). The events themselves load via GET /api/sessions/{sessionId}/events{ batches: [...] } where each batch's data is a base64-encoded gzip blob the browser decompresses with DecompressionStream. The decompressed batches are concatenated, sorted by timestamp, and fed to both the rrweb Replayer and the history builder.

The events query is staleTime: Infinity — recordings are immutable once captured. A polled session-detail update (new markers / endedAt flip) lights the orange Reload button; the user clicks it to re-fetch the (now-larger) event stream.

Control bar

The bar below the viewport carries:

  • Play / Pause — toggle playback.
  • −5s / +5s — seek backward / forward by 5 seconds.
  • Speed — popover with 0.5× / / .
  • Skip idle (toggle) — fast-forward through inactive periods during playback.
  • Compress idle (toggle, on by default) — physically squashes idle gaps in the timeline to 5 s each before the rrweb Replayer sees the events. The seek bar represents only active time; history items still display their real durations on labels (so a 59-minute idle reads as "59m" in the feed even though it occupies a 5 s blip on the seek bar). Toggle off to inspect real-time pacing.
  • Seek bar — scrubbable progress bar across the (possibly compressed) timeline.

There are no keyboard shortcuts.

Side panel

A 320 px column on the right of the viewport with two tabs:

  • History — the chronological feed described above. The currently playing item is highlighted; the list auto-scrolls to keep it in view. Click any item to seek.
  • Console — every console.log/warn/error/info/debug call captured during the session, filtered to entries up to the current playback time. Follows playback when you're scrolled to the bottom; scrolling up to inspect an earlier log pauses the auto-follow until you scroll back down.

Console capture is on by default in the SDK (recordConsole: true) and can be opted out per-deployment.

Sandboxed iframe

The recorded page DOM is replayed inside a sandboxed iframe owned by rrweb's Replayer. The dashboard's CSS, scripts, and cookies stay isolated from the recording — anything inline in the recorded page can't reach into the dashboard's chrome.

This is load-bearing for security. See Resources → Replay player for the sandbox model + how DOM mutations are reconstructed.

Deleting a session

Not exposed in the player — only from the Replays list via the row's kebab menu (OWNER / ADMIN).

See also

On this page