Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ pcx_content_type: how-to
title: Custom fonts
description: Learn how to add custom fonts to Browser Rendering for use in screenshots and PDFs.
sidebar:
order: 1
order: 3
---

import { Tabs, TabItem } from "~/components";
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
---
pcx_content_type: how-to
title: Human in the Loop
description: Temporarily hand off browser control to a human operator for authentication, sensitive actions, or tasks that are difficult to fully automate.
sidebar:
order: 2
badge: Beta
---

Some browser automation workflows require manual intervention. A login page may need multi-factor authentication, a form may require sensitive credentials you do not want to pass to an automation script, or a task may be too complex to fully automate. Human in the Loop lets a human step into a live browser session through [Live View](/browser-rendering/features/live-view/) to handle what automation cannot, then hand control back to the script.

## How it works

Human in the Loop works with any [Browser Session](/browser-rendering/#integration-methods) and uses [Live View](/browser-rendering/features/live-view/) to give humans access:

1. Your automation script navigates to a page that needs human input.
2. The script retrieves the [Live View](/browser-rendering/features/live-view/) URL from the session's target list and shares it with a human operator (for example, by sending it via Slack, email, or displaying it in a user interface).
3. The human operator opens the Live View URL and completes the required action (logging in, solving a CAPTCHA, entering sensitive data, etc.).
4. The automation script detects that the human is done (for example, by waiting for a navigation event or polling for a page element) and resumes.

A more structured handoff flow where the agent can signal that it needs help and notify a human is coming soon.
Comment thread
kathayl marked this conversation as resolved.

## Example: login with human assistance

This example uses [Puppeteer](/browser-rendering/puppeteer/) connected to Browser Run via the [CDP](/browser-rendering/cdp/) endpoints. The script navigates to a login page, shares a Live View URL for a human to enter credentials, then continues the automation after login completes.

```js
import puppeteer from "puppeteer-core";

const ACCOUNT_ID = "<your-account-id>";
const API_TOKEN = "<your-api-token>";

// Create a browser session via CDP
const response = await fetch(
`https://api.cloudflare.com/client/v4/accounts/${ACCOUNT_ID}/browser-rendering/devtools/browser?keep_alive=600000&targets=true`,
{
method: "POST",
headers: { Authorization: `Bearer ${API_TOKEN}` },
}
);
const { webSocketDebuggerUrl, targets } = await response.json();
const liveUrl = targets[0].devtoolsFrontendUrl;
Comment thread
kathayl marked this conversation as resolved.

// Connect Puppeteer to the session
const browser = await puppeteer.connect({
browserWSEndpoint: webSocketDebuggerUrl,
headers: { Authorization: `Bearer ${API_TOKEN}` },
});

const page = await browser.newPage();
await page.goto("https://example.com/login");

// Share the Live View URL with the human operator (for example, send it via Slack, email, or display it in a UI)
console.log(`Human input needed. Open this URL: ${liveUrl}`);
Comment thread
kathayl marked this conversation as resolved.

// Wait for the human to complete login (5 minute timeout — the script will continue after this period)
await page.waitForNavigation({ waitUntil: "networkidle0", timeout: 300000 });

// Login complete, continue automation
const cookies = await page.cookies();
console.log("Login complete. Continuing automation...");

await page.goto("https://example.com/dashboard");
const content = await page.content();

browser.disconnect();
```

The Live View URL is valid for five minutes from when it was generated. If the URL expires before the human operator opens it, list the targets again to get a fresh URL.

## Use cases

- **Authentication flows**: Login pages with MFA, SSO, or CAPTCHA that cannot be bypassed programmatically
Comment thread
kathayl marked this conversation as resolved.
- **Sensitive data entry**: Forms requiring credentials or personal information you do not want to pass to an automation script
- **Complex interactions**: One-off tasks that are too difficult or not worth fully automating, such as configuring a dashboard or approving a workflow
- **Verification steps**: Confirming an order, reviewing generated content, or approving an action before the script proceeds

:::note[Bot detection]
Browser Rendering requests are [always identified as bot traffic](/browser-rendering/faq/#will-browser-rendering-be-detected-by-bot-management). Even with a human controlling the session, some third-party services may still block the request.
:::
126 changes: 126 additions & 0 deletions src/content/docs/browser-rendering/features/live-view.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
---
pcx_content_type: how-to
title: Live View
description: View and interact with remote Browser Run sessions in real time using the hosted DevTools UI or native Chrome DevTools.
sidebar:
order: 1
badge: Beta
---

import { CURL, DashButton } from "~/components";

Live View lets you see and interact with a remote Browser Run session in real time. This is useful for debugging automation scripts, monitoring what a browser is doing, or manually stepping in when a task requires human intervention (see [Human in the Loop](/browser-rendering/features/human-in-the-loop/)).

Live View is available for any [Browser Session](/browser-rendering/#integration-methods), including sessions created with [Puppeteer](/browser-rendering/puppeteer/), [Playwright](/browser-rendering/playwright/), or the [CDP](/browser-rendering/cdp/) endpoints.

## How to access Live View

There are three ways to access Live View: through the Cloudflare dashboard, via the hosted user interface (UI) at `live.browser.run`, or using native Chrome DevTools.

### Cloudflare dashboard

In the Cloudflare dashboard, go to the **Browser Run** page and select the **Live Sessions** tab. This shows all active browser sessions in your account. Expand a session to see its tabs, then select **Open** to open the Live View for that tab.

<DashButton url="/?to=/:account/workers/browser-rendering" />

### Hosted UI (any browser)

When you create a session or list targets through the [CDP](/browser-rendering/cdp/) endpoints, the API response includes a `devtoolsFrontendUrl` for each target (tab). Open this URL in any browser to load the DevTools UI hosted at `live.browser.run`, which streams the remote session to your browser.

The hosted UI supports two viewing modes, controlled by the `mode` parameter in the URL:

| Mode | URL pattern | Description |
| --- | --- | --- |
| Tab | `https://live.browser.run/ui/view?mode=tab&wss=...` | Standalone page view |
| Inspector | `https://live.browser.run/ui/view?mode=devtools&wss=...` | DevTools inspector panel (Elements, Console, Network, etc.) |

