Appearance
Replaying Recorded Recordings with rrweb and rrweb cloud
This guide shows you how to fetch and replay recorded recordings from rrweb cloud using rrweb's replay functionality.
You can view and manage your recordings in the rrweb Cloud dashboard.
Installing the rrweb player
For a pre-built player UI, install rrweb-player: (recommended)
bash
npm install rrweb-playerFor a bare bones player without UI, install the rrweb replay package:
bash
npm install @rrweb/replayCDN Installation
Include rrweb-player via CDN for quick setup:
html
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/rrweb-player@latest/dist/style.css"
/>
<script src="https://cdn.jsdelivr.net/npm/rrweb-player@latest/dist/index.js"></script>Basic Replay Setup
Fetch Events from rrweb cloud
First, retrieve the recorded events for a recording. You can find your recording IDs in the rrweb Cloud dashboard.
javascript
async function fetchRecordingEvents(recordingId) {
try {
const response = await fetch(
`https://api.rrwebcloud.com/recordings/${recordingId}/events`,
);
if (!response.ok) {
throw new Error(`Failed to fetch events: ${response.status}`);
}
const events = await response.json();
return events;
} catch (error) {
console.error("Error fetching recording events:", error);
return null;
}
}Initialize and Play Replayer
Once you have the events, initialize the player and play the recording:
javascript
// Fetch events
const events = await fetchRecordingEvents(recordingId);
if (events && events.length > 0) {
// Initialize rrweb-player
const player = new rrwebPlayer({
target: document.getElementById("player-container"), // Container element
props: {
events: events,
// Player options
width: 1024, // Player width (px)
height: 576, // Player height (px)
maxScale: 1, // Maximum scale (1 = 100%, 0 = unlimited)
autoPlay: true, // Auto-start playback
speedOption: [1, 2, 4, 8], // Available speed options
showController: true, // Show player controls
tags: {}, // Custom event tag styles
// All other options are passed to the underlying replayer
skipInactive: true,
mouseTail: true,
blockClass: "rr-block",
},
});
}Quick Preview Endpoint
For a quick preview without writing any code, you can use the built-in preview endpoint:
https://api.rrwebcloud.com/recordings/{recordingId}/previewThis endpoint serves an HTML page with the rrweb player pre-configured, automatically fetching and displaying the recording events. Simply replace {recordingId} with your recording ID and open the URL in a browser.
Example:
https://api.rrwebcloud.com/recordings/550e8400-e29b-41d4-a716-446655440000/previewThe preview page includes:
- Full playback controls (play, pause, speed adjustment, timeline scrubbing)
- Mouse trail visualization
- Automatic event fetching from the recording events endpoint
- Skip inactive periods
- Responsive layout that adapts to your screen size
This is perfect for quick debugging, sharing recordings with team members, or testing recording playback without integrating the player into your own application.
Alternative: Using the rrweb replay package
If you prefer to build your own player UI, you can use the rrweb replay package:
bash
npm install @rrweb/replayjavascript
// Fetch events for a specific recording
const recordingId = "your-recording-id";
const events = await fetchRecordingEvents(recordingId);
if (events && events.length > 0) {
// Initialize the replayer
const replayer = new rrweb.Replayer(events, {
// Configuration options
speed: 1, // Playback speed (1 = normal)
root: document.body, // Root element for replay
loadTimeout: 0, // Timeout for loading external resources
skipInactive: false, // Skip inactive periods
inactivePeriodThreshold: 10000, // Threshold for inactive periods (ms)
showWarning: true, // Show warning messages
showDebug: false, // Show debug messages
blockClass: "rr-block", // Class for blocked elements
liveMode: false, // Enable live mode
insertStyleRules: [], // Custom CSS rules to inject
triggerFocus: true, // Trigger focus events
UNSAFE_replayCanvas: false, // Replay canvas elements (unsafe)
pauseAnimation: true, // Pause CSS animations when paused
mouseTail: true, // Show mouse cursor trail
});
// Start playback
replayer.play();
}Advanced Replay Features
Live Mode Replay (not supported by rrweb cloud yet)
For real-time or near real-time replay:
javascript
// Initialize in live mode
const replayer = new rrweb.Replayer(events, {
liveMode: true,
speed: 1,
});
// For existing events, play with offset
if (events.length > 0) {
const offset = Date.now() - events[0].timestamp;
replayer.play(offset);
}
// For true live streaming, start with empty events array
const liveReplayer = new rrweb.Replayer([], {
liveMode: true,
});
liveReplayer.startLive();
// Then add events as they arrive
function addLiveEvent(event) {
liveReplayer.addEvent(event);
}Control Playback
Control playback programmatically:
javascript
// Play from the beginning
replayer.play();
// Play from a specific time (in milliseconds)
replayer.play(3000); // Start at 3 seconds
// Pause playback
replayer.pause();
// Pause at a specific time
replayer.pause(5000); // Pause at 5 seconds
// Resume playback
replayer.play();
// Jump to a specific time
replayer.goto(10000); // Jump to 10 seconds
// Get current time
const currentTime = replayer.getCurrentTime();
// Get total duration
const totalDuration = replayer.getMetaData().totalTime;
// Destroy the replayer
replayer.destroy();Custom Event Handling
Handle custom events during replay:
javascript
const replayer = new rrweb.Replayer(events, {
// Custom event handlers
hooks: {
// Called before replaying an event
beforeReplay: (event) => {
console.log("Replaying event:", event);
},
// Called after replaying an event
afterReplay: (event) => {
if (event.type === 5 && event.data.tag === "user-action") {
// Handle custom user action events
console.log("User action:", event.data.payload);
}
},
},
});Replayer Configuration Options
Privacy and Security
javascript
const replayer = new rrweb.Replayer(events, {
// Block sensitive elements
blockClass: "rr-block",
blockSelector: ".sensitive, .private-data",
// Mask text in sensitive elements
maskTextClass: "rr-mask",
maskTextSelector: ".email, .phone, .ssn",
// Don't trigger focus (prevents stealing focus)
triggerFocus: false,
// Don't replay canvas (safer)
UNSAFE_replayCanvas: false,
});Custom Styling
javascript
const replayer = new rrweb.Replayer(events, {
// Inject custom CSS
insertStyleRules: [
".replayer-wrapper { background: #f0f0f0; }",
".replayer-mouse { cursor: none; }",
".rr-block { background: #ccc; }",
],
});Using Plugins
Install and Use Replay Plugins
bash
npm install @rrweb/rrweb-plugin-sequential-id-replayjavascript
import rrweb from "rrweb";
import { sequentialIdReplayPlugin } from "@rrweb/rrweb-plugin-sequential-id-replay";
// Initialize with plugin
const replayer = new rrweb.Replayer(events, {
plugins: [
sequentialIdReplayPlugin({
key: "sequenceId",
}),
],
});Custom Replay Plugin
Create a custom plugin to handle specific events:
javascript
// Define a custom replay plugin
const customReplayPlugin = {
handler(event, isSync, context) {
if (event.type === rrweb.EventType.Plugin) {
// Handle custom plugin events
if (event.data.plugin === "my-custom-plugin") {
console.log("Custom plugin data:", event.data.payload);
// Access replayer context
const { replayer, mirror } = context;
// Perform custom actions
const element = mirror.getNode(event.data.payload.nodeId);
if (element) {
element.classList.add("highlighted");
}
}
}
},
};
// Use the plugin
const replayer = new rrweb.Replayer(events, {
plugins: [customReplayPlugin],
});Handle Large Recordings
Coming later...
Filtering recordings by metadata
When listing recordings via GET /recordings, you can filter by metadata using the meta[key]=value deep object syntax. Always wrap both the key and value in encodeURIComponent before building the query string so filters containing spaces or punctuation still match the stored metadata.
ts
const params = new URLSearchParams();
params.set(
`meta[${encodeURIComponent("user id")}]`,
encodeURIComponent(currentUser.id),
);
const response = await fetch(
`https://api.rrwebcloud.com/recordings?${params.toString()}`,
);Troubleshooting
- Events not loading: Check recording ID and ensure events were ingested successfully
- Replay not starting: Verify events array is not empty and contains valid rrweb events
- Styling issues: Ensure rrweb CSS is loaded and no conflicting styles
- Canvas not replaying: Enable
UNSAFE_replayCanvas: true(note: this removes sandbox security)