Skip to content

Advanced replay and troubleshooting

Use this guide after your application can securely retrieve a complete rrweb event array. It covers the replay layer; ingestion and viewer authorization stay separate concerns.

Control playback programmatically

rrwebPlayer exposes UI methods such as play(), pause(), goto(), setSpeed(), and toggleSkipInactive() for building custom controls, plus getReplayer() for direct access to the underlying Replayer.

javascript
player.play();
player.pause();
player.goto(30_000, false);
player.setSpeed(2);
player.toggleSkipInactive();

player.addEventListener('ui-update-current-time', ({ payload }) => {
  updateClock(payload);
});

Use player.getReplayer() when you need the underlying Replayer events or methods, and call player.$destroy() when the view unmounts.

Continue in the rrweb Library customize the replayer recipe for controller events, sizing, and custom UI patterns, or the rrweb-player package reference for the complete public API.

Configure the Replayer

Options inside props that are not player-only options are passed to the underlying Replayer. Start with a small, explicit configuration:

javascript
const player = new rrwebPlayer({
  target: document.querySelector('#replay'),
  props: {
    events,
    autoPlay: false,
    showController: true,
    skipInactive: true,
    mouseTail: false,
    triggerFocus: false,
    showWarning: true,
    showDebug: false,
  },
});

Recording-time privacy cannot be recovered during replay. Blocking, masking, canvas capture, stylesheet inlining, and asset capture must be configured while recording; see Recording and privacy settings.

Continue in the rrweb Library Replayer options before enabling options such as canvas replay or injected styles.

For UI-less playback, instantiate Replayer directly from @rrweb/replay instead. Continue in the rrweb Library @rrweb/replay package reference for installation, styles, and the direct API.

Handle custom events during replay

Custom events describe application-specific moments without defining a replay plugin. Record a small, versioned payload with the Browser Client's addCustomEvent(tag, payload), then listen for the event through the player's underlying Replayer:

javascript
const replayer = player.getReplayer();

replayer.on('custom-event', (event) => {
  if (event.tag === 'checkout-completed') {
    showOrderMarker(event.payload);
  }
});

To show the same tag on the rrweb-player timeline, include a tags color map when you initialize the player:

javascript
const player = new rrwebPlayer({
  target: replayTarget,
  props: {
    events,
    tags: {
      'checkout-completed': '#2563eb',
    },
  },
});

Do not put secrets or raw user input in a custom-event payload.

Continue in the rrweb Library custom event recipe for recording, listening, and timeline styling semantics.

Plugins

Replay plugins must match the data emitted by their recording-side partner. For example, sequential-ID, console, network, and canvas integrations each have separate record and replay packages. Pin compatible package versions and test the exact recorder/replayer pair before rollout.

Continue in the rrweb Library plugin guide for the plugin contract and package catalog.

Handle large recordings

Get recording events returns a top-level JSON array for the complete recording. It does not currently accept limit or offset. Show a loading state, abort stale requests when the viewer changes recordings, and destroy the previous player before allocating a new one.

For a long user journey made from several recordings, Cloud can compose the recordings by metadata. Do not concatenate unrelated event arrays without preserving their FullSnapshot boundaries and timestamp order.

If your own trusted proxy or storage layer delivers an already-retrieved stream in chunks, Replayer.addEvent() can append ordered events. Continue in the rrweb Library pagination recipe for that replay API. The recipe does not add pagination parameters to the Cloud event endpoint.

Check rrweb version compatibility

Cloud stores rrweb events and returns them for rrweb-player or Replayer, so rrweb version and plugin compatibility still apply; replay a privacy-safe fixture and verify FullSnapshot ordering, plugin alignment, and browser rendering before upgrading.

Before upgrading:

  1. replay a privacy-safe fixture captured by the deployed recorder;
  2. verify a FullSnapshot precedes mutations for every page view;
  3. verify replay-side plugins match recorded plugin events; and
  4. check stylesheets, fonts, images, iframes, and canvas behavior in the target browser.

Keep recorder and replay dependencies on known-compatible versions. A newer player cannot reconstruct DOM or asset data that was never captured.

Recover from missing or corrupt events

Treat the event stream as ordered data. Each event needs a valid type, timestamp, and data value, and incremental mutations need the appropriate earlier FullSnapshot. Silently filtering corrupt events can leave later mutations pointing at nodes that were never created.

When replay fails:

  1. check the HTTP status and confirm the response is a non-empty JSON array;
  2. compare event count and timestamps with the original ingest logs;
  3. locate the first FullSnapshot and the first warning from showWarning or temporary showDebug output; and
  4. reproduce with the same rrweb and plugin versions used by the application.

Use diagnostic logging only with privacy-safe recordings; event payloads can contain captured page data.

Does rrweb Cloud support live replay?

No. Live ingest replay is not supported by rrweb Cloud: the Cloud WebSocket endpoint streams events into storage but does not stream them back to a viewer, so wait until events are retrievable before starting a Cloud replay.

For a separately operated end-to-end live transport, continue outside Cloud. Continue in the rrweb Library live mode recipe. Its liveMode, startLive(), and addEvent() APIs do not turn Cloud ingestion into a live playback feed.

Troubleshooting

SymptomCheckAction
401 fetching eventsViewer used no credential or the wrong credentialRetrieve or sign access on the trusted server; a public write key cannot read recordings
403 on a signed URLExpiry or signature no longer validatesRequest a fresh scoped URL after re-authorizing the viewer
Empty array or 404Recording ID, tenant, and ingestion resultVerify the recording in the dashboard before initializing a player
Replay starts blankMissing or late FullSnapshotInspect event order and recorder checkout behavior
DOM divergesMissing assets, iframe limits, unsupported capture, or version mismatchReproduce with a privacy-safe fixture and compare recorder/replayer configuration
Plugin events do nothingReplay plugin absent or incompatibleInstall the matching replay plugin and align versions
Browser becomes slowLarge event array or an old player retained in memoryShow loading state, destroy old players, and reduce optional visual effects