Comment thread
kathayl marked this conversation as resolved.
### Native Chrome DevTools (Chrome only)

Because Browser Run speaks standard CDP, you can connect Chrome's built-in DevTools directly to a remote session. Replace the `https://live.browser.run/ui/inspector?wss=` prefix in the `devtoolsFrontendUrl` with the `devtools://` protocol:

```txt
devtools://devtools/bundled/inspector.html?wss=live.browser.run/api/devtools/browser/SESSION_ID/page/TARGET_ID?jwt=...
```

Paste this URL into Chrome's address bar to connect native DevTools to the remote browser session. You will get the same DevTools interface you use for local debugging. The `devtools://` protocol is Chrome-only and limited to inspector viewing mode.

:::caution[URL validity]
The `devtoolsFrontendUrl` is valid for five minutes from when it was generated. If you do not open the URL within this timeframe, list the targets again to get a fresh URL. Once the DevTools connection is established, it remains active as long as the browser session is alive.
:::

## View a new session

1. Create a browser session with `targets=true` to include target URLs in the response:

<CURL
url="https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/browser-rendering/devtools/browser"
method="POST"
headers={{
Authorization: "Bearer $CLOUDFLARE_API_TOKEN",
}}
query={{
keep_alive: "600000",
targets: "true",
}}
/>

```json
{
"sessionId": "1909cef7-23e8-4394-bc31-27404bf4348f",
"targets": [
{
"description": "",
"devtoolsFrontendUrl": "https://live.browser.run/ui/inspector?wss=live.browser.run/api/devtools/browser/1909cef7-.../page/8E598E99...?jwt=...",
"id": "8E598E996530FB09E46A22B8B7754F7F",
"title": "about:blank",
"type": "page",
"url": "about:blank",
"webSocketDebuggerUrl": "wss://live.browser.run/api/devtools/browser/1909cef7-.../page/8E598E99...?jwt=..."
}
],
"webSocketDebuggerUrl": "wss://api.cloudflare.com/client/v4/accounts/{account_id}/browser-rendering/devtools/browser/1909cef7-..."
}
```

2. Copy the `devtoolsFrontendUrl` from `targets[0]` and open it in your browser. You now have a live, interactive view of the remote browser session.

## View an existing session

If you have a running session and want to connect to it:

1. List your active sessions:

<CURL
url="https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/browser-rendering/devtools/session"
method="GET"
headers={{
Authorization: "Bearer $CLOUDFLARE_API_TOKEN",
}}
/>

2. Using the session ID, list the targets in that session:

<CURL
url="https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/browser-rendering/devtools/browser/$SESSION_ID/json/list"
method="GET"
headers={{
Authorization: "Bearer $CLOUDFLARE_API_TOKEN",
}}
/>


```json output {8}
[
{
"id": "110850A800BDB8B593CDDA30676635CF",
"type": "page",
"url": "https://example.com",
"title": "Example Domain",
"description": "",
"devtoolsFrontendUrl": "https://live.browser.run/ui/view?wss=live.browser.run/api/devtools/browser/28d75446-.../page/110850A8...?jwt=...",
"webSocketDebuggerUrl": "wss://live.browser.run/api/devtools/browser/28d75446-.../page/110850A8...?jwt=..."
}
]
```

3. Copy the `devtoolsFrontendUrl` and open it in your browser.
Loading