2026-10-11 16:37 UTC

Browserbase claims Stagehand's browser-adjacent execution and accessibility-tree trimming deliver twice the execution speed of equivalent Playwright cloud browsers and substantially reduce agent token consumption, potentially lowering browser-automation latency and inference costs.

state: corroboratedheat: mediumuncertainty: mediumconvergesscott: mediumbrowser-agents agent-harnesses inference-economicsBrowserbase

What is this?

Stagehand is Browserbase's open-source SDK for AI browser automation, built on Playwright and adding natural-language act/observe/extract primitives; v4 (per Browserbase's changelog and site) claims 2x faster execution than equivalent Playwright cloud browsers and ~80% token efficiency via two mechanisms: running the runtime inside the browser as an extension (cutting per-action round-trip latency, mainly on Browserbase cloud) and hybrid accessibility-tree trimming (shrinking agent context). The snippets confirm the claims are vendor-reported benchmarks and marketing copy; the case's own history adds independent corroboration for the underlying accessibility-tree-over-screenshots pattern from PawBrowse and a computer-use MCP practitioner, though Stagehand-specific magnitudes remain unvalidated. Third-party comparisons (Skyvern, nxcode) position Stagehand as 'Playwright with an AI brain' for selective hybrid automation rather than fully autonomous agents.

Why it matters to Scott

PawBrowse's reproducible benchmark plus a second practitioner's matching report promote the accessibility-tree-over-screenshots mechanism from Browserbase's vendor claim to an independently corroborated pattern — other parties newly arriving where Scott's Text Is the Model's Home Turf, Denoised Semantic DOM, and Signal Extraction canon already argued, a dated-receipts opportunity (including the pixel-fallback caveat for canvas/custom widgets, which his canon also specifies). Practically, Stagehand v4 is now a credible matched-task benchmark candidate for the Dental booking scraper's agent-fallback tier (latency, success rate, token cost), but the 2x/80% magnitudes remain vendor-reported, browser-local execution benefits may not generalize to local Playwright/Patchright runs, and the lab's drift toward direct payload capture keeps the action at a small test rather than a stack change.
ip:concept.text-is-the-models-home-turfip:concept.denoised-semantic-domip:concept.signal-extractionip:framework.context-engineeringdev:project.browserusedev:technology.browser-usedev:concept.agentic-browser-scrapingdev:technology.playwrightradar:saccade-semantic-browser-stateradar:browser-agent-token-efficiency-validationradar:web-draw-text-browser-controlradar:uia-reader-semantic-desktop-perceptionradar:concept.computer-useradar:concept.inference-economicsradar:concept.token-efficiency
queries asked of Scott's wikis
  • accessibility tree vs screenshots agent context token cost
  • Playwright browser agent harness round-trip latency
  • Dental booking scraper benchmark latency success rate cost
  • signal extraction compact page representation context engineering
  • computer-use MCP element table structured representation
  • inference economics browser agent token spend optimization

Measured heat

now 0 pts/hpeak 1 pts/hcomments 0/hpeers p14momentum: steady3 platformsage 552h
points/hour across evidence · reading as of 2026-10-12 02:59:37.977291+11:00 · deterministic, not a model opinion

How the heat travelled

09-18 17:48 (minted)⭐ origin echo-reconstructedThe Stagehand repository provides TypeScript, Python, and Go installation examples, describes hybrid accessibility-tree trimming and browser
Browserbase on github (echo) · attributed from hn.story.49756671 · published time unknown
—
09-18 16:25first on hacker news · published · lag ?We made Playwright 2x faster and 80% more token efficient
wittydeveloper
—
09-27 11:47first on r/ClaudeAI · published · lag ?PawBrowse - I made my agent's browser automation ~2x faster by giving it an element table instead of screenshots (open source, reproducible benchmark)
Far-Round2092
—
09-18 16:25amplified on hacker news 👑hn.story.49756671
wittydeveloper
peak 155 · 41 comments · 95% of case engagement
09-27 11:47amplified on r/ClaudeAIreddit.post.1wri6sn
Far-Round2092
peak 7 · 12 comments · 5% of case engagement
09-18 17:21our radar first saw it · lag ?discovery anchor: hn.story.49756671—
pace: p75 vs 1032 stories at the 336h mark (now 552h old) — ahead of breeze-tts-2-local-release (1.0x), behind rsa-260-factorization (1.0x)

