Skip to content

Commit c2a3d03

Browse files
omarmosidpedrosousakathayl
authored
[Browser Rendering] Add session recording docs (#29284)
* [Browser Rendering] Add session recording feature docs * [Browser Rendering] Add minimum recording duration limit * [Browser Rendering] Rename Logs to Runs in session recording docs * [Browser Rendering] Replace response table with example JSON response * [Browser Rendering] Add CDP endpoint section to session recording docs * [Browser Rendering] Use MCP config example for CDP recording section * [Browser Rendering] Fix DashButton URL to use validated runs route * [Browser Rendering] Revert Runs to Logs for session recording nav * [Browser Rendering] Remove unreleased DOM inspection and network log mentions * Apply suggestions from PCX review Co-authored-by: Pedro Sousa <680496+pedrosousa@users.noreply.github.com> * Apply suggestion from @pedrosousa Co-authored-by: Pedro Sousa <680496+pedrosousa@users.noreply.github.com> * Apply suggestion from @pedrosousa Co-authored-by: Pedro Sousa <680496+pedrosousa@users.noreply.github.com> * Update session recording terminology - Rename 'Workers Bindings' to 'Browser Sessions' in limits section * Add beta badge to session recording page - Import InlineBadge component - Add beta preset badge above intro paragraph * [Browser Rendering] Add 30-day recording retention limit * Update session recording retention period description Clarified the retention period for recordings in the documentation. --------- Co-authored-by: Pedro Sousa <680496+pedrosousa@users.noreply.github.com> Co-authored-by: Kathy <153706637+kathayl@users.noreply.github.com> Co-authored-by: kathayl <kathyyliao@gmail.com>
1 parent fed97f5 commit c2a3d03

2 files changed

Lines changed: 163 additions & 0 deletions

File tree

src/content/dash-routes/core-manually-defined.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@
44
"name": "Tunnels",
55
"parent": ["Networking"]
66
},
7+
{
8+
"deeplink": "/?to=/:account/workers/browser-rendering/logs",
9+
"name": "Browser Rendering Logs",
10+
"parent": ["Compute & AI"]
11+
},
712
{
813
"deeplink": "/?to=/:account/mesh",
914
"name": "Mesh",
Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
---
2+
pcx_content_type: how-to
3+
title: Session recording
4+
description: Record and replay Browser Rendering sessions to visually debug browser automation scripts.
5+
sidebar:
6+
order: 2
7+
---
8+
9+
import { Details, InlineBadge, Tabs, TabItem, DashButton } from "~/components";
10+
11+
<InlineBadge preset="beta" />
12+
13+
When browser automation fails or behaves unexpectedly, it can be difficult to understand what happened. Session recording captures DOM changes, mouse and keyboard events, and page navigation as structured JSON events — not a video — so it is lightweight and easy to inspect. Recordings are powered by [rrweb](https://github.com/rrweb-io/rrweb) and are opt-in per session.
14+
15+
## Enable session recording
16+
17+
Pass `recording: true` to `puppeteer.launch()` or `playwright.launch()`:
18+
19+
<Tabs>
20+
<TabItem label="Puppeteer">
21+
22+
```ts
23+
import puppeteer from "@cloudflare/puppeteer";
24+
25+
interface Env {
26+
MYBROWSER: Fetcher;
27+
}
28+
29+
export default {
30+
async fetch(request: Request, env: Env): Promise<Response> {
31+
const browser = await puppeteer.launch(env.MYBROWSER, { recording: true });
32+
const page = await browser.newPage();
33+
34+
await page.goto("https://example.com");
35+
// ... your automation steps ...
36+
37+
const sessionId = browser.sessionId();
38+
await browser.close();
39+
40+
return new Response(`Session recorded: ${sessionId}`);
41+
},
42+
};
43+
```
44+
45+
</TabItem>
46+
<TabItem label="Playwright">
47+
48+
```ts
49+
import { launch } from "@cloudflare/playwright";
50+
51+
interface Env {
52+
MYBROWSER: Fetcher;
53+
}
54+
55+
export default {
56+
async fetch(request: Request, env: Env): Promise<Response> {
57+
const browser = await launch(env.MYBROWSER, { recording: true });
58+
const page = await browser.newPage();
59+
60+
await page.goto("https://example.com");
61+
// ... your automation steps ...
62+
63+
const sessionId = browser.sessionId();
64+
await browser.close();
65+
66+
return new Response(`Session recorded: ${sessionId}`);
67+
},
68+
};
69+
```
70+
71+
</TabItem>
72+
</Tabs>
73+
74+
:::note
75+
The recording is finalized when the browser session closes, whether you call `browser.close()` explicitly, the session reaches its idle timeout, or the Worker terminates for any other reason. The recording is not available until after the session ends.
76+
:::
77+
78+
## Enable with CDP endpoint
79+
80+
When connecting to Browser Rendering from any environment using the [CDP endpoint](/browser-rendering/cdp/), add `recording=true` as a query parameter to the WebSocket URL:
81+
82+
```txt
83+
wss://api.cloudflare.com/client/v4/accounts/<ACCOUNT_ID>/browser-rendering/devtools/browser?recording=true&keep_alive=600000
84+
```
85+
86+
For example, to enable session recording in an MCP client, add `recording=true` to the `--wsEndpoint` URL in your client configuration:
87+
88+
```json
89+
{
90+
"mcpServers": {
91+
"browser-rendering": {
92+
"command": "npx",
93+
"args": [
94+
"-y",
95+
"chrome-devtools-mcp@latest",
96+
"--wsEndpoint=wss://api.cloudflare.com/client/v4/accounts/<ACCOUNT_ID>/browser-rendering/devtools/browser?recording=true&keep_alive=600000",
97+
"--wsHeaders={\"Authorization\":\"Bearer <API_TOKEN>\"}"
98+
]
99+
}
100+
}
101+
}
102+
```
103+
104+
For other MCP clients and CDP usage with Puppeteer or Playwright, refer to the [CDP documentation](/browser-rendering/cdp/).
105+
106+
:::note
107+
The recording is only available after the browser session closes. CDP sessions typically use `keep_alive` to stay open between commands. The browser will close automatically when it has been idle for the `keep_alive` duration. You can also close it explicitly with `browser.close()`.
108+
:::
109+
110+
## View recordings
111+
112+
After a session closes, its recording is available in the Cloudflare dashboard under **Browser Rendering** > **Logs**. Select a session to open the recording viewer, where you can scrub through the timeline and replay what happened during the session.
113+
114+
<DashButton url="/?to=/:account/workers/browser-rendering/logs" />
115+
116+
## Retrieve a recording via API
117+
118+
You can also retrieve a recording programmatically using the session ID. Use `browser.sessionId()` to capture the session ID before closing the browser, then pass it to the recordings endpoint.
119+
120+
```bash
121+
curl https://api.cloudflare.com/client/v4/accounts/<ACCOUNT_ID>/browser-rendering/recording/<SESSION_ID> \
122+
-H "Authorization: Bearer <API_TOKEN>"
123+
```
124+
125+
A successful response looks similar to the following:
126+
127+
```json
128+
{
129+
"sessionId": "e26d4660-5b78-4761-b82f-c6b5bad5a925",
130+
"duration": 4380,
131+
"events": {
132+
"target-1": []
133+
}
134+
}
135+
```
136+
137+
## Replay a recording
138+
139+
The `events` values in the API response are standard rrweb event arrays. You can pass them directly to [`rrweb-player`](https://github.com/rrweb-io/rrweb/tree/master/packages/rrweb-player) to self-host a replay UI with a timeline scrubber and playback controls.
140+
141+
## Limits
142+
143+
- Recordings are retained for 30 days after the session ends and automatically deleted.
144+
- Recording is opt-in. It is not enabled by default.
145+
- Session recording is available with Browser Sessions via `launch()` and the [CDP endpoint](/browser-rendering/cdp/). It is not available with Quick Actions.
146+
- The minimum recording duration is 1 second. Sessions shorter than 1 second will not produce a viewable recording.
147+
- The maximum recording duration is 2 hours.
148+
149+
## rrweb limitations
150+
151+
Session recording uses [rrweb](https://github.com/rrweb-io/rrweb), which records DOM state and events rather than pixels. This approach is lightweight but has the following limitations:
152+
153+
- **Canvas elements** — The content of `<canvas>` elements is not captured. The element itself appears in the recording as a blank placeholder.
154+
- **Cross-origin iframes** — Content inside cross-origin `<iframe>` elements is not recorded. Same-origin iframes are recorded normally.
155+
- **Video and audio** — The DOM structure of `<video>` and `<audio>` elements is captured, but media playback state and content are not.
156+
- **WebGL** — WebGL rendering is not captured.
157+
- **Input fields** — The content of all input fields is masked by default and will not be visible in the replay.
158+
- **Large or complex pages** — Pages with frequent DOM mutations (for example, pages with real-time data feeds or heavy animations) can generate a high volume of events, which increases the size of the recording.

0 commit comments

Comments
 (0)