From zero to bashing browsers

A ten-minute tour of the CLI, then 12 hands-on scenarios against real public sites — beginner to advanced. Every command is copy-paste runnable.

The guided tour

1

Install in one line

BrowserBash is a natural-language browser automation CLI: you write a plain-English objective, an AI agent drives a real Chrome browser and returns structured results. Install it globally from npm. You need Node 18 or newer and Google Chrome stable on your machine.

npm install -g browserbash-cli
browserbash --version
2

Your first run

Hand browserbash run an objective in plain English and watch it drive the browser. If you want a value back, end the objective with store ... as 'name' and the captured value is returned in the final state. Add --headless to hide the browser window and --timeout to cap the run in seconds.

browserbash run "Open https://news.ycombinator.com and store the top story title as 'top_story'"

# no visible window, give up after 90 seconds
browserbash run "Open https://example.com and store the heading as 'h1'" --headless --timeout 90
3

Pick a brain: Ollama, Anthropic, or OpenRouter

By default BrowserBash thinks with a local Ollama model: free, open source, no API keys, just have Ollama running. Set ANTHROPIC_API_KEY and it uses Claude instead. For everything else there is OpenRouter: grab a key at openrouter.ai/keys, export OPENROUTER_API_KEY, and pass --model openrouter/<vendor>/<model>. One flag swaps between hundreds of models, so you can trade cost for capability without touching your tests.

# Option 1 — local and free (default): just have Ollama running
ollama pull qwen3
browserbash run "Open https://example.com and store the heading as 'h1'"

# Option 2 — Anthropic
export ANTHROPIC_API_KEY=sk-ant-...
browserbash run "Open https://example.com and store the heading as 'h1'"

# Option 3 — OpenRouter: get a key at openrouter.ai/keys
export OPENROUTER_API_KEY=sk-or-...
browserbash run "..." --model openrouter/anthropic/claude-sonnet-4-6
browserbash run "..." --model openrouter/meta-llama/llama-3.3-70b-instruct
4

Agent mode: NDJSON + exit codes

The --agent flag switches stdout to NDJSON: one JSON object per line, stable schema, built for scripts and AI coding tools. Step events stream as the agent works, then a single run_end event carries the verdict, a summary, the final state with your stored values, and the duration. The process exit code is the verdict itself, so callers never have to parse output.

browserbash run "<objective>" --agent --headless --timeout 120

# progress events, one per step
{"type":"step","step":1,"status":"passed","action":"navigate","remark":"..."}

# terminal event
{"type":"run_end","status":"passed|failed|error|timeout","summary":"...","final_state":{...},"duration_ms":...,"test_url":"..."}

# exit codes: 0 passed · 1 failed · 2 error · 3 timeout
5

Markdown test files

Tests are plain Markdown files ending in _test.md: committable, reviewable, and readable by anyone on the team. Each list item is one step, {{placeholders}} work everywhere, and you can splice shared steps in with @import ./helpers/login.md. Run a file with browserbash testmd run; after every run a Result.md report is written next to the test file.

mkdir -p .browserbash/tests
cat > .browserbash/tests/login_test.md <<'EOF'
# Login flow

- Open {{base_url}}/login
- Type {{username}} into the email field
- Type {{password}} into the password field and press Enter
- Verify the dashboard heading is visible
- Store the logged-in user name as 'user_name'
EOF

browserbash testmd run .browserbash/tests/login_test.md
# -> writes .browserbash/tests/Result.md next to the test file
6

Variables & secrets

Any {{key}} placeholder in an objective or test step gets substituted at run time. Pass values inline with --variables, from a file with --variables-file, or drop JSON files in ./.browserbash/variables/ (project) and ~/.browserbash/variables/ (global) to load them automatically. Wrap sensitive values as {"value":"...","secret":true} and they are masked as ***** in all logs and NDJSON output.

browserbash run "Log in to {{base_url}} as {{username}} with password {{password}}" \
  --variables '{"base_url":"https://app.example.com","username":"qa@example.com","password":{"value":"hunter2","secret":true}}'

# or keep them in a file
browserbash run "Log in to {{base_url}} as {{username}} with password {{password}}" \
  --variables-file ./staging.vars.json

# secret values never leak — logs show: Type ***** into the password field
7

Run it in CI

Agent mode and exit codes make CI integration trivial: the job fails exactly when the test fails, with zero output parsing. Run headless, set a timeout, and put your LLM key in repo secrets. Pipe the NDJSON to a file if you want step-by-step logs as a build artifact.

# .github/workflows/e2e.yml
name: e2e
on: [push]
jobs:
  smoke:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 20
      - run: npm install -g browserbash-cli
      - run: browserbash testmd run .browserbash/tests/smoke_test.md --agent --headless --timeout 180
        env:
          ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
# exit code is the verdict: 0 passed · 1 failed · 2 error · 3 timeout

12 scenarios, real sites, real verdicts

Each card is a complete exercise: an objective, the exact command, hints if you're stuck, and what a passing run looks like. The exit code is your scoreboard — 0 means Bo approves.

01beginnerextraction

Hello, Browser

Open https://example.com and store the main heading text as 'h1'

