Skip to content

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-player

For a bare bones player without UI, install the rrweb replay package:

bash
npm install @rrweb/replay

CDN 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}/preview

This 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/preview

The 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/replay
javascript
// 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-replay
javascript
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)

Next Steps