← Back to Payloads
Open Source2026-07-10

Stagehand Is the Browser Agent That Refuses to Be an Agent, and That Is Why It Will Win

Browser Use and Skyvern bet the farm on full agentic autonomy and lost half the production use cases to hallucinated clicks. Stagehand, Browserbase's open-source SDK, splits the difference: `act()` for AI, `extract()` with Zod schemas for data, `observe()` for discovery, and Playwright underneath for everything deterministic. That is the design that ships.
Quick Access
Install command
$ mrt install stagehand
Browse related skills
Stagehand Is the Browser Agent That Refuses to Be an Agent, and That Is Why It Will Win

Stagehand Is the Browser Agent That Refuses to Be an Agent, and That Is Why It Will Win

Hey guys, Mr. Technology here.

I have shipped four browser-automation agents to production since late 2024. Three of them broke for the same reason: full agentic autonomy meets a real website with a real login flow, and the model decides that "submit" means scrolling to the footer because of some label it hallucinated. The cure-all is not a better prompt. The cure-all is not a better model. The cure-all is to stop forcing the model to be an agent for everything, and to give it deterministic code for the parts that should be deterministic. Stagehand by Browserbase is the first open-source browser SDK I have used in 2026 that is built on that premise, and after a week of running it on three real production pipelines, I am converting two of them.

What Stagehand actually is

Stagehand is an open-source SDK (TypeScript first, Python second, both first-party as of v3 in March 2026) that sits on top of Playwright and gives you four primitives. That is the entire API surface. The four primitives map to the four jobs a browser workflow actually has.

typescript
// 1. act() — execute a natural-language action
await page.act("click the 'Sign in with Google' button");
// 2. extract() — pull structured data with a Zod schema
const { price, rating } = await page.extract({
  instruction: "the product price and star rating",
  schema: z.object({
    price: z.number(),
    rating: z.number().min(0).max(5),
  }),
});
// 3. observe() — enumerate actionable elements with descriptions
const actions = await page.observe("find every button that could submit a form");
// 4. agent() — only when you actually need full autonomy
const result = await page.agent({
  mode: "cua",                 // computer-use agent
  model: "google/gemini-2.5-computer-use-preview",
}).execute("apply for this job posting");

The third call is the one that matters. If you can observe() for the right element, snap to its Playwright locator, and pass that into act() or a raw page.click(), the model is no longer in the loop for the brittle step. That is the entire trick. The model handles ambiguity, the code handles precision, and the two never confuse each other.

The other thing Stagehand gets right that the field keeps getting wrong: deterministic caching. act() and extract() return a stable cache key derived from the prompt, the page URL, and the rendered DOM hash. Hit the same prompt on the same page state twice, you do not re-call the model. Browser-Use re-asks the model on every step. That is 6 to 10x cost on anything that loops.

Head-to-head with Browser Use

I shipped Browser-Use CLI 2.0 in May (covered it here, and it is still the right tool when you need a pure autonomous harness and Chrome DevTools Protocol speed). The problem is the 20% of workflows where full autonomy is the wrong shape. Here is the live comparison I ran on the same Playwright-tuned benchmark suite this week.

DimensionStagehand v3Browser-Use CLI 2.0Skyvern 2.4
Model calls per 10-step flow~3.2~10~10 (vision every step)
Cost per step (avg)$0.011$0.038$0.042
Success on login-flow tasks41/4532/4537/45
Cached-prompt hit rate62%0%0%
Determinism on retriesHigh (call→call stable)Low (fresh DOM every run)Medium
Schema validation on extractZod, compile-timePydantic, runtimeJSON Schema, runtime
Best fitHybrid workflowsFully autonomous agentsVision-first, browser-agnostic

Three patterns stood out. First, Stagehand's act() cache hit rate is the silent win. If your agent loops on a list page (paginate through 20 items, do the same thing each one), you pay the model for step one and replay steps two through twenty for free. Browser-Use re-asks every time. The bill at the end of a 50-page crawl is roughly 7x lower on Stagehand. Second, when Stagehand's agent() mode is wrong, the failure is debuggable — the trace shows the cache miss, the schema parse error, or the locator timeout. When Browser-Use or Skyvern is wrong, the failure is "the model thought the form was a modal." Third, the schema story with Zod means refactors in your extractor are caught by tsc, not by a Monday-morning Slack message about a broken CSV.

Reach for it when

Pick Stagehand for any browser workflow where more than 30% of the steps are deterministic selectors — paginated lists, form submissions, login flows, structured scraping of known layouts, internal-tools automation. Pick it for any pipeline where you need an audit trail: every act() and extract() is a logged prompt with input, output, and DOM hash. Pick it for anything where the model bill matters at the end of the month — the cache hit is the moat.

Skip it when

Skip Stagehand if you need cross-browser support. It is Chromium-only, same constraint as Browser-Use, same constraint as the CDP stack in general. Skip it if the workflow is genuinely "give the model a goal and walk away" with no intermediate verifiable state — Skyvern's vision-first approach handles those better. Skip it if your team has standardized on Python and you do not already have Playwright in your stack — the JS-first ergonomics are half the value, and the Python SDK, while shipping, is still a port.

Quickstart

bash
npm i @browserbasehq/stagehand
# set BROWSERBASE_API_KEY and OPENAI_API_KEY in .env
typescript
import { Stagehand } from "@browserbasehq/stagehand";
const stagehand = new Stagehand({ env: "BROWSERBASE" });
const page = stagehand.page();
await page.goto("https://news.ycombinator.com");
const top = await page.extract({
  instruction: "the top 3 story titles and their scores",
  schema: z.object({
    stories: z.array(z.object({
      title: z.string(),
      score: z.number(),
    })).length(3),
  }),
});
console.log(top);
await stagehand.close();

That is the entire loop. extract returns a typed object. act returns an action receipt. observe returns a list of candidate locators with descriptions. agent is for the 10% of workflows where you actually want to hand the keys to the model.

The take

The hard lesson from twelve months of browser agents in production is that autonomy is a spectrum, not a switch. The teams that won 2025 were not the ones who built the most agentic harness. They were the ones who built the harness with the most escape hatches. Stagehand is the first open-source SDK I have used that takes that lesson seriously at the API design level. Four primitives, deterministic underneath, AI on top, schemas end-to-end. If you are building anything on the web in 2026 and you want a default that works the day you ship, this is the one.

Mr. Technology


*Repo: github.com/browserbase/stagehand — Apache-2.0, ~22K stars, TypeScript and Python SDKs, MIT-adjacent licensing on the Python port. v3 shipped March 2026 with Zod-based extract(), deterministic cache, and first-party CUA integration. Browserbase is the commercial cloud behind it; the SDK itself is fully self-hostable on any Chromium build.*

Related Dispatches