Session Replay
Session Replay captures browser sessions as interactive replays that you can view in your Browserless dashboard. Unlike screen recording (which produces video files), Session Replay uses RRWeb technology to record DOM mutations, mouse movements, clicks, scrolling, keyboard input, console logs, and network requests. This creates lightweight, high-fidelity recordings that can be played back at any speed. This feature is not to be confused with the Screencast API, which captures WebM video files that are returned directly to your code.
This feature is particularly useful for debugging complex user workflows and interactions, creating visual documentation of browser automation processes, and troubleshooting issues with recorded evidence.

Prerequisites
Before using Session Replay, make sure you have a Browserless account with Session Replay access (available on paid plans), a valid API key, and Node.js installed on your system (for code examples). Install the required npm packages:
npm install puppeteer-core
What Gets Recorded
Session Replay captures the following data:
DOM Events: All visual changes to the page including element mutations, style changes, and layout shifts are recorded using RRWeb's snapshot technology.
User Interactions: Mouse movements, clicks, scrolling, and keyboard input are captured with precise timing for accurate playback.
Console Logs: All console output (log, warn, error, info) is recorded with timestamps, making it easy to correlate visual events with application state.
Network Requests: HTTP requests and responses are logged, helping you understand data flow during the session.
Recording a Session
When you connect with replay=true, recording begins immediately. There is no need to call a start command. The recording continues until you explicitly stop it or close the browser connection.
Connect to Browserless with Replay Enabled
Connect to Browserless and enable session replay recording by adding the
replay=truequery parameter to your connection URL. Recording starts automatically upon connection.- Puppeteer
- Playwright
import puppeteer from 'puppeteer-core';
const browser = await puppeteer.connect({
browserWSEndpoint: `wss://production-sfo.browserless.io?token=YOUR_API_TOKEN_HERE&timeout=300000&headless=false&replay=true`,
});import { chromium } from 'playwright-core';
const browser = await chromium.connectOverCDP(
'wss://production-sfo.browserless.io?token=YOUR_API_TOKEN_HERE&timeout=300000&headless=false&replay=true'
);Perform Actions to Record
Create a page, navigate to your target website, and perform the actions you want to record. The recording will capture all interactions on this page.
- Puppeteer
- Playwright
const page = await browser.newPage();
await page.goto("https://www.example.com", { waitUntil: "networkidle0" });
const sleep = (ms) => new Promise((res) => setTimeout(res, ms));
// Example: Random mouse movements for demonstration
const randomMouseMovements = async (page, moves = 20) => {
const viewport = page.viewport() || { width: 1280, height: 720 };
for (let i = 0; i < moves; i++) {
const x = Math.floor(Math.random() * viewport.width);
const y = Math.floor(Math.random() * viewport.height);
await page.mouse.move(x, y, {
steps: 5 + Math.floor(Math.random() * 10),
});
await sleep(100 + Math.random() * 300);
}
};
await randomMouseMovements(page, 2);
await sleep(6000);const [context] = await browser.contexts();
const page = await context.newPage();
await page.goto("https://www.example.com", { waitUntil: "networkidle" });
const sleep = (ms) => new Promise((res) => setTimeout(res, ms));
// Example: Random mouse movements for demonstration
const randomMouseMovements = async (page, moves = 20) => {
const viewport = page.viewportSize() || { width: 1280, height: 720 };
for (let i = 0; i < moves; i++) {
const x = Math.floor(Math.random() * viewport.width);
const y = Math.floor(Math.random() * viewport.height);
await page.mouse.move(x, y);
await sleep(100 + Math.random() * 300);
}
};
await randomMouseMovements(page, 2);
await sleep(6000);Stop Recording and Clean Up
Create a CDP session, stop the session recording, and close the browser connection. When you call
Browserless.stopSessionRecording, the recorded data is automatically uploaded to your Browserless account for viewing in the dashboard.- Puppeteer
- Playwright
const cdp = await page.createCDPSession();
// Stop the recording - data is automatically uploaded
await cdp.send("Browserless.stopSessionRecording");
await browser.close();const cdpSession = await context.newCDPSession(page);
// Stop the recording - data is automatically uploaded
await cdpSession.send("Browserless.stopSessionRecording");
await browser.close();Alternative: Close Without Explicit StopIf you close the browser without calling
Browserless.stopSessionRecording, the recording will still be saved automatically. However, explicitly stopping the recording ensures all data is properly flushed before disconnection.
Viewing Replays
After your session ends, the replay is automatically uploaded and available in your Browserless dashboard. Navigate to the Session Replay section to find your recorded sessions. Each replay includes a timeline showing all captured events, console logs, and network activity. You can play back the session at different speeds and jump to specific moments in the recording.
For BrowserQL-specific Session Replay documentation, see Session Replay with BQL.
Navigation Handling
Session Replay automatically handles page navigations within your session. When the browser navigates to a new page, the recording system reinjects the RRWeb recorder and continues capturing events. All data from multiple page navigations is aggregated into a single replay, so you can see the complete user journey across different pages.
Limitations
Session Replay has some limitations to be aware of. Cross-origin iframes may not be fully captured due to browser security restrictions. Very long sessions with high DOM activity may result in large replay files. Some dynamic content loaded via WebGL or canvas may not be perfectly reproduced in playback.
Next Steps
Ready to explore more recording capabilities? Consider these alternatives for different use cases: