Cloudflare Agents browserTool入門——永続ブラウザ操作をFirestoreで監査する
Cloudflare Agents SDKの永続ブラウザツールを題材に、AIエージェントのタブ、ログイン、人間引き継ぎをNext.js + Firestoreで監査する実践設計を解説します。

はじめに
AIエージェントにブラウザ操作を任せると、問い合わせ管理、レポート確認、外部SaaSの入力補助まで自動化しやすくなります。一方で、ログイン後の画面をまたぐ処理では、次の不安が残ります。
| 場面 | 残したい証跡 |
|---|---|
| ログイン済み画面を調査する | どのタブで何を見たか |
| スクリーンショットをもとに判断する | どの会話・タスクの結果か |
| MFAや送信直前で人間に渡す | 誰が確認し、承認したか |
Cloudflareは2026年10月13日のAgents Changelogで、Agents SDKに browserTool を追加したと発表しました。Browser Run のブラウザをエージェントが後続ターンでも使い続けられ、タブ、Cookie、ログイン状態をセッション存続中に再利用できます。公式ドキュメントではAgents SDK v0.28.0以降が必要で、既定のアイドルタイムアウトは10分、期限切れやクラッシュ後は restarted: true が返ると説明されています。
本記事では、架空の問い合わせ管理SaaS「SupportTrail」を題材に、Next.js App Router + Firestore + TypeScriptで「永続ブラウザをどう監査するか」を実装寄りに整理します。
参考にした一次情報は、Cloudflare Agents Changelog、Cloudflare Agents: Browser、Cloudflare Agents: Web search、Cloudflare Agents: Web fetch、Firebase: Cloud Firestore add dataです。
何が新しいのか
従来のブラウザ操作は、1回のツール呼び出しでページを開いて結果を返す形になりがちでした。永続ブラウザでは、エージェントが次のターンで同じブラウザへ戻れます。ログイン済み画面、開いたタブ、Cookieを使いながら、複数ターンにまたがる調査や入力補助を作りやすくなります。
ただし、これは「AIに自由にブラウザを触らせてよい」という意味ではありません。CloudflareのBrowserドキュメントは、Live View URLをブラウザ操作できるベアラー資格情報として扱い、信頼済みユーザーだけに見せ、保存せず、モデルにも渡さないよう注意しています。
業務アプリ側で最低限記録したい項目は次の4つです。
| 記録項目 | 理由 |
|---|---|
conversationId | どのAI会話のブラウザ操作か追跡する |
scope | 会話ごとのアクティブタブを分ける |
restarted | 前のタブやログイン状態が失われた可能性を検知する |
humanHandoff | MFA、CAPTCHA、重要入力を人間に渡した証跡を残す |
全体像
SupportTrailでは、Cloudflare Worker上のAgentが外部SaaSの問い合わせ履歴を確認し、Next.js側は監査台帳とレビューUIを担当します。ブラウザ操作そのものはCloudflare側に置き、Next.jsには結果イベントだけを送ります。
ポイントは、Live View URLそのものをFirestoreに保存しないことです。保存するのは「人間へ引き継いだ」「誰が確認した」「承認したか」という監査事実に限定します。
ハンズオン1: Firestoreの台帳を作る
まず、Next.js側で保存する型を決めます。allowedHosts はCloudflare側のガードレールとは別に、アプリ側の意図を残すための項目です。細かなスクリーンショット本文やLive View URLは保存せず、監査に必要な要約だけを残します。
export type BrowserSession = {
id: string;
conversationId: string;
status: "running" | "needs_human" | "completed" | "failed";
allowedHosts: string[];
updatedAt: FirebaseFirestore.Timestamp;
};
export type BrowserEvent = {
sessionId: string;
eventType: "page_opened" | "screenshot" | "handoff_requested" | "closed";
pageUrl?: string;
restarted: boolean;
requiresHuman: boolean;
summary: string;
};
restarted: true のイベントが届いたら、前のタブやログイン状態がない前提で扱います。再ログイン待ち、再取得待ち、または人間確認待ちへ状態を変えると安全です。
ハンズオン2: Workerイベントを受け取る
Cloudflare WorkerからNext.jsへ送られるイベントを保存するRoute Handlerを作ります。ここでは共有シークレットで保護する簡略例です。本番では署名検証、リプレイ防止、プロジェクト権限も組み合わせてください。
// src/app/api/agent-browser-events/route.ts
import { NextRequest, NextResponse } from "next/server";
import { FieldValue, getFirestore } from "firebase-admin/firestore";
export async function POST(request: NextRequest) {
if (request.headers.get("x-agent-event-secret") !== process.env.AGENT_EVENT_SECRET) {
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
}
const payload = await request.json();
const db = getFirestore();
const now = FieldValue.serverTimestamp();
await db.collection("browserSessions").doc(payload.sessionId).collection("events").add({
...payload,
restarted: payload.restarted ?? false,
requiresHuman: payload.requiresHuman ?? false,
createdAt: now,
});
await db.collection("browserSessions").doc(payload.sessionId).set(
{
conversationId: payload.conversationId,
status: payload.requiresHuman ? "needs_human" : "running",
updatedAt: now,
},
{ merge: true },
);
return NextResponse.json({ ok: true });
}
ハンズオン3: Cloudflare側ではscopeを渡す
CloudflareのBrowserドキュメントでは、AI SDKアダプター利用時に scope を省略すると1つのアクティブタブを共有すると説明されています。SupportTrailでは、会話ごとに conversationId を渡してタブを分けます。
import { browserTool } from "agents/browser/ai-sdk";
const tools = {
browser: browserTool({
ctx: this.ctx,
browser: this.browser,
loader: this.env.LOADER,
scope: conversationId,
}),
};
Live Viewで人間に渡す場合も、URLは保存しません。Firestoreには reviewerId、decision、note、createdAt だけを残し、資格情報になり得るリンクは画面表示のたびにCloudflare側から取り直します。
GitHub Actionsで未完了セッションを検知する
ブラウザ操作は途中で止まることがあります。毎朝、古い running / needs_human セッションを確認するAPIを叩くと、レビュー漏れを見つけやすくなります。
name: browser-session-audit
on:
schedule:
- cron: "0 22 * * *"
workflow_dispatch:
jobs:
audit:
runs-on: ubuntu-latest
steps:
- name: Check stale browser sessions
run: |
curl -fsS -X POST "$AUDIT_ENDPOINT" \
-H "Authorization: Bearer $AUDIT_TOKEN"
env:
AUDIT_ENDPOINT: ${{ secrets.BROWSER_SESSION_AUDIT_ENDPOINT }}
AUDIT_TOKEN: ${{ secrets.BROWSER_SESSION_AUDIT_TOKEN }}
使い分けの目安
永続ブラウザは強力ですが、すべての情報取得に使う必要はありません。
| 目的 | 使うもの |
|---|---|
| URLがわからない最新情報を探す | web_search |
| 既知URL、PDF、JSON、長文ページを読む | web_fetch |
| JavaScript描画、ログイン、タブ継続、スクリーンショットが必要 | browserTool |
ブラウザは状態を持つぶん、監査と権限管理が重くなります。まず web_search / web_fetch で済む処理を分け、状態が必要な場面だけ browserTool に寄せるのが現実的です。
まとめ
Cloudflare Agents SDKの browserTool は、AIエージェントがブラウザを「その場限りの取得」ではなく「続きから作業できる環境」として扱うための重要な更新です。一方で、ログイン状態、タブ、スクリーンショット、人間引き継ぎが絡むため、業務アプリでは監査設計が欠かせません。
SupportTrailの例では、Cloudflare Workerにブラウザ操作を任せ、Next.js + Firestoreではイベント、再起動、人間承認を記録しました。読み取り中心の小さなタスクから始め、web_search、web_fetch、browserTool を使い分けると、安全にAIブラウザ操作を導入できます。