エージェントは Browser Run を使い、Chrome DevTools Protocol (CDP) 経由で Web ページを確認し操作できます。ベータ ブラウザーツールは、レンダリング済みページの理解、スクリーンショットの取得、フロントエンド動作のデバッグ、JavaScript 実行後にだけ存在する情報の抽出が必要なときに役立ちます。
クリック、スクリーンショット、ナビゲートといった固定のブラウザー操作ではなく、モデルがコードを書き、cdp コネクター経由でライブブラウザーセッションに対して CDP コマンドを実行します。プロトコルのすべてのドメイン、コマンド、イベント、型にアクセスできます。実行は 耐久性のある Code Mode ランタイム を使うため、承認で一時停止し、ブラウザーセッションを保ったまま再開できます。
ブラウザーツールは、エージェントに次をさせたいときに使います。
- ライブの Web ページを開いて確認する。
- スクリーンショットやページ状態を取得する。
- 静的 HTML に無い、レンダリング済みコンテンツをスクレイピングする。
- CDP コマンドでフロントエンドの問題をデバッグする。
- RAG や Sandbox など、ほかのツールとページ確認を組み合わせる。
Browser Run は、エージェントが CDP で制御できる分離されたブラウザーセッションを提供します。エージェントはページの移動、JavaScript の評価、DOM 状態の読み取り、スクリーンショットの取得、ネットワークやコンソール出力の確認ができます。
ブラウザーセッションは Worker isolate の外で動きます。軽量な HTTP fetch ではなく、実際のブラウザー環境が必要な作業に使います。
Browser Run と Worker Loader のバインディングでブラウザーツールを作成し、モデル呼び出しへ渡します。
import { AIChatAgent } from "@cloudflare/ai-chat";
import { createBrowserTools } from "agents/browser/ai";
import { streamText, convertToModelMessages, stepCountIs } from "ai";
import { createWorkersAI } from "workers-ai-provider";
export class BrowserAgent extends AIChatAgent {
async onChatMessage() {
const workersai = createWorkersAI({ binding: this.env.AI });
const browserTools = createBrowserTools({
ctx: this.ctx,
browser: this.env.BROWSER,
loader: this.env.LOADER,
});
const result = streamText({
model: workersai("@cf/zai-org/glm-4.7-flash"),
system: "You can inspect web pages with browser tools.",
messages: await convertToModelMessages(this.messages),
tools: browserTools,
stopWhen: stepCountIs(10),
});
return result.toUIMessageStreamResponse();
}
}import { AIChatAgent } from "@cloudflare/ai-chat";
import { createBrowserTools } from "agents/browser/ai";
import { streamText, convertToModelMessages, stepCountIs } from "ai";
import { createWorkersAI } from "workers-ai-provider";
export class BrowserAgent extends AIChatAgent<Env> {
async onChatMessage() {
const workersai = createWorkersAI({ binding: this.env.AI });
const browserTools = createBrowserTools({
ctx: this.ctx,
browser: this.env.BROWSER,
loader: this.env.LOADER,
});
const result = streamText({
model: workersai("@cf/zai-org/glm-4.7-flash"),
system: "You can inspect web pages with browser tools.",
messages: await convertToModelMessages(this.messages),
tools: browserTools,
stopWhen: stepCountIs(10),
});
return result.toUIMessageStreamResponse();
}
}ブラウザーツールは Durable Object(Agent など)の内側で作成します。耐久ランタイムのファセットとセッションストアは、その ctx 上にあります。ヘルパーは、耐久 CDP ツールを 1 つ公開します。browser バインディングがあるときは、ステートレスな Quick Action ツールも公開します。
| ツール | 説明 |
|---|---|
browser_execute |
CDP 経由でライブブラウザーに対してサンドボックスコードを実行します。スクリーンショット、DOM 読み取り、JavaScript 評価などです。 |
browser_markdown |
ページまたは生 HTML を Markdown として読みます。 |
browser_extract |
AI でページから構造化データを抽出します。 |
browser_links |
ページ上のリンクを一覧します。 |
browser_scrape |
CSS セレクターで特定の要素をスクレイピングします。 |
プロトコル面の発見には、モデルが cdp.spec()(ライブで正規化された CDP プロトコル説明)またはランタイム組み込みの codemode.search() と codemode.describe() を呼び出します。
wrangler.jsonc に Browser Run と Worker Loader のバインディングを追加します。
{
"compatibility_flags": ["nodejs_compat"],
"browser": {
"binding": "BROWSER"
},
"worker_loaders": [
{
"binding": "LOADER"
}
]
}compatibility_flags = [ "nodejs_compat" ]
[browser]
binding = "BROWSER"
[[worker_loaders]]
binding = "LOADER"ツール背後の耐久ランタイムは Durable Object ファセット上にあるため、Worker エントリでエクスポートします(@cloudflare/codemode/vite プラグインは自動で行います)。
export { CodemodeRuntime } from "agents/browser";export { CodemodeRuntime } from "agents/browser";agents/browser は、ブラウザーツール構成向けに Code Mode ランタイムを再エクスポートします。Code Mode 固有の例では、@cloudflare/codemode から CodemodeRuntime をインポートすることもできます。
デフォルトでは、実行ごとに新しいブラウザーセッションを作り、実行終了時に破棄します(one-shot)。session オプションを渡すと、次の 2 モードも使えます。
createBrowserTools({
ctx: this.ctx,
browser: this.env.BROWSER,
loader: this.env.LOADER,
session: { mode: "dynamic" }, // or { mode: "reuse", key: "main" }
});createBrowserTools({
ctx: this.ctx,
browser: this.env.BROWSER,
loader: this.env.LOADER,
session: { mode: "dynamic" }, // or { mode: "reuse", key: "main" }
});one-shot(デフォルト) — 実行ごとに新しいセッション。実行が終端ステータスに達すると確定的にクリーンアップします。reuse— 名前付きの共有セッション。明示的に閉じるかスイープするまで、実行をまたいで残ります。dynamic— one-shot で開始します。モデルはcdp.startSession()でセッションを昇格できます(ページへログインしたあとなど)。以降の実行は同じブラウザーで続きます。
reuse と dynamic モードでは、サンドボックスに cdp.startSession()、cdp.sessionInfo()、cdp.closeSession()、cdp.resetSession() も渡されます。
セッションは Durable Object のストレージに耐久的に記録されます。ハイバーネーションと承認の一時停止をまたいで残ります。人が承認するまで一時停止した実行は、ブラウザーセッション、タブ、Cookie を保ったまま再開します。一時停止中に Browser Run がセッションを期限切れにした場合、再開時に明確なエラーが出て、モデルはやり直します。
ホスト側の配線(セッションの確認、クリーンアップ、古い一時停止の回収)には createBrowserRuntime を使い、{ runtime, connector, tools } を受け取ります。期限切れや古いセッションの回収は、スケジュールしたタスクから connector.sweep() を呼びます。承認されなかった古い一時停止の拒否は runtime.expirePaused() です。
対話的で複数ステップの自動化には browser_execute を使います。ワンショットのブラウジングには Browser Run Quick Actions を使います。Quick Actions に必要なのは browser バインディングだけです。Worker Loader やサンドボックスは不要です。
import { createQuickActionTools } from "agents/browser/ai";
const tools = createQuickActionTools({ browser: this.env.BROWSER });
// browser_markdown, browser_extract, browser_links, browser_scrapeimport { createQuickActionTools } from "agents/browser/ai";
const tools = createQuickActionTools({ browser: this.env.BROWSER });
// browser_markdown, browser_extract, browser_links, browser_scrapeデフォルトでは、createBrowserTools と createBrowserRuntime は browser バインディングがあるとき Quick Action ツールを含めます。browser_execute だけ残す場合は quickActions: false を渡します。ステートレスツールを設定する場合は quickActions: { actions, maxChars, options } を渡します。
createBrowserTools({
browser: this.env.BROWSER,
loader: this.env.LOADER,
quickActions: { maxChars: 20_000 },
});createBrowserTools({
browser: this.env.BROWSER,
loader: this.env.LOADER,
quickActions: { maxChars: 20_000 },
});Quick Action の結果はすべて maxChars で上限され、結果の形を保ったままモデルのコンテキストウィンドウを守ります。ホストが渡すリクエストオプション(cookies、authenticate、gotoOptions、viewport など)は options 経由で一度だけ渡り、モデルには公開されません。
Quick Actions には、Worker の compatibility_date が 2026-03-24 以降であることと、ローカルの wrangler dev 向けにブラウザーバインディングの remote: true が必要です。
Live View では、人が実行中のブラウザーセッションをリアルタイムで監視または操作できます。ログイン、MFA、CAPTCHA、機密入力など、人が介在するステップに使います。
Code Mode ランタイムはブラウザーセッションを保ったまま実行を一時停止できるため、引き継ぎは次の流れです。
- モデルが
cdp.getLiveViewUrl()を呼び、現在のタブへのリンクを取得します。 - エージェントがそのリンクをユーザーへ提示します。
- モデルが承認ゲート付きの呼び出しを行い、実行が耐久的に一時停止します。
- 承認後、同じセッションに対して実行が再開します。
async () => {
const { targetId } = await cdp.send({
method: "Target.createTarget",
params: { url: "https://example.com/login" },
});
const { url } = await cdp.getLiveViewUrl({ targetId, mode: "tab" });
return { needsHumanLogin: url };
};async () => {
const { targetId } = await cdp.send({
method: "Target.createTarget",
params: { url: "https://example.com/login" },
});
const { url } = await cdp.getLiveViewUrl({ targetId, mode: "tab" });
return { needsHumanLogin: url };
};対話的なページ表示には mode: "tab"、完全な DevTools インスペクターには mode: "devtools" を渡します。URL の有効期限は約 5 分です。新しい URL を作るには、再度 cdp.getLiveViewUrl() を呼びます。
ホスト側では、connector.liveView() が共有セッションのタブ向け Live View URL を返します。各タブには現在の pageUrl が含まれるため、エージェント UI はタブにラベルを付け、空白や内部ページをスキップできます。
セッション録画 は、Browser Run セッションを構造化された rrweb イベントとして記録します。自律ブラウザー実行がセッション終了後に何をしたかを監査またはデバッグするときに使います。
セッションごとに recording: true でオプトインします。
import { createBrowserRuntime } from "agents/browser/ai";
const { connector } = createBrowserRuntime({
ctx: this.ctx,
browser: this.env.BROWSER,
loader: this.env.LOADER,
session: { mode: "reuse", key: "main", recording: true },
});import { createBrowserRuntime } from "agents/browser/ai";
const { connector } = createBrowserRuntime({
ctx: this.ctx,
browser: this.env.BROWSER,
loader: this.env.LOADER,
session: { mode: "reuse", key: "main", recording: true },
});録画はセッション終了後に確定します。セッションが生きているあいだにセッション ID を取得し、Browser Rendering REST API から録画を取得します。
import { getBrowserRecording } from "agents/browser";
const { sessionId } = (await connector.sessionInfo()) ?? {};
if (!sessionId) {
throw new Error("No active browser session");
}
const recording = await getBrowserRecording({
accountId: this.env.CF_ACCOUNT_ID,
apiToken: this.env.CF_API_TOKEN,
sessionId,
});import { getBrowserRecording } from "agents/browser";
const { sessionId } = (await connector.sessionInfo()) ?? {};
if (!sessionId) {
throw new Error("No active browser session");
}
const recording = await getBrowserRecording({
accountId: this.env.CF_ACCOUNT_ID,
apiToken: this.env.CF_API_TOKEN,
sessionId,
});録画の保持期間は 30 日で、セッションあたり最大 2 時間です。共有の reuse および dynamic セッションでは、録画がセッション寿命全体に及ぶため、意図して使います。
browser_execute 内の cdp 名前空間は、次のメソッドを提供します。すべてのメソッドはオブジェクト引数を 1 つ取ります。
| メソッド | 説明 |
|---|---|
cdp.send({ method, params?, sessionId?, timeoutMs? }) |
CDP コマンドを送り、応答を待ちます。 |
cdp.attachToTarget({ targetId, timeoutMs? }) |
ターゲットへアタッチします。ページスコープの send 向けに { sessionId } を返します。 |
cdp.spec() |
検索可能な、正規化された CDP プロトコル仕様です。 |
cdp.getDebugLog({ limit? }) |
この実行の接続に関する最近の CDP トラフィック(送信、受信、警告)です。 |
cdp.clearDebugLog() |
デバッグログバッファーをクリアします。 |
cdp.getLiveViewUrl({ targetId?, mode? }) |
タブ向けの Live View URL を作成します。 |
cdp.startSession() (reuse/dynamic) |
共有セッションを昇格または確保し、その情報を返します。 |
cdp.sessionInfo() (reuse/dynamic) |
共有セッション情報。無い場合は null。 |
cdp.closeSession() (reuse/dynamic) |
共有セッションを閉じます。 |
cdp.resetSession() (reuse/dynamic) |
共有セッションを閉じて置き換えます。 |
すべての cdp.* 呼び出しは、ランタイムの耐久ログに記録されます。実行が一時停止(承認)するかサンドボックスが中断した場合、再開時にログを再生して続行します。そのため、コネクター呼び出しは逐次で決定的である必要があります。モデルのコードは CDP 呼び出しを Promise.all してはいけません(ツールの手順がこれを強制します)。返される sessionId は安定したセッションハンドルで、一時停止と再開の再接続をまたいで有効です。
Browser Run のセットアップ、ツール定義、スクリーンショット取得を含む完全な手順は、ブラウザーエージェントの例を使います。