Plain-English browser tests for AI agents: real Chrome, deterministic verdicts. Free, no API keys.
Copy the AI prompt to install this server into Claude Code, Cursor, or another agent β or use 1-click editor setup below.
π‘ Paste into ~/Library/Application Support/Claude/claude_desktop_config.json (macOS) or %APPDATA%\Claude\claude_desktop_config.json (Windows)
Plain-English browser automation. No selectors. Free and open-source.

You write a plain-English objective. An AI agent drives a real Chrome browser step by step β no selectors, no scripts. Ollama-first, so it runs on free local models with no API keys and nothing ever leaves your machine.
Website Β· Docs / Learn Β· Tutorials Β· npm
Both layers are swappable: the engine interprets the English, the provider runs the browser.
| Engine | What it is | License |
|---|---|---|
stagehand (default) | Stagehand β open-source AI browser automation framework by Browserbase. act/extract/observe/agent primitives, self-healing, supports Anthropic/OpenAI/Google models. | MIT |
builtin | In-repo Anthropic tool-use loop driving Playwright. Used automatically for grids Stagehand can't attach to (LambdaTest, BrowserStack). | Apache-2.0 |
| Provider | Where the browser runs | Engine | Auth |
|---|---|---|---|
local (default) | Chromium/Chrome on this machine | stagehand or builtin | none |
cdp | Any Chrome DevTools Protocol endpoint (your grid, docker, Playwright MCP-managed browser) | stagehand or builtin | none |
browserbase | Browserbase cloud browsers | stagehand only | BROWSERBASE_API_KEY / BROWSERBASE_PROJECT_ID |
lambdatest | LambdaTest / TestMu AI cloud grid | builtin (auto) | LT_USERNAME / LT_ACCESS_KEY |
browserstack | BrowserStack Automate cloud grid | builtin (auto) | BROWSERSTACK_USERNAME / BROWSERSTACK_ACCESS_KEY |
Default model is auto, resolved in this order:
ollama/<OLLAMA_MODEL or first installed model> β free, open source, no keysANTHROPIC_API_KEY set β claude-opus-4-8OPENAI_API_KEY set β openai/gpt-4.1| Backend | Model flag | Needs |
|---|---|---|
| Ollama β local, free, OSS (preferred) | auto or ollama/<model> e.g. ollama/qwen3 | Ollama running; OLLAMA_BASE_URL to override http://localhost:11434/v1, OLLAMA_MODEL to pin auto-detection. Same flag works for any OpenAI-compatible server (vLLM, LM Studio, llama.cpp). |
| Anthropic | claude-opus-4-8 | ANTHROPIC_API_KEY |
| OpenAI / Google | openai/gpt-4.1, google/gemini-2.5-flash | provider key (Stagehand engine) |
| OpenRouter β hundreds of models, one key | openrouter/<vendor>/<model> e.g. openrouter/anthropic/claude-sonnet-4-6, openrouter/meta-llama/llama-3.3-70b-instruct | OPENROUTER_API_KEY (https://openrouter.ai/keys); override endpoint with OPENROUTER_BASE_URL |
| Anthropic-compatible gateway | claude-* + ANTHROPIC_BASE_URL | builtin engine routes through any Anthropic-compatible endpoint (e.g. a LiteLLM proxy fronting local models) |
Stagehand engine (MIT) + local Chromium + Ollama (MIT) β zero cloud cost, no API keys. Tip: small models (β€8B) are flaky on multi-step objectives; Qwen3 / Llama 3.3 70B class works best.
Note: cloud-grid providers (lambdatest, browserstack) use the builtin engine, which speaks the Anthropic API β pair them with ANTHROPIC_API_KEY or an ANTHROPIC_BASE_URL gateway.
Requires Node β₯ 18 and Google Chrome stable (for the local provider).
--agent switches stdout to NDJSON β one JSON object per line, stable schema:
{"type":"step","step":1,"status":"passed","action":"navigate","remark":"...","cached":false}{"type":"run_end","status":"passed|failed|error|timeout","summary":"...","final_state":{...},"duration_ms":...,"provider":"local","cache":"hit|miss|off","tokens_in":...,"tokens_out":...,"test_url":"..."}Exit codes: 0 passed Β· 1 failed Β· 2 error Β· 3 timeout. cached, cache, tokens_in/tokens_out are additive fields (present when relevant), so existing consumers are unaffected.
Full agent integration guide: docs/agents.md.
BrowserBash is a validation layer for AI agents: your coding agent builds a feature, BrowserBash proves it works in a real browser. One line plugs it into any MCP host:
Tools exposed: run_objective (one plain-English objective), run_test_file (a *_test.md), run_suite (a folder, parallel). Each returns the structured verdict JSON: status, summary, final_state, assertions, cost_usd, duration_ms. A failed test is a successful validation, so the tool call succeeds and the agent reads the verdict. No extra dependencies, stdio only, nothing leaves your machine.
Every run is kept in a private on-disk store (~/.browserbash/runs, secrets masked, capped at 200). Two ways to see them:
Local dashboard β free, no account, fully local:
Left panel lists your runs; the main pane shows the verdict, extracted values and the recording β with --record you get a screenshot plus a session video (stagehand engine, video needs ffmpeg, bundled) or a native Playwright trace you can open at trace.playwright.dev (builtin engine). Nothing leaves your machine.
Cloud dashboard β optional, opt-in per run: a hosted dashboard at browserbash.com/dashboard with run history across machines and shareable per-run pages.
Without --upload nothing is sent to the cloud. BrowserBash is free and open source; cloud runs are kept 15 days.
A green run records the actions it took. The next identical run replays them with zero model calls, and the agent only steps back in when the page actually changed. Steady-state suites run at close to script speed and cost.
run_end.cache reports hit / miss / off. On by default; config set cache.enabled false to disable, cache.dir to relocate (default .browserbash/cache, gitignored by init). Secrets never enter the cache: values arrive through the variables channel (Stagehand) or are re-templatized to {{name}} tokens (builtin), and any cached action that types a secret is origin-pinned β replaying it on a different origin fails closed. Builtin journals are also HMAC-signed with a per-machine key (~/.browserbash/cache.key); an edited or foreign journal is ignored and simply re-recorded. CI fleets that want to share committed caches can set the same BROWSERBASH_CACHE_KEY (64 hex chars) on every runner.
run-all)Run a whole folder of *_test.md files at once with memory-aware scheduling:
min(requested, cpus, floor((mem - 2GB) / budget))), so big suites do not thrash the machine. Override with --concurrency, tune the estimate with --memory-budget <mb>. A hard watchdog also kills any test whose whole process tree (Node + Chromium) exceeds --memory-cap <mb> (default 2x the budget, 0 disables); the test is reported as an infra error with a test_kill event, and retried per --retries.Result.md; a failure never leaks state to the next test.--retries <n> retries infra errors only (not real failures), --max-failures <n> stops early, --stagger <ms> softens burst load.--events, add --agent to also stream on stdout), JUnit XML (--junit), and a RunAll-Result.md with a flaky column..browserbash/memory/history.json orders the next run (previously-failed first, then slowest first) and flags flaky tests. --no-memory opts out.--shard 2/4 runs a deterministic slice, computed on sorted discovery order so parallel CI machines agree without coordination.--matrix-viewport 1280x720,390x844 runs every test once per viewport; cells are labeled in events, JUnit and results. Single runs take --viewport WxH too.--budget-usd 2.50 (or --budget-tokens) stops launching new tests once estimated spend crosses the budget; the rest are reported skipped and the suite exits 2. Spend lands in RunAll-Result.md and JUnit <properties>.--notify <url> POSTs the suite verdict when it ends (Slack URLs get Slack formatting).0 all passed Β· 1 any failed Β· 2 infra error or budget stop Β· 3 suite timeout.Plan on a strong model, execute on a cheap one, escalate back automatically after a failed step:
run_end reports tokens_in / tokens_out (builtin engine) so you can see what a run costs, plus a cost_usd estimate from a bundled per-model price table (override at ~/.browserbash/pricing.json; unknown models get no estimate rather than a wrong one). Set persistently with config set routing.executionModel <id>.
*_test.md)Committable, reviewable Markdown tests:
Composition via @import ./helpers/login.md (steps are spliced in place). After every run a Result.md is written next to the test file.
Add version: 2 frontmatter and steps execute ONE AT A TIME against a single browser session, with two deterministic step types that never touch a model:
GET/POST/PUT/DELETE/PATCH url [with body {...}] + Expect status N[, store $.path as 'name']) run as plain HTTP: seed data, then verify through the UI. Stored values feed {{variables}} in later steps.Verify steps compile to real Playwright checks (URL contains, title is/contains, text visible, 'name' button|link|heading visible, element counts, stored equals). A pass means the condition held; a fail comes with expected vs actual evidence in run_end.assertions and the Result.md assertion table. Verify lines outside the grammar still run, agent-judged and flagged judged: true.ANTHROPIC_API_KEY or an ANTHROPIC_BASE_URL gateway).{{key}} placeholders are substituted in objectives and test steps. Load order (highest priority last):
~/.browserbash/variables/*.json./.browserbash/variables/*.json--variables-file <path>--variables '<json>'Mark sensitive values {"value": "...", "secret": true} β they are masked as ***** in all logs and NDJSON output.
browserbash auth)Real suites live behind a login. Log in once, reuse the session everywhere:
Sessions are Playwright storageState files in ~/.browserbash/auth/ (mode 0600, they hold live credentials). Test files can pin their own profile with auth: staging frontmatter. A profile whose saved origins do not cover the target URL prints a warning instead of silently doing nothing.
record captures clicks, typing and navigation (password values never leave the page; the generated step reads Type {{password}} into ...). import translates common Playwright calls deterministically and writes everything it could NOT translate to IMPORT-REPORT.md instead of guessing. Both outputs are starting points to review, not gospel.
browserbash monitor)The same tests double as production checks:
Alerts fire on pass<->fail STATE CHANGES only, both directions, never on every green run. Slack webhook URLs get Slack formatting; any other URL receives the raw JSON payload. With the replay cache warm, a monitor makes zero model calls until the page actually changes.
Precedence: flags > env vars > ~/.browserbash/config.json defaults.
The process exit code is the test verdict β no output parsing needed.
Or use the official GitHub Action (PR verdict comment, artifacts, sharded matrix jobs, budget stop):
Full guide: docs/github-action.md.
Adding a vendor = one file implementing BrowserProvider (connect() returning a Playwright Browser/Page) + one registry line in providers/index.ts.
Apache-2.0
Showcase your server listing on GitHub or your project documentation. Embed this dynamic SVG badge to highlight official listing status and live engagement.
[](https://allmcps.com/mcp/browserbash)<a href="https://allmcps.com/mcp/browserbash"><img src="https://allmcps.com/api/badge/browserbash?style=directory" alt="Browserbash on AllMCPs" /></a>