For AI agents: a documentation index is available at /llms.txt
Skip to main content

CDP Extensions

Browserless-specific Chrome DevTools Protocol methods you call via cdp.send() on a page's CDP session in Puppeteer or Playwright. They extend standard CDP with live URLs, captcha solving, session reconnect, recording, file transfer, and page identification. Several also emit CDP events (listen with cdp.on()).

Prerequisites
  • A Browserless API token from your account dashboard
  • An existing WebSocket connection to Browserless via Puppeteer or Playwright
  • Familiarity with creating a CDP session (page.createCDPSession() in Puppeteer, page.context().newCDPSession(page) in Playwright)

Availability depends on how the browser was launched: live URLs, captcha solving, reconnect, and recording are each gated on their own feature flag / query param and return an error in the result when unavailable.

Usage

const browser = await puppeteer.connect({ browserWSEndpoint: '...' });
const [page] = await browser.pages();
const cdp = await page.createCDPSession();

// Command: get a live URL for debugging
const { liveURL } = await cdp.send('Browserless.liveURL', { quality: 70 });

// Event: react to an auto-detected captcha
cdp.on('Browserless.captchaFound', ({ type, status }) => {});

Commands

Browserless.liveURL

Mints a temporary URL that opens a live, interactive view of the current page in any browser. For debugging, QA, or human-in-the-loop workflows. Requires live URLs to be enabled for the session.

Call via CDP: cdp.send('Browserless.liveURL', { quality: 70 })

Returns: { error, liveURLId, liveURL } (error is null on success).

ParameterTypeDefaultDescription
qualitynumber70Stream image quality (1-100).
typestring"jpeg"Stream frame image format.
timeoutnumber30000How long (ms) the minted URL stays valid.
interactablebooleantrueAllow the viewer to click/type into the page.
resizablebooleantrueAllow the viewer to resize the viewport.
showBrowserInterfacebooleanfalseShow browser chrome around the page.
compressedbooleantrueCompress the stream.
emulateComponentsbooleantrueEmulate UI components in the stream.

Browserless.closeLiveURL

Closes a live URL opened with liveURL, freeing server resources. Called automatically when the session ends.

Call via CDP: cdp.send('Browserless.closeLiveURL', { liveURLId })

Returns: { error, liveURLId }.

ParameterTypeDescription
liveURLIdstringRequired. The liveURLId returned by liveURL.

Browserless.solveCaptcha

Detects a CAPTCHA on the current page and attempts to solve it via a third-party solving service (reCAPTCHA v2/v3, hCaptcha, Cloudflare Turnstile, and more). Requires captcha solving to be available for the session.

Call via CDP: cdp.send('Browserless.solveCaptcha')

Returns: { ok, captchaFound, solveAttempted, solved, token?, message?, error? }.

Browserless.reconnect

Returns a WebSocket URL for reconnecting to this browser session after disconnecting. The browser stays alive server-side for timeout ms. Requires reconnect to be enabled; timeout is capped by the plan's maximum reconnect time.

Call via CDP: cdp.send('Browserless.reconnect', { timeout: 60000 })

Returns: { auth, error, browserWSEndpoint } (browserWSEndpoint is null on error).

ParameterTypeDescription
timeoutnumberHow long (ms) to keep the browser alive after disconnect. Defaults to the session timeout.
authstringOptional auth token echoed back and required on the reconnect handshake.

Browserless.pageId

Returns Browserless's stable identifier for the current page target, useful for routing and correlating a page across reconnects.

Call via CDP: cdp.send('Browserless.pageId')

Returns: { pageId: '...' }.

Browserless.startRecording

Starts server-side video recording of the page. Requires connecting with ?record=true. Refused after a credential has been filled on the session (the recording could capture the secret).

Call via CDP: cdp.send('Browserless.startRecording', { width, height })

Returns: { recording, error? }.

ParameterTypeDescription
widthnumberOptional recording width.
heightnumberOptional recording height.

Browserless.stopRecording

Stops the recording started with startRecording and returns the video. Requires ?record=true.

Call via CDP: cdp.send('Browserless.stopRecording', { encoding: 'base64' })

Returns the encoded recording, or { error }.

ParameterTypeDescription
encodingstring"binary" or "base64".

Browserless.stopSessionRecording

Stops rrweb session-replay capture, then processes and uploads the events. Requires connecting with ?replay=true.

Call via CDP: cdp.send('Browserless.stopSessionRecording')

Returns: { error } (null on success).

Browserless.uploadFile

Uploads one or more files into a file <input> on the page, matched by selector. Total decoded size is capped per request.

Call via CDP: cdp.send('Browserless.uploadFile', { selector, files })

Returns: { ok, error? }.

ParameterTypeDescription
selectorstringRequired. CSS selector for the file input.
filesarrayRequired. Objects of { name, content, mimeType? } where content is base64 and mimeType is inferred from name if omitted.

Browserless.setDownloadEnabled

Toggles streaming of completed downloads back to the client as Browserless.fileDownloaded events. Off by default, so download bytes never flow unless you opt in.

Call via CDP: cdp.send('Browserless.setDownloadEnabled', { enabled: true })

Returns: { ok, enabled }.

ParameterTypeDescription
enabledbooleanWhether to emit fileDownloaded events.

Events

Subscribe with cdp.on('<EventName>', handler).

Browserless.heartbeat

Periodic keep-alive emitted on each attached session at the server's heartbeat interval. No params.

Browserless.captchaFound

Emitted when a CAPTCHA is auto-detected on a page.

Params: { type, status }status is "solving" when auto-solve is on, otherwise "found".

Browserless.captchaAutoSolved

Emitted after an auto-solve attempt completes (only when auto-solving is enabled).

Params: the solve result { found, solved, token, time, error? }.

Browserless.fileDownloaded

Emitted when a download completes, if enabled via setDownloadEnabled. Mirrored to every attached session.

Params: { filename, mimeType, size, data } (data base64), or { filename, mimeType, size, error: 'FileTooLarge', maxBytes } when the file exceeds the transfer limit.

Browserless.liveComplete

Emitted when a live URL viewer session ends. No params.

FAQ & Troubleshooting

Why does liveURL or reconnect return an error instead of a URL?

Each of these commands is gated on its own feature flag or query param for the session — live URLs, captcha solving, reconnect, and recording all have to be explicitly enabled. If the corresponding feature isn't on for the session, the command still returns successfully, but with error set instead of the expected field (liveURL, browserWSEndpoint, and so on). Check that you connected with the matching query param (for example ?record=true for recording) or that the feature is enabled on your plan.

Why isn't my cdp.on() handler firing?

CDP extension events are scoped to the session that triggered them, so cdp.on() has to be attached to the same CDPSession you called cdp.send() on, before the triggering action happens. A handler attached after the event already fired, or attached to a different page's CDP session, never receives it.

Why does Browserless.startRecording fail after I've already filled in a login form?

Recording is refused once a credential has been filled on the session, since the recording could capture the secret. Start recording before any authentication step, or use a separate session for the recorded portion of the flow.

Next steps