Record a Browser Session
Capture a video recording of a browser session — navigations, clicks, and interactions — as a .webm file using the Browserless recording API.
- A Browserless API token from your account dashboard
Steps
Recording uses CDP commands Browserless.startRecording and Browserless.stopRecording. Three parameters are required in the WebSocket URL: headless=false (the recording extension captures a visible window), stealth (recording is not available on the standard /chrome route), and record=true. The video dimensions match the viewport when recording starts — set it before calling startRecording.
- Puppeteer
- Playwright
1. Install dependencies
npm install puppeteer-core
2. Connect, record, and save
import fs from 'fs';
import puppeteer from 'puppeteer-core';
const browser = await puppeteer.connect({
browserWSEndpoint:
'wss://production-sfo.browserless.io?token=YOUR_API_TOKEN_HERE&headless=false&stealth&record=true',
});
try {
const page = await browser.newPage();
// Set viewport before starting — dimensions are fixed for the entire recording.
await page.setViewport({ width: 1280, height: 720 });
const cdp = await page.createCDPSession();
await cdp.send('Browserless.startRecording');
await page.goto('https://example.com', { waitUntil: 'networkidle2' });
await new Promise(r => setTimeout(r, 2000));
await page.goto('https://example.com/about', { waitUntil: 'networkidle2' });
await new Promise(r => setTimeout(r, 2000));
// base64 encoding is required — CDP can't transfer raw binary over its text protocol.
const { value } = await cdp.send('Browserless.stopRecording', { encoding: 'base64' });
fs.writeFileSync('recording.webm', Buffer.from(value, 'base64'));
console.log('Recording saved to recording.webm');
} finally {
// Always close to release the session even on error.
await browser.close();
}
3. Check the output
Run with node record.mjs. The file recording.webm contains the full browser session video.
All Playwright languages must reuse the existing context and page from connectOverCDP — creating new ones starts a fresh session that isn't wired to the recording.
- JavaScript
- Python
- Java
- C#
1. Install dependencies
npm install playwright-core
2. Connect, record, and save
import fs from 'fs';
import { chromium } from 'playwright-core';
const browser = await chromium.connectOverCDP(
'wss://production-sfo.browserless.io?token=YOUR_API_TOKEN_HERE&headless=false&stealth&record=true'
);
try {
const context = browser.contexts()[0];
const page = context.pages()[0];
// Set viewport before starting — dimensions are fixed for the entire recording.
await page.setViewportSize({ width: 1280, height: 720 });
const cdp = await page.context().newCDPSession(page);
await cdp.send('Browserless.startRecording');
await page.goto('https://example.com', { waitUntil: 'networkidle' });
await new Promise(r => setTimeout(r, 2000));
await page.goto('https://example.com/about', { waitUntil: 'networkidle' });
await new Promise(r => setTimeout(r, 2000));
// base64 encoding is required — CDP can't transfer raw binary over its text protocol.
const { value } = await cdp.send('Browserless.stopRecording', { encoding: 'base64' });
fs.writeFileSync('recording.webm', Buffer.from(value, 'base64'));
console.log('Recording saved to recording.webm');
} finally {
// Always close to release the session even on error.
await browser.close();
}
3. Check the output
Run with node record.mjs. The file recording.webm contains the full browser session video.
1. Install dependencies
pip install playwright
playwright install chromium
2. Connect, record, and save
import base64
import time
from playwright.sync_api import sync_playwright
TOKEN = 'YOUR_API_TOKEN_HERE'
WS_ENDPOINT = f'wss://production-sfo.browserless.io?token={TOKEN}&headless=false&stealth&record=true'
with sync_playwright() as playwright:
browser = playwright.chromium.connect_over_cdp(WS_ENDPOINT)
try:
# Reuse the existing context and page — new ones won't be wired to the recording.
context = browser.contexts[0]
page = context.pages[0]
# Set viewport before starting — dimensions are fixed for the entire recording.
page.set_viewport_size({'width': 1280, 'height': 720})
cdp_session = context.new_cdp_session(page)
cdp_session.send('Browserless.startRecording')
page.goto('https://example.com')
time.sleep(5)
page.goto('https://example.com/about')
time.sleep(5)
# base64 encoding is required — CDP can't transfer raw binary over its text protocol.
response = cdp_session.send('Browserless.stopRecording', {'encoding': 'base64'})
with open('recording.webm', 'wb') as f:
f.write(base64.b64decode(response['value']))
print('Recording saved to recording.webm')
finally:
# Always close to release the session even on error.
browser.close()
3. Check the output
Run with python record.py. The file recording.webm contains the full browser session video.
1. Install dependencies
Add the Playwright dependency to your pom.xml:
<dependency>
<groupId>com.microsoft.playwright</groupId>
<artifactId>playwright</artifactId>
<version>1.44.0</version>
</dependency>
2. Connect, record, and save
import com.microsoft.playwright.*;
import java.nio.file.*;
import java.util.Base64;
import java.util.Map;
public class ScreenRecording {
public static void main(String[] args) throws Exception {
String TOKEN = "YOUR_API_TOKEN_HERE";
String WS_ENDPOINT = String.format(
"wss://production-sfo.browserless.io?token=%s&headless=false&stealth&record=true",
TOKEN
);
try (Playwright playwright = Playwright.create()) {
Browser browser = playwright.chromium().connectOverCDP(WS_ENDPOINT);
try {
// Reuse the existing context and page — new ones won't be wired to the recording.
BrowserContext context = browser.contexts().get(0);
Page page = context.pages().get(0);
// Set viewport before starting — dimensions are fixed for the entire recording.
page.setViewportSize(1280, 720);
CDPSession cdpSession = context.newCDPSession(page);
cdpSession.send("Browserless.startRecording", null);
page.navigate("https://example.com");
Thread.sleep(5000);
page.navigate("https://example.com/about");
Thread.sleep(5000);
// base64 encoding is required — CDP can't transfer raw binary over its text protocol.
var response = cdpSession.send(
"Browserless.stopRecording",
Map.of("encoding", "base64")
);
byte[] data = Base64.getDecoder().decode(response.get("value").getAsString());
Files.write(Paths.get("recording.webm"), data);
System.out.println("Recording saved to recording.webm");
} finally {
// Always close to release the session even on error.
browser.close();
}
}
}
}
3. Check the output
Compile and run with mvn exec:java. The file recording.webm contains the full browser session video.
1. Install dependencies
dotnet add package Microsoft.Playwright
playwright install chromium
2. Connect, record, and save
using Microsoft.Playwright;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text.Json;
using System.Threading.Tasks;
class ScreenRecording
{
public static async Task Main()
{
const string TOKEN = "YOUR_API_TOKEN_HERE";
string WS_ENDPOINT = $"wss://production-sfo.browserless.io?token={TOKEN}&headless=false&stealth&record=true";
using var playwright = await Playwright.CreateAsync();
var browser = await playwright.Chromium.ConnectOverCDPAsync(WS_ENDPOINT);
try
{
// Reuse the existing context and page — new ones won't be wired to the recording.
var context = browser.Contexts[0];
var page = context.Pages[0];
// Set viewport before starting — dimensions are fixed for the entire recording.
await page.SetViewportSizeAsync(1280, 720);
var cdpSession = await context.NewCDPSessionAsync(page);
await cdpSession.SendAsync("Browserless.startRecording");
await page.GotoAsync("https://example.com");
await Task.Delay(5000);
await page.GotoAsync("https://example.com/about");
await Task.Delay(5000);
// base64 encoding is required — CDP can't transfer raw binary over its text protocol.
var response = await cdpSession.SendAsync(
"Browserless.stopRecording",
new Dictionary<string, object> { ["encoding"] = "base64" }
);
var encoded = response?.GetProperty("value").GetString()
?? throw new InvalidOperationException("stopRecording returned no value.");
byte[] data = Convert.FromBase64String(encoded);
await File.WriteAllBytesAsync("recording.webm", data);
Console.WriteLine("Recording saved to recording.webm");
}
finally
{
// Always close to release the session even on error.
await browser.CloseAsync();
}
}
}
3. Check the output
Run with dotnet run. The file recording.webm contains the full browser session video.
Notes
- The video is encoded as WebM (VP8). Convert to MP4 with
ffmpeg -i recording.webm recording.mp4if needed. - Do not change the viewport size after calling
startRecording— the dimensions are fixed when recording begins. - For DOM-based session replay (not video), use
replay=truein the connection URL instead — recordings are uploaded to the Browserless dashboard automatically.
Next steps
- Take a Screenshot — capture a static image instead of a video
- Run Concurrent Browser Sessions — record multiple sessions in parallel