TypeScriptでブラウザ操作をAI化するなら、2026年現在の最有力候補がStagehandだ。GitHub Stars 22.5k、MIT ライセンスのOSSで、Browserbase社が開発する「TypeScript製ブラウザAIエージェントFW」として急速に普及している。
PythonのBrowser-useが「フルエージェント自律実行」を目指すのに対し、Stagehandは「PlaywrightにAIを後付けする」ハイブリッド設計。TypeScript開発者が既存コードを壊さずAI化できる点が最大の差別化ポイントだ。
本記事ではインストールから実践コードまで、Stagehandを今日から使い始めるために必要な情報を全部まとめた。
Stagehandとは何か?Browser-useとの本質的な違い
StagehandはPlaywrightのラッパーとして動作する。既存のPlaywrightコードにAI命令を数行追加するだけで、セレクタ指定なしのブラウザ操作が可能になる。
Browser-useとの根本的な違いを整理すると次のとおりだ。
| 項目 | Stagehand | Browser-use |
|---|---|---|
| 言語 | TypeScript(主) | Python |
| 設計思想 | PlaywrightにAIを後付け | フルエージェント自律実行 |
| AI呼び出しタイミング | 必要な時だけ | 常時LLM推論 |
| 制御粒度 | ステップごとに制御可能 | ゴール指定で全自動 |
| GitHub Stars | 22.5k | 50k+ |
| ライセンス | MIT | MIT |
「ブラウザ操作の途中でデータを検証したい」「特定のステップだけ人間が確認したい」といったケースではStagehandが圧倒的に扱いやすい。一方、ゴールだけ渡して全部任せたいならBrowser-useが向く。
インストールとセットアップ(5分)
npmパッケージ名は @browserbasehq/stagehand だ。
npm install @browserbasehq/stagehand zod
npx playwright install chromium
最小構成の初期化コードは次のとおり。ローカルで動かす場合はBrowserbase APIキーは不要だ。
import { Stagehand } from "@browserbasehq/stagehand";
const stagehand = new Stagehand({
env: "LOCAL", // BrowserbaseはBROWSERBASEに変更
verbose: 1,
debugDom: true,
});
await stagehand.init();
const page = stagehand.page;
await page.goto("https://example.com");
await stagehand.close();
環境変数 OPENAI_API_KEY(または ANTHROPIC_API_KEY)を設定しておく必要がある。
export OPENAI_API_KEY="sk-..."
# または
export ANTHROPIC_API_KEY="sk-ant-..."
3つのコアAPI:act / extract / observe
Stagehandの操作はほぼこの3メソッドで完結する。
act() — 自然言語でブラウザ操作
CSSセレクタなしでクリック・入力・スクロールが実行できる。ページのデザイン変更にも自動対応する。
// ログインフォームの操作
await stagehand.act({ action: "click the login button" });
await stagehand.act({ action: "type 'user@example.com' into the email field" });
await stagehand.act({ action: "fill in the password field with 'mypassword'" });
await stagehand.act({ action: "submit the form" });
// 変数を使った動的な操作
const searchTerm = "Stagehand browser automation";
await stagehand.act({
action: `search for "${searchTerm}" in the search box`
});
extract() — Zodスキーマで型安全なデータ抽出
ページからデータを取り出すと同時にZodで型検証をかけられる。スクレイピングの型安全化に強力だ。
import { z } from "zod";
// 商品情報の構造化抽出
const product = await stagehand.extract({
instruction: "extract the product name, price, and availability",
schema: z.object({
name: z.string().describe("product name"),
price: z.number().describe("price in USD"),
inStock: z.boolean().describe("whether the item is in stock"),
variants: z.array(z.string()).describe("available size or color options"),
}),
});
console.log(product.name); // string が保証される
console.log(product.price); // number が保証される
配列抽出も直感的だ。
// 検索結果一覧を全件取得
const results = await stagehand.extract({
instruction: "extract ALL search results with their titles and URLs",
schema: z.array(
z.object({
title: z.string(),
url: z.string().url(),
snippet: z.string().optional(),
})
),
});
observe() — アクション候補の先読み
observe()はページ上で実行可能なアクションを事前に列挙する。UIの状態確認やテスト自動化に有用だ。
// フォーム送信前にアクション候補を確認
const actions = await stagehand.observe({
instruction: "what actions can I take on this page?"
});
console.log(actions);
// [
// { description: "click submit button", selector: "..." },
// { description: "click cancel link", selector: "..." },
// ]
// observe結果をactに直接渡せる
await stagehand.act(actions[0]);
Zodスキーマによる型安全抽出のベストプラクティス
extractをフル活用するには、スキーマのdescribeフィールドが重要だ。LLMへのヒントになるため、フィールド名だけでなく意味を添えると精度が上がる。
// 精度の低い例(describeなし)
const badSchema = z.object({
price: z.number(),
date: z.string(),
});
// 精度の高い例(describeあり)
const goodSchema = z.object({
price: z.number().describe("listing price in USD, excluding tax"),
date: z.string().describe("listing date in ISO 8601 format"),
isNegotiable: z.boolean().describe("true if price is marked as negotiable"),
});
ページによってフィールドが欠損する場合は z.optional() を使う。
const productSchema = z.object({
title: z.string(),
price: z.number(),
rating: z.number().optional().describe("star rating 1-5, may not exist"),
reviewCount: z.number().optional(),
});
Visionモード(スクリーンショット連携)
StagehandはDOMベースの解析とVision(スクリーンショット)モードを使い分けられる。JavaScriptで描画されたキャンバスやSVGベースのUIにはVisionモードが有効だ。
const stagehand = new Stagehand({
env: "LOCAL",
modelName: "claude-3-7-sonnet-20250219", // Vision対応モデルを指定
modelClientOptions: {
apiKey: process.env.ANTHROPIC_API_KEY,
},
enableCaching: false,
});
await stagehand.init();
// Vision経由でキャンバスUI上のボタンをクリック
await stagehand.act({
action: "click the blue 'Export' button in the chart toolbar",
useVision: true, // スクリーンショット解析を強制
});
Browserbaseクラウド統合(並列実行・セッション管理)
Stagehandをローカルで動かす場合はPlaywrightのみ依存するが、本番スケールにはBrowserbaseのマネージドブラウザとの統合が推奨される。
Browserbaseへの接続
const stagehand = new Stagehand({
env: "BROWSERBASE",
apiKey: process.env.BROWSERBASE_API_KEY,
projectId: process.env.BROWSERBASE_PROJECT_ID,
browserbaseSessionCreateParams: {
proxies: true, // 自動プロキシローテーション
stealth: true, // ステルスモード(bot検知回避)
},
});
await stagehand.init();
並列セッションの起動
Browserbaseでは複数セッションを並列で動かせる。プランごとの上限は次のとおりだ。
| プラン | 月額 | 同時セッション数 | ブラウザ時間 |
|---|---|---|---|
| Free | $0 | 3 | 1時間 |
| Developer | $20 | 25 | 100時間 |
| Startup | $99 | 100 | 500時間 |
| Scale | 要相談 | 250+ | カスタム |
// 並列で複数URLをスクレイピング
const urls = ["https://example.com/1", "https://example.com/2", "https://example.com/3"];
const results = await Promise.all(
urls.map(async (url) => {
const s = new Stagehand({ env: "BROWSERBASE", /* ... */ });
await s.init();
await s.page.goto(url);
const data = await s.extract({
instruction: "extract the main article title and author",
schema: z.object({
title: z.string(),
author: z.string().optional(),
}),
});
await s.close();
return data;
})
);
E2Eテスト統合パターン
StagehandはPlaywrightのテスト基盤の上に乗るため、既存のPlaywright Testに追加できる。セレクタに依存しないため、UI変更耐性が高いテストが書ける。
import { test, expect } from "@playwright/test";
import { Stagehand } from "@browserbasehq/stagehand";
test("ログインフローのE2Eテスト", async () => {
const stagehand = new Stagehand({ env: "LOCAL" });
await stagehand.init();
await stagehand.page.goto("https://myapp.example.com/login");
// セレクタ不要でフォーム入力
await stagehand.act({ action: "enter 'testuser@example.com' in the email field" });
await stagehand.act({ action: "enter 'password123' in the password field" });
await stagehand.act({ action: "click the sign in button" });
// ログイン成功を検証
const status = await stagehand.extract({
instruction: "check if the user is logged in successfully",
schema: z.object({
isLoggedIn: z.boolean(),
username: z.string().optional(),
}),
});
expect(status.isLoggedIn).toBe(true);
await stagehand.close();
});
スクレイピング・フォーム自動化の実例
ECサイトの価格監視スクリプトを例に、Stagehandの実用パターンを示す。
import { Stagehand } from "@browserbasehq/stagehand";
import { z } from "zod";
async function monitorProductPrice(productUrl: string) {
const stagehand = new Stagehand({ env: "LOCAL" });
await stagehand.init();
await stagehand.page.goto(productUrl);
// 価格・在庫・評価を一括抽出
const info = await stagehand.extract({
instruction: "extract current price, stock status, and review score",
schema: z.object({
price: z.number().describe("current selling price in JPY"),
originalPrice: z.number().optional().describe("original price before discount"),
inStock: z.boolean(),
reviewScore: z.number().min(0).max(5).optional(),
reviewCount: z.number().optional(),
}),
});
await stagehand.close();
return info;
}
// 複数商品を並列監視
const products = [
"https://shop.example.com/item/1001",
"https://shop.example.com/item/1002",
];
const prices = await Promise.all(products.map(monitorProductPrice));
console.log(prices);
Vercel AI SDK・LangChainとの連携
StagehandはVercel AI SDKの AISdkClient を通じて複数プロバイダーを切り替えられる。また、LangChainのツールとして組み込むことでエージェントワークフローに統合できる。
import { Stagehand } from "@browserbasehq/stagehand";
import { openai } from "@ai-sdk/openai";
// Vercel AI SDK経由でモデルを指定
const stagehand = new Stagehand({
env: "LOCAL",
modelName: "gpt-4o",
modelClientOptions: {
// AISdkClient設定
provider: openai("gpt-4o"),
},
});
await stagehand.init();
// LangChainのtool定義としてact()を包む
import { tool } from "langchain/tools";
const browserActTool = tool(
async ({ instruction }: { instruction: string }) => {
await stagehand.act({ action: instruction });
return `Executed: ${instruction}`;
},
{
name: "browser_action",
description: "Perform an action in the browser using natural language",
schema: z.object({ instruction: z.string() }),
}
);
失敗パターン4選と対処法
実際にStagehandを使う中でハマりやすい4つのパターンをまとめた。
1. act()が誤ったボタンをクリックする
「submit」「send」等の一般的な表現は複数要素にマッチすることがある。observe()で先にアクション候補を確認してから、より具体的な表現でact()を呼ぶとよい。
// 曖昧な指定(失敗しやすい)
await stagehand.act({ action: "click submit" });
// 具体的な指定(安定)
await stagehand.act({ action: "click the blue 'Submit Order' button at the bottom of the checkout form" });
2. extract()でundefinedが返る
対象要素がページにない場合、スキーマが required だと例外が出る。extractの前にobserve()でページ状態を確認するか、スキーマを optional() にする。
3. SPAのナビゲーション後に古いDOMを解析する
Reactなどのルーティング後は waitForLoadState で待機が必要だ。
await stagehand.act({ action: "click the 'Products' navigation item" });
await stagehand.page.waitForLoadState("networkidle");
// ここでextract()を実行
4. Browserbase接続時にセッションが残る
try-finallyで必ず stagehand.close() を呼ぶこと。残留セッションは課金対象になる。
const stagehand = new Stagehand({ env: "BROWSERBASE", /* ... */ });
try {
await stagehand.init();
// ... 処理 ...
} finally {
await stagehand.close(); // 必須
}
まとめ:Stagehandを選ぶべき場面
Stagehandが最適な場面をまとめると次のとおりだ。
- 既存のPlaywright / Next.jsプロジェクトにAIブラウザ操作を追加したい
- TypeScriptのエコシステムで完結させたい
- Zodによる型安全なWebスクレイピングを実装したい
- E2Eテストの保守コストを下げたい(セレクタ不要)
- Browserbaseのマネージドクラウドで並列・スケールさせたい
一方、Pythonベースのコードベースや「ゴールだけ渡して全自動」が必要な場面ではBrowser-useやAIブラウザ比較記事も参照してほしい。
Stagehandは v3.6.4(2026年5月時点)でAPIが安定しており、GitHubのissueレスポンスも活発だ。TypeScript開発者がブラウザAIエージェントに入門するなら、現時点での最短ルートといえる。
この記事を読んで導入イメージが固まってきた方へ
UravationではAIエージェント導入の研修・コンサルを行っています。