Clawdbotのブラウザ操作設計が良すぎたので自分のプロジェクトにパクった
はじめに
Clawdbot(現在はOpenClawに改名)は、2025年11月に登場し、2026年1月に爆発的に話題になったオープンソースのAIアシスタントです。24時間で9000スター、数日で6万スター超えという異例のスピードでGitHub最速クラスの成長を見せました。
このプロジェクトのブラウザ操作モジュールを読んでみたところ、かなり良い設計になっていて、正直「これは真似するしかない」と思いました。
この記事では、Clawdbotのブラウザ操作設計の何が良かったのかを紹介します。

AIブラウザ操作の現状
最近のAIエージェントがブラウザを操作する方法として、アクセシビリティツリーを使うアプローチが主流になってきています。
アクセシビリティツリーとは、ブラウザがスクリーンリーダーなどの支援技術向けに構築する、ページ構造の情報です。「ここにボタンがある」「これは入力欄」といった、要素の意味的な情報が含まれています。
たとえば、Claude for ChromeやPlaywright MCPも、このアクセシビリティツリーをベースにしています(スクリーンショットも併用しますが、主軸はアクセシビリティツリーです)。CSSセレクタのようにHTML構造に依存せず、要素の意味で操作できるのが利点です。
ただ、同じアクセシビリティツリーを使っていても、実装のアプローチはツールによってかなり違います。Clawdbotのコードを読んでいて、「ここはうまいな」と思った工夫がいくつかありました。
Clawdbotの工夫
アクセシビリティツリーを使うツールでは、要素をRefという短いID(e1, e2, e3...)で参照するのが一般的です。Playwright MCPもこの方式を採用しています。
Clawdbotの特徴は、Refの管理方法を柔軟に選べる点です。Playwrightが生成するRefをそのまま使うこともできますし、独自のロジックで振り直すこともできます。
基本的な流れ
たとえば、ログインページのスナップショットはこんな感じになります。
- button "Sign In" [ref=e1]
- textbox "Email" [ref=e2]
- textbox "Password" [ref=e3]
- checkbox "Remember me" [ref=e4]
AIは「e2にメールアドレスを入力して、e3にパスワードを入力して、e1をクリック」と指示するだけで済みます。
なぜARIA役割なのか
ポイントは、この参照IDがCSSセレクタではなく、ARIA役割(role)と名前(name) に基づいている点です。
type RoleRef = {
role: string; // "button", "textbox", "link" など
name?: string; // "Sign In", "Email" など
nth?: number; // 同じ役割+名前が複数ある場合のインデックス
};
ARIA役割とは、スクリーンリーダーなどの支援技術向けに定義された「この要素が何なのか」を表す情報です。
CSSクラス名が btn-primary から submit-btn に変わっても、「Sign Inというボタン」であることは変わりません。見た目やスタイルが変わっても、機能的な意味は維持されます。
要素の分類
すべての要素にRefを振るのではなく、役割に応じて分類しています。
| 分類 | 例 | Refの扱い |
|---|---|---|
| インタラクティブ要素 | button, link, textbox, checkbox | 必ずRef付与 |
| コンテンツ要素 | heading, cell, listitem | 名前がある場合のみ |
| 構造要素 | generic, group, list, table | Ref不要 |
これによって、スナップショットのノイズが減り、AIにとって必要な情報だけが残ります。
キャッシュ機構
スナップショットを取るたびにRefを振り直すと、同じボタンが「e1」になったり「e5」になったりして混乱します。
Clawdbotでは、ページのtargetIdごとにRefをキャッシュする仕組みを持っています。
const roleRefsByTarget = new Map<string, RoleRefsCacheEntry>();
const MAX_ROLE_REFS_CACHE = 50;
スナップショットAで取得した「e1」を、その後のクリック操作でも使えるようにしているわけです。キャッシュは最大50件で、古いものから削除されます。
Compactモード
ページによっては、構造要素が深くネストしていて、スナップショットが長くなりすぎることがあります。
Compactモードを有効にすると、Refを持たない構造要素が自動的に省略されます。
通常モード:
- generic
- group
- button "Submit" [ref=e1]
Compactモード:
- button "Submit" [ref=e1]
AIへの入力トークンを節約できるので、実用上かなり効果があります。
Playwright MCPとの違い
同じくアクセシビリティツリーを使うツールとして、Playwright MCP(Microsoft公式)があります。同じ土台を使っていますが、設計のアプローチが結構違っていて面白いです。
ツールの数
Playwright MCPは browser_click、browser_type、browser_snapshot など、操作ごとに別々のツールを用意しています。全部で20以上あります。
一方、Clawdbotは1つの browser ツールに action 引数を持たせて、すべての操作をカバーしています。
// Playwright MCP: 操作ごとに別ツール
browser_click({ element: "Submit", ref: "e2" })
browser_type({ element: "Email", ref: "e1", text: "test@example.com" })
// Clawdbot: 1つのツールでaction引数で分岐
{ action: "click", ref: "e2" }
{ action: "type", ref: "e1", text: "test@example.com" }
ツール定義が少ない方がLLMにとって理解しやすく、トークン効率も良くなります。
Playwright MCPはアクセシビリティツリーをそのまま返す感じですが、Clawdbotは前述の三分類でフィルタリングしてから返します。
この差は、ページが複雑になるほど効いてきます。ECサイトのトップページなど、要素が多いページでは特に。
Clawdbotは、Playwright以外のブラウザ実装にも対応できるように設計されています。自前でRefを管理しているので、ブラウザエンジン側の実装に依存しにくい構造になっています。
どちらが良いかは用途次第ですが、シンプルさとトークン効率を重視するならClawdbotのアプローチは参考になります。
自分のプロジェクトへ
自分のAgentプロジェクトに、これらの設計思想を取り入れてみました。
元のコードをそのまま使ったわけではなく、プロジェクトの構造に合わせて書き直しています。特に要素の三分類(インタラクティブ・コンテンツ・構造)と単一ツール設計は、そのまま参考にしました。
// 自分のプロジェクトでの実装例
browser({ action: "snapshot" })
browser({ action: "click", ref: "e1" })
browser({ action: "type", ref: "e2", text: "hello" })
実際に使ってみると、Playwright MCPをそのまま使っていた頃と比べて、操作の速度も精度もかなり上がった印象があります。ツールが1つにまとまっているので、AIが迷わずに済むのかもしれません。
あと、個人的にやっているのは、よく使うサイトの独特な操作パターンをSkillとしてまとめておくことです。たとえば「このサイトのログインはこういう手順」「この画面ではこのボタンを押す前に待機が必要」といった情報を事前に読み込ませておくと、操作の精度がさらに上がりますね。
実際の操作シナリオ
自分のAgentプロジェクトで実際にAIが楽天市場でキーボードを検索する様子を録画してみました。

このシナリオでは、以下の操作を自律的に行っています:
- 楽天市場のトップページへ移動
- 検索ボックスに「キーボード」と入力
- 価格フィルターで20000円〜25000円を設定
- 検索結果から商品を選択
- 詳細ページをスクロールして情報を取得
スナップショットで取得したRef(e1, e2...)を使って、AIが自分で判断しながら操作を進めています。途中でページが変わってもRefを取り直して対応できるのが、この設計の強みですね。
まとめ
アクセシビリティツリーを使ったブラウザ操作は、今やいろんなツールで採用されています。その中でClawdbotは、要素の分類・フィルタリング・単一ツール設計といった工夫で、よりシンプルで効率的な実装を実現していました。
自分のプロジェクトに取り入れてみて、今のところうまく動いています。もっと良い方法があれば、ぜひ教えてください。
Discussion