Evidence (3) — ⭐ canonical anchor

sourceobjectauthorscorecomments
🟧 hnWe made Playwright 2x faster and 80% more token efficient
Retrieved article excerpt

Open article · Retrieved 2026-09-18T17:24:00.381580+00:00

[Stagehand](https://stagehand.dev)

**Stagehand is the SDK to extract data and interact with any site on the web.**  
Playwright was built for testing. Stagehand is built for agents, in TypeScript, Python, and Go.

[**Docs**](https://docs.stagehand.dev) ·
[**Quickstart**](https://docs.stagehand.dev/v4/first-steps/quickstart) ·
[**⭐ Star this repo**](https://github.com/browserbase/stagehand/stargazers)

[MIT License](https://github.com/browserbase/stagehand/tree/main?tab=MIT-1-ov-file#MIT-1-ov-file)
[Discord Community](https://discord.gg/stagehand)
[Ask DeepWiki](https://deepwiki.com/browserbase/stagehand)

## AI that uses the browser like humans.

Sign in once, keep the session, and pull structured data out the other side.

```
import { localBrowser, Stagehand } from "@browserbasehq/stagehand";
import { z } from "zod/v4";

// Cookies persist in ./browser-data, so the next run starts already signed in
const browser = await localBrowser.launch({ userDataDir: "./browser-data" });
const stagehand = await Stagehand.create({
  browser,
  model: { modelName: "openai/gpt-5.4-mini", apiKey: process.env.OPENAI_API_KEY },
});

const [page] = await browser.context.pages();
await page.goto("https://app.example.com/login");

// observe() returns real selectors, so credentials never reach the model
const { data: email } = await stagehand.observe("find the email input");
const { data: password } = await stagehand.observe("find the password input");
await page.locator(email[0].selector).fill(process.env.APP_EMAIL!);
await page.locator(password[0].selector).fill(process.env.APP_PASSWORD!);

// act() self-heals when the site redesigns its form
await stagehand.act("click the sign in button");
await stagehand.act("open the billing page");

// extract() returns schema-validated data
const { data } = await stagehand.extract(
  "extract every invoice in the table",
  z.object({
    invoices: z.array(z.object({ number: z.string(), amount: z.number(), paid: z.boolean() })),
  }),
);

console.log(data.invoices);

await stagehand.close();
await browser.close();
```

**Python**

```
import asyncio
import os

from pydantic import BaseModel
from stagehand import Stagehand, local_browser


class Invoice(BaseModel):
    number: str
    amount: float
    paid: bool


class Invoices(BaseModel):
    invoices: list[Invoice]


async def main() -> None:
    # Cookies persist in ./browser-data, so the next run starts already signed in
    browser = await local_browser.launch(user_data_dir="./browser-data")
    try:
        stagehand = await Stagehand.create(
            browser=browser,
            model="openai/gpt-5.4-mini",
            model_api_key=os.environ["OPENAI_API_KEY"],
        )
        try:
            page = (await browser.context.pages())[0]
            await page.goto("https://app.example.com/login")

            # observe() returns real selectors, so credentials never reach the model
            email = await stagehand.observe("find the email input")
            password = await stagehand.observe("find the password input")
            await page.locator(email.data[0].selector).fill(os.environ["APP_EMAIL"])
            await page.locator(password.data[0].selector).fill(os.environ["APP_PASSWORD"])

            # act() self-heals when the site redesigns its form
            await stagehand.act("click the sign in button")
            await stagehand.act("open the billing page")

            # extract() returns schema-validated data
            result = await stagehand.extract(
                "extract every invoice in the table",
                Invoices,
            )
            print(result.data.invoices)
        finally:
            await stagehand.close()
    finally:
        await browser.close()


asyncio.run(main())
```


**Go**

```
package main

import (
	"context"
	"errors"
	"fmt"
	"log"
	"os"

	stagehand "github.com/browserbase/stagehand/packages/sdk-go/v4"
)

type invoice struct {
	Number string  `json:"number"`
	Amount float64 `json:"amount"`
	Paid   bool    `json:"paid"`
}

type invoices struct {
	Invoices []invoice `json:"invoices"`
}

func main() {
	if err := run(context.Background()); err != nil {
		log.Fatal(err)
	}
}

func run(ctx context.Context) (err error) {
	// Cookies persist in ./browser-data, so the next run starts already signed in
	browser, err := stagehand.LaunchLocalBrowser(ctx, &stagehand.LocalBrowserLaunchOptions{
		UserDataDir: "./browser-data",
	})
	if err != nil {
		return err
	}
	defer func() { err = errors.Join(err, browser.Close(ctx)) }()

	modelAPIKey := os.Getenv("OPENAI_API_KEY")
	client, err := stagehand.Create(ctx, stagehand.CreateOptions{
		Browser: browser,
		Model: &stagehand.ModelConfig{
			ModelName: "openai/gpt-5.4-mini",
			APIKey:    &modelAPIKey,
		},
	})
	if err != nil {
		return err
	}
	defer func() { err = errors.Join(err, client.Close(ctx)) }()

	browserContext, err := browser.Context()
	if err != nil {
		return err
	}
	pages, err := browserContext.Pages(ctx)
	if err != nil {
		return err
	}
	page := pages[0]
	if _, err := page.Goto(ctx, "https://app.example.com/login", nil); err != nil {
		return err
	}

	// Observe returns real selectors, so credentials never reach the model
	emailInstruction := "find the email input"
	email, err := client.Observe(ctx, &emailInstruction, nil)
	if err != nil {
		return err
	}
	if err := page.Locator(email.Data[0].Selector).Fill(ctx, os.Getenv("APP_EMAIL")); err != nil {
		return err
	}

	passwordInstruction := "find the password input"
	password, err := client.Observe(ctx, &passwordInstruction, nil)
	if err != nil {
		return err
	}
	if err := page.Locator(password.Data[0].Selector).Fill(ctx, os.Getenv("APP_PASSWORD")); err != nil {
		return err
	}

	// Act self-heals when the site redesigns its form
	if _, err := client.Act(ctx, stagehand.ActInstruction("click the sign in button"), nil); err != nil {
		return err
	}
	if _, err := client.Act(ctx, stagehand.ActInstruction("open the billing page"), nil); err != nil {
		return err
	}

	// Extract returns data decoded into a Go type
	extracted, err := stagehand.Extract[invoices](
		ctx,
		client,
		"extract every invoice in the table",
		nil,
	)
	if err != nil {
		return err
	}
	fmt.Println(extracted.Data.Invoices)

	return nil
}
```

## Install

```
pnpm add @browserbasehq/stagehand 'zod@~4.4.3'
```

**Python**

```
pip install stagehand
```


**Go**

```
go get github.com/browserbase/stagehand/packages/sdk-go/[email protected]
```

Local runs need [Chrome](https://www.google.com/chrome/) installed. Full setup: [Quickstart](https://docs.stagehand.dev/v4/first-steps/quickstart).

## Why Stagehand

|  |  |
| --- | --- |
| **Familiar APIs** | The Playwright-style methods you and your agents already know: `goto`, `click`, `locator`, `screenshot`. |
| **Token efficiency** | Hybrid accessibility-tree trimming gives agents exactly the page context they need and nothing more. |
| **Faster in production** | Stagehand runs as an extension next to the browser, cutting round-trip latency on every action. |
| **Self-healing** | `act`, `observe`, and `extract` refresh how an action happens when the site changes underneath it. |
| **Built for agents** | WebMCP, clipboard support, batch commands, deep locators for nested iframes and closed Shadow DOMs, OTel traces. |
| **Three languages** | One complete browser driver across TypeScript, Python, and Go. |

## Run it on Browserbase

Point the same script at [Browserbase](https://www.browserbase.com) and get 2x faster execution than Playwright cloud equivalent browsers. Configure the [Model Gateway](https://docs.stagehand.dev/v4/configuration/models#model-gateway) so you never wire up a provider, and enable [server-side caching](https://docs.stagehand.dev/v4/best-practices/caching) to cache repeated actions.

```
import { browserbase, Stagehand } from "@browserbasehq/stagehand";

const browser = await browserbase.launch({ apiKey: process.env.BROWSERBASE_API_KEY! });

// No model configuration: the Model Gateway picks the cheapest model for each action
// cache: true: identical calls come back from Browserbase, no tokens spent
const stagehand = await Stagehand.create({ browser, cache: true });
```

**Python**

```
import os

from stagehand import Stagehand, browserbase

browser = await browserbase.launch(api_key=os.environ["BROWSERBASE_API_KEY"])

# No model configuration: the Model Gateway picks the cheapest model for each action
# cache=True: identical calls come back from Browserbase, no tokens spent
stagehand = await Stagehand.create(browser=browser, cache=True)
```


**Go**

```
browser, err := stagehand.LaunchBrowserbase(ctx, stagehand.BrowserbaseLaunchOptions{
	APIKey: os.Getenv("BROWSERBASE_API_KEY"),
})
if err != nil {
	return err
}

// No model configuration: the Model Gateway picks the cheapest model for each action
// CacheEnabled(true): identical calls come back from Browserbase, no tokens spent
cache := stagehand.CacheEnabled(true)
client, err := stagehand.Create(ctx, stagehand.CreateOptions{
	Browser: browser,
	Cache:   &cache,
})
if err != nil {
	return err
}
```

[Verified mode](https://docs.browserbase.com/platform/identity/verified-customization), [residential proxies](https://docs.browserbase.com/platform/identity/proxies), [persistent contexts](https://docs.browserbase.com/platform/browser/core-features/contexts), and [session recordings](https://docs.browserbase.com/platform/browser/observability/session-replay) come with it. [Get an API key](https://www.browserbase.com/overview) and learn how to configure your browser [here](https://docs.stagehand.dev/v4/configuration/browser).

## Give your coding agent a browser

The hosted Browserbase [MCP server](https://docs.stagehand.dev/integrations/mcp/setup) puts `navigate`, `act`, `observe`, and `extract` in any MCP client — no install, no local browser.

```
claude mcp add --transport http browserbase https://mcp.browserbase.com/mcp \
  --header "Authorization: Bearer $BROWSERBASE_API_KEY"
```

**Cursor, Codex, and other MCP clients**

```
{
  "mcpServers": {
    "browserbase": {
      "url": "https://mcp.browserbase.com/mcp",
      "headers": { "Authorization": "Bearer YOUR_BROWSERBASE_API_KEY" }
    }
  }
}
```

## Search and fetch without a browser

[Fetch](https://docs.stagehand.dev/v4/add-ons/fetch) lets you grab the content of any URL as markdown. [Search](https://docs.stagehand.dev/v4/add-ons/search) provides fast, token-efficient web search results.
Both as a lightweight complement to browser sessions.

```
import { browserbase } from "@browserbasehq/stagehand";

const { results } = await browserbase.search({
  apiKey: process.env.BROWSERBASE_API_KEY!,
  query: "browser agent frameworks",
  numResults: 5,
});

const fetched = await browserbase.fetch({
  apiKey: process.env.BROWSERBASE_API_KEY!,
  url: results[0].url,
  format: "markdown",
});

console.log(fetched.content);
```

## Docs and resources

|  |  |
| --- | --- |
| [Quickstart](https://docs.stagehand.dev/v4/first-steps/quickstart) | Empty directory to working automation in three steps |
| [page](https://docs.stagehand.dev/v4/reference/page) · [locator](https://docs.stagehand.dev/v4/reference/locator) | Playwright-style browser and element APIs |
| [WebMCP](https://docs.stagehand.dev/v4/basics/webmcp) | Discover and invoke WebMCP tools exposed by web pages |
| [act](https://docs.stagehand.dev/v4/basics/act) · [extract](https://docs.stagehand.dev/v4/basics/extract) · [observe](https://docs.stagehand.dev/v4/basics/observe) | Browser actions and data extraction with natural language |
| [Search](https://docs.stagehand.dev/v4/add-ons/search) · [Fetch](https://docs.stagehand.dev/v4/add-ons/fetch) | Web search and page content without a browser |
| [Migrate from Playwright](https://docs.stagehand.dev/v4/migrations/playwright) | Port an existing suite |
| [Integrations](https://docs.stagehand.dev/v4/integrations/overview) | CrewAI, Mastra, Deep Agents, Vercel AI SDK, Claude Code, Codex |
| [Python SDK](https://
wittydeveloper15541
🟧 echo.github ⭐The Stagehand repository provides TypeScript, Python, and Go installation examples, describes hybrid accessibility-tree trimming and browserBrowserbase——
🟠 redditPawBrowse - I made my agent's browser automation ~2x faster by giving it an element table instead of screenshots (open source, reproducible benchmark)
ClaudeAI
Far-Round2092712

Interpretation history

Decision trace