The core loop: objective in, verdict and extracted values out.

browserbash run "Open https://example.com and store the main heading text as 'h1'" --headless
02beginnerextraction

Front Page News

Open https://news.ycombinator.com and store the top story title as 'top_story' and its points as 'points'

Extracting multiple values from one page in a single pass.

browserbash run "Open https://news.ycombinator.com and store the top story title as 'top_story' and its points as 'points'" --headless
03beginnerverification

Quote Quality Control

Open https://quotes.toscrape.com, verify there are exactly 10 quotes on the first page, and store the first quote's author as 'author'

Mixing verification and extraction — your first real test.

browserbash run "Open https://quotes.toscrape.com, verify there are exactly 10 quotes on the first page, and store the first quote's author as 'author'" --headless
04beginnerextraction

Judge a Book by Its Cover

Open https://books.toscrape.com and store the title and price of the first book as 'title' and 'price'

Targeting a specific element among many similar ones.

browserbash run "Open https://books.toscrape.com and store the title and price of the first book as 'title' and 'price'" --headless
05intermediatelogin

Secret Agent Login

Open {{base_url}}/login, log in as {{username}} with password {{password}}, and verify the page says 'You logged into a secure area'

Variables, secret masking, and a real login flow.

browserbash run "Open {{base_url}}/login, log in as {{username}} with password {{password}}, and verify the page says 'You logged into a secure area'" --headless --variables '{"base_url":"https://the-internet.herokuapp.com","username":"tomsmith","password":{"value":"SuperSecretPassword!","secret":true}}'
06intermediatee2e

Supermarket Sweep

Open {{base_url}}, log in as {{username}} with password {{password}}, add the Sauce Labs Backpack to the cart, and store the cart badge count as 'cart_count'

A multi-step shop flow: login, action, then state extraction.

browserbash run "Open {{base_url}}, log in as {{username}} with password {{password}}, add the Sauce Labs Backpack to the cart, and store the cart badge count as 'cart_count'" --headless --variables '{"base_url":"https://www.saucedemo.com","username":"standard_user","password":{"value":"secret_sauce","secret":true}}'
07intermediateforms

Form and Function

Open https://httpbin.org/forms/post, fill the customer name with 'Bo Basher', choose a Large pizza, check the cheese topping, submit the form, and verify the response contains 'Bo Basher'

Form controls: text, radio, checkbox, submit — no selectors needed.

browserbash run "Open https://httpbin.org/forms/post, fill the customer name with 'Bo Basher', choose a Large pizza, check the cheese topping, submit the form, and verify the response contains 'Bo Basher'" --headless
08intermediatesearch

Search Party

Open https://duckduckgo.com, search for 'browser automation', and store the title of the first result as 'first_result'

Handling navigation triggered by a search, plus dynamic content.

browserbash run "Open https://duckduckgo.com, search for 'browser automation', and store the title of the first result as 'first_result'" --headless --timeout 120
09advancede2e

Checkout Champion

Open {{base_url}}, log in as {{username}} with password {{password}}, add the Sauce Labs Backpack and Sauce Labs Bike Light to the cart, go to checkout, fill first name 'Bo', last name 'Basher', postal code '94016', finish the order, and store the confirmation header as 'confirmation'

A full e2e purchase: 10+ steps, one English sentence.

browserbash run "Open {{base_url}}, log in as {{username}} with password {{password}}, add the Sauce Labs Backpack and Sauce Labs Bike Light to the cart, go to checkout, fill first name 'Bo', last name 'Basher', postal code '94016', finish the order, and store the confirmation header as 'confirmation'" --headless --timeout 180 --max-steps 40 --variables '{"base_url":"https://www.saucedemo.com","username":"standard_user","password":{"value":"secret_sauce","secret":true}}'
10advancedinteractions

Dropdown Dexterity

Open {{base_url}}/dropdown, select 'Option 2' from the dropdown, then open {{base_url}}/checkboxes, check both checkboxes, and verify both are checked

Native form widgets across multiple pages in one run.

browserbash run "Open {{base_url}}/dropdown, select 'Option 2' from the dropdown, then open {{base_url}}/checkboxes, check both checkboxes, and verify both are checked" --headless --variables '{"base_url":"https://the-internet.herokuapp.com"}'
11advancedextraction

Price Patrol

Open https://books.toscrape.com, navigate to the Travel category, store the number of books shown as 'count' and the price of the most expensive book on the page as 'max_price'

Navigation plus comparative reasoning over page data.

browserbash run "Open https://books.toscrape.com, navigate to the Travel category, store the number of books shown as 'count' and the price of the most expensive book on the page as 'max_price'" --headless --timeout 120
12advancedtesting

Markdown Test Drive

Write a committable *_test.md file and run it with testmd — your first reviewable test artifact

Tests as reviewable markdown files your whole team can read.

cat > hn_test.md <<'EOF' # Hacker News smoke - Open https://news.ycombinator.com - Verify the page has loaded and stories are visible - Store the title of the first story as 'top_story' - Store the points of the first story as 'top_points' EOF browserbash testmd run ./hn_test.md --headless