AIエージェント開発

Stagehand完全ガイド2026|TypeScriptブラウザエージェント

この記事の結論

BrowserbaseのTypeScript製ブラウザAIエージェントFW「Stagehand」を徹底解説。act/extract/observe API、Zod型安全抽出、Browserbaseクラウド統合まで実例コード付き。

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-useAIブラウザ比較記事も参照してほしい。

Stagehandは v3.6.4(2026年5月時点)でAPIが安定しており、GitHubのissueレスポンスも活発だ。TypeScript開発者がブラウザAIエージェントに入門するなら、現時点での最短ルートといえる。

この記事を読んで導入イメージが固まってきた方へ

UravationではAIエージェント導入の研修・コンサルを行っています。

Need help moving from reading to rollout?

この記事を読んで導入イメージが固まってきた方へ

Uravationでは、AIエージェントの要件整理、PoC設計、社内導入、研修まで一気通貫で支援しています。

この記事をシェア

X Facebook LINE

※ 本記事の情報は2026年5月時点のものです。サービスの料金・仕様は変更される可能性があります。最新情報は各サービスの公式サイトをご確認ください。

関連記事