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.
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:
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:
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:
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:
- replay a privacy-safe fixture captured by the deployed recorder;
- verify a FullSnapshot precedes mutations for every page view;
- verify replay-side plugins match recorded plugin events; and
- 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:
- check the HTTP status and confirm the response is a non-empty JSON array;
- compare event count and timestamps with the original ingest logs;
- locate the first FullSnapshot and the first warning from
showWarningor temporaryshowDebugoutput; and - 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
| Symptom | Check | Action |
|---|---|---|
401 fetching events | Viewer used no credential or the wrong credential | Retrieve or sign access on the trusted server; a public write key cannot read recordings |
403 on a signed URL | Expiry or signature no longer validates | Request a fresh scoped URL after re-authorizing the viewer |
Empty array or 404 | Recording ID, tenant, and ingestion result | Verify the recording in the dashboard before initializing a player |
| Replay starts blank | Missing or late FullSnapshot | Inspect event order and recorder checkout behavior |
| DOM diverges | Missing assets, iframe limits, unsupported capture, or version mismatch | Reproduce with a privacy-safe fixture and compare recorder/replayer configuration |
| Plugin events do nothing | Replay plugin absent or incompatible | Install the matching replay plugin and align versions |
| Browser becomes slow | Large event array or an old player retained in memory | Show loading state, destroy old players, and reduce optional visual effects |