AI

Cloudflare Agents browserTool入門——永続ブラウザ操作をFirestoreで監査する

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

2026年10月14日
CloudflareAgents SDKBrowser RunNext.jsFirestore
Cloudflare Agents browserTool入門——永続ブラウザ操作を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前のタブやログイン状態が失われた可能性を検知する
humanHandoffMFA、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ブラウザ操作を導入できます。