browserbase/stagehand

▲ 146 stars today★ 24,626⑂ 1,698

The SDK to extract data and interact with any site on the web. Get started with Claude Code, Codex, Eve, Mastra, and more.

About browserbase/stagehand

browserbase/stagehand is an open-source project on GitHub, mainly written in TypeScript. The SDK to extract data and interact with any site on the web. Get started with Claude Code, Codex, Eve, Mastra, and more. It currently holds 24,626 stars and 1,698 forks with 394 open issues, and was last pushed on 2026-09-20 (repository created 2024-03-24).

Project Overview

Git Homed tracks it on the Today's Trending board, currently at rank #30 with 146 new stars today.

GitHub Repository Details

Repository browserbase/stagehand · default branch main · size 186181 KB · watchers 102 · source: GitHub REST API and repository README

README

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 · Quickstart · ⭐ Star this repo

https://github.com/browserbase/stagehand/blob/HEAD/MIT License https://github.com/browserbase/stagehand/blob/HEAD/Discord Community https://github.com/browserbase/stagehand/blob/HEAD/Ask DeepWiki

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 installed. Full setup: 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 and get 2x faster execution than Playwright cloud equivalent browsers. Configure the Model Gateway so you never wire up a provider, and enable server-side 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, residential proxies, persistent contexts, and session recordings come with it. Get an API key and learn how to configure your browser here.

Give your coding agent a browser

The hosted Browserbase MCP server 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 lets you grab the content of any URL as markdown. 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 Empty directory to working automation in three steps
page · locator Playwright-style browser and element APIs
WebMCP Discover and invoke WebMCP tools exposed by web pages
act · extract · observe Browser actions and data extraction with natural language
Search · Fetch Web search and page content without a browser
Migrate from Playwright Port an existing suite
Integrations CrewAI, Mastra, Deep Agents, Vercel AI SDK, Claude Code, Codex
Python SDK · Go SDK Language-specific guides
Ask DeepWiki Ask questions about this codebase

Join the community

Stagehand is built in the open, and the fastest way to shape it is to show up.

Contributing

We're focused on improving reliability, extensibility, speed, and cost, in that order. Bug fixes and small improvements are the best way to get started. For anything larger, reach out to Miguel Gonzalez or Paul Klein on Discord first so we can make sure it lands.

Stagehand is a TypeScript, Python, and Go monorepo driven by just:

git clone https://github.com/browserbase/stagehand.git
cd stagehand
just install
just generate
just build

export OPENAI_API_KEY="your-openai-api-key" just example act # runs packages/sdk-ts/examples/act.ts

See CONTRIBUTING.md for the full TypeScript, Python, and Go setup.

Acknowledgements

We'd like to thank the following people for their major contributions to Stagehand:

License

Licensed under the MIT License.

Copyright 2026 Browserbase, Inc.

"Stagehand" is a trademark of Browserbase, Inc.

GitHub Stars & Activity

24,626Stars
1,698Forks
394Open issues
TypeScriptLanguage

GitHub Popularity

GitHub stars24,626
Forks1,698
Open issues394
Primary languageTypeScript
LicenseMIT
Stars gained today146
Created2024-03-24
Last pushed2026-09-20

Trending History

Daily boardrank #30 · ▲ 146 stars

Related GitHub Projects

1

anthropics / claude-code

TypeScript★ 146,951⑂ 23,997▲ 415 stars
2

OpenCut-app / OpenCut

TypeScript★ 89,948⑂ 8,888▲ 126 stars
3

ZuodaoTech / everyone-can-use-english

TypeScript★ 38,103⑂ 5,221▲ 436 stars
4

supermemoryai / supermemory

TypeScript★ 30,670⑂ 2,676▲ 392 stars
5

vercel-labs / json-render

TypeScript★ 17,059⑂ 907▲ 585 stars
6

ahmedkhaleel2004 / gitdiagram

TypeScript★ 16,720⑂ 1,275▲ 285 stars
7

Open-Dev-Society / OpenStock

TypeScript★ 16,537⑂ 2,122▲ 752 stars
8

krillinai / OpenCreator

TypeScript★ 11,884⑂ 1,184▲ 317 stars

More Trending Repositories