Skip to content

feat: add replay command for interactive DOM session recording#1074

Open
LyricalString wants to merge 4 commits intovercel-labs:mainfrom
LyricalString:feat/replay-command
Open

feat: add replay command for interactive DOM session recording#1074
LyricalString wants to merge 4 commits intovercel-labs:mainfrom
LyricalString:feat/replay-command

Conversation

@LyricalString
Copy link
Copy Markdown

@LyricalString LyricalString commented Mar 29, 2026

Summary

Adds a replay command that records browser sessions as interactive HTML replays using rrweb. This complements the existing record command (video via ffmpeg) with a lightweight, inspectable alternative.

Commands

Command Description
replay start Inject rrweb into the page, auto re-inject on navigation
replay stop [path] Extract events + CSS vars, generate self-contained replay HTML
replay status Show event count and recording state

Why

Video recording (record) requires ffmpeg and produces passive video files. DOM replay captures the actual DOM mutations, producing:

  • Interactive replays with play/pause, timeline scrubbing, speed controls (1x-8x)
  • Self-contained HTML files that open in any browser, no server needed
  • 10x lighter files compared to WebM videos
  • No ffmpeg dependency

How it works

  1. replay start fetches rrweb from CDN, injects it via Runtime.evaluate, and registers it for auto re-injection via Page.addScriptToEvaluateOnNewDocument
  2. During the session, rrweb captures DOM snapshots + incremental mutations with inlineImages, collectFonts, and inlineStylesheet enabled
  3. replay stop extracts events via Runtime.evaluate, resolves CSS custom properties for accurate replay of var(--x) references, and generates a self-contained HTML file with rrweb-player

Example

agent-browser open https://app.example.com
agent-browser replay start
agent-browser click @e3
agent-browser fill @e5 "hello"
agent-browser replay stop ./my-session
open ./my-session.html

Files changed

  • cli/src/native/replay.rs -- New module: ReplayState, rrweb injection, CSS extraction, HTML generation
  • cli/src/native/mod.rs -- Module registration
  • cli/src/native/actions.rs -- DaemonState field, dispatch arms, handler functions
  • cli/src/commands.rs -- CLI parsing for replay start|stop|status
  • cli/src/output.rs -- Help text for the new command
  • .changeset/add-replay-command.md -- Minor version bump

Tests

  • 4 new unit tests for ReplayState, inject JS, and HTML generation
  • All 546 existing tests pass

Demo

Here's a real-world recording of a login flow + chat interaction, captured with replay start / replay stop and exported to video from the generated HTML player:

session-replay.4.webm

The replay HTML includes:

  • Gap compression (no idle zones in the timeline)
  • CSS custom property extraction (accurate colors/theming)
  • Interactive player with 1x-8x speed controls
  • One-click video export via Screen Capture API

…rrweb

Adds a new `replay` command alongside the existing `record` (video) command.
While `record` produces WebM/MP4 videos via ffmpeg, `replay` captures DOM
mutations via rrweb and generates self-contained HTML files with an
interactive player (play/pause, timeline, 1x-8x speed).

Commands:
- `replay start` -- inject rrweb into the page, auto re-inject on navigation
- `replay stop [path]` -- extract events + CSS vars, generate replay HTML
- `replay status` -- show event count

Key features:
- Uses Page.addScriptToEvaluateOnNewDocument for automatic re-injection
  across navigations (no manual re-inject needed)
- Extracts resolved CSS custom properties so var(--x) works in replay
- inlineImages + collectFonts + inlineStylesheet for high-fidelity replay
- No ffmpeg dependency required
- Self-contained HTML output -- open in any browser

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
@vercel
Copy link
Copy Markdown
Contributor

vercel bot commented Mar 29, 2026

@LyricalString is attempting to deploy a commit to the Vercel Labs Team on Vercel.

A member of the Team first needs to authorize it.

LyricalString and others added 2 commits March 29, 2026 18:54
Prevents broken HTML when recorded pages contain script closing tags
in their DOM content. The </script> sequence inside the embedded JSON
would prematurely close the <script> block.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
- Enable skipInactive by default so idle periods are compressed
- Add "Export as video" button that uses MediaRecorder + canvas capture
  to download the replay as a WebM file
- Start with autoPlay: false so user controls when playback begins

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Three fixes based on real-world testing:

1. Gap compression: compress idle periods (navigation redirects, network
   waits) in event timestamps before generating the HTML. This prevents
   rrweb-player from showing grey inactive zones in the timeline that
   block UI controls (a known rrweb-player bug).

2. Video export: replace broken html2canvas approach with Screen Capture
   API (getDisplayMedia). Auto-stops when replay finishes and downloads
   the WebM file. The iframe sandbox makes canvas-based capture impossible.

3. Player size: scale from 1920x1080 to 1280x720 so the full replay
   fits on screen with title, controls, and export button visible.

Also removes skipInactive/inactiveThreshold props since gap compression
makes them unnecessary.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant