brow - agentic browsing
Standalone Playwright CLI for agent browser automation. Launches a real Chromium instance with an agent-friendly API - structured commands for common actions, eval escape hatch for full power.
Install
Homebrew:
brew tap detrin/tap
brew install brow
pip:
pip install brow-cli
Then install Chromium once (either method above):
brow setup # ~150MB, one-time
Update patchright and its matching Chromium build later with:
brow setup --upgrade
Agent skill:
npx -y skills add detrin/brow
Example: Find Bars Near Times Square with Google Maps
A real use case: use your Google account to search Maps in a city you've never visited, and extract structured results.
Step 1: Log into Google (once)
Open a headed browser with a persistent profile and sign in manually:
brow session new --profile personal --headed
brow navigate -s 1 "https://accounts.google.com"
# Sign in manually in the browser window...
brow session delete 1
Your login is saved in ~/.brow/profiles/personal/ -you won't need to sign in again.
Step 2: Ask Claude Code to search
Paste this into Claude Code:
Open a brow session with my personal profile, go to Google Maps, and search for bars near Times Square in New York. Return the names, Google Maps URLs, ratings, and number of reviews in a markdown table.
Claude Code runs:
brow session new --profile personal --headed # → 1 (already logged in)
brow navigate -s 1 "https://www.google.com/maps/search/bars+near+Times+Square+New+York"
brow screenshot -s 1
brow eval -s 1 "
results = await page.evaluate('''() => {
const items = document.querySelectorAll('div.Nv2PK');
return Array.from(items).slice(0, 8).map(el => {
const name = el.querySelector('.fontHeadlineSmall, .qBF1Pd');
const rating = el.querySelector('.MW4etd');
const reviews = el.querySelector('.UY7F9');
const link = el.querySelector('a[href*=\"/maps/place\"]');
return {
name: name?.innerText || '',
rating: rating?.innerText || '',
reviews: reviews?.innerText.replace(/[()]/g, '') || '',
url: link?.href || ''
};
});
}''')
import json
result = json.dumps(results, indent=2)
"
brow session delete 1
Result
| Bar | Rating | Reviews | Link |
|---|---|---|---|
| The Riff Raff Club | 4.4 | 60 | Maps |
| Ascent Lounge | 4.4 | 646 | Maps |
| Jimmy's Corner | 4.6 | 2,195 | Maps |
| O'Donoghue's Times Square | 4.4 | 2,633 | Maps |
| The Dickens | 4.8 | 2,128 | Maps |
| The Woo Woo | 4.8 | 1,871 | Maps |
Because the google profile persists your login, you get personalized results -no cookie banners, no sign-in walls, just data.
Commands
Daemon
brow daemon start [--port 19987]
brow daemon stop
brow daemon status
Sessions
brow session new [--profile <name>] [--headed]
brow session list
brow session delete <id>
Navigation
brow -s <id> navigate <url>
brow -s <id> wait <selector>
brow -s <id> wait --load
Observation
brow -s <id> snapshot [--search <regex>] [--locator <selector>]
brow -s <id> screenshot [--full] [--path <file>]
brow -s <id> html [--locator <selector>] [--search <regex>]
brow -s <id> logs [--search <regex>] [--count <n>]
brow -s <id> url
Interaction
brow -s <id> click <selector>
brow -s <id> fill <selector> <value>
brow -s <id> type <text>
brow -s <id> key <key> # Enter, Tab, Meta+a
brow -s <id> hover <selector>
brow -s <id> scroll <pixels>
brow -s <id> scroll-to <selector>
brow -s <id> drag <from> <to>
brow -s <id> upload <selector> <filepath>
Pages
brow -s <id> page list
brow -s <id> page new [url]
brow -s <id> page close [index]
brow -s <id> page switch <index>
Profiles & State
brow profile list
brow profile delete <name>
brow state save <name> -s <id>
brow state restore <name> -s <id>
brow state list
Eval & Run
brow eval -s <id> <code> # inline, one-off
brow run -s <id> workflow.py --arg k=v # reusable, from a file
Variables available: page, context, browser, state, pages, plus args (from --arg) for run.
Selectors
Playwright selector syntax:
- CSS:
button.submit,#login - Text:
text=Login - Role:
role=button[name="Save"] - XPath:
xpath=//div
Architecture
┌─────────────────────────────────────────────────────────────────┐
│ Agent (Claude Code, script, etc.) │
│ │
│ brow session new --headed ← start browser │
│ brow navigate -s 1 "https://..." ← go to page │
│ brow snapshot -s 1 ← read page (a11y tree) │
│ brow click -s 1 "text=Login" ← interact │
│ brow fill -s 1 "#email" "me@..." ← fill form │
│ brow screenshot -s 1 ← capture screen │
│ brow eval -s 1 "await page..." ← escape hatch │
│ brow session delete 1 ← cleanup │
└──────────────┬──────────────────────────────────────────────────┘
│ HTTP (localhost:19987)
▼
┌──────────────────────────────────────┐
│ brow daemon (FastAPI + uvicorn) │
│ │
│ ┌──────────┐ ┌──────────────────┐ │
│ │ Session 1 │ │ ProfileManager │ │
│ │ (browser) │ │ ~/.brow/profiles │ │
│ ├──────────┤ └──────────────────┘ │
│ │ Session 2 │ │
│ │ (browser) │ ┌──────────────────┐ │
│ └──────────┘ │ StateManager │ │
│ │ ~/.brow/states │ │
│ └──────────────────┘ │
└──────────────┬───────────────────────┘
│ CDP (Chrome DevTools Protocol)
▼
┌──────────────────────────────────────┐
│ Chromium (via Playwright) │
│ │
│ ┌────────┐ ┌────────┐ ┌────────┐ │
│ │ Page 1 │ │ Page 2 │ │ Page 3 │ │
│ └────────┘ └────────┘ └────────┘ │
└──────────────────────────────────────┘
- Daemon auto-starts on first
browcommand - Persistent Chromium profiles for login session survival
- One browser per session, full isolation
- Headless by default,
--headedto watch
Configuration
| Variable | Default | Description |
|---|---|---|
BROW_HOME |
~/.brow |
Data directory |
BROW_PORT |
19987 |
Daemon port |
BROW_MAX_SESSIONS |
10 |
Max concurrent sessions |
Benchmarks
16 fixture tasks, Claude Sonnet via AWS Bedrock, 1 run each. Compared against playwright-cli, MCP Playwright, agent-browser, and browser-use.
| Metric | brow | agent-browser | browser-use | playwright-cli | MCP Playwright |
|---|---|---|---|---|---|
| Success rate (16 fixture) | 88% (14/16) | 63% (10/16) | 63% (10/16) | 50% (8/16) | 44% (7/16) |
| Success rate (22 total) | 82% (18/22) | 64% (14/22) | 64% (14/22) | 55% (12/22) | 36% (8/22) |
| Avg tokens/task (16 fixture) | 68K | 73K | 75K | 113K | 118K |
| Avg tokens/task (22 total) | 88K | 69K | 81K | 96K | 132K |
| Avg tool calls | 9.6 | 11.2 | 5.8 | 9.6 | 11.6 |
| Avg wall-clock | 41s | 36s | 73s | 44s | 50s |
| Est. cost/task | $0.22 | $0.23 | $0.27 | $0.35 | $0.37 |
brow leads on success rate across both suites. On token efficiency, brow leads the 16-task fixture suite (68K avg); agent-browser leads across all 22 tasks (69K avg) — brow's 22-task average is inflated by a single live task where the agent didn't use snapshot filtering. agent-browser wins on wall-clock speed. browser-use runs its own agent loop — included for completeness.
Full results and per-task breakdown →
Resource Usage
~150-300MB per Chromium instance. 10 sessions = ~2-3GB.
License
Elastic License 2.0 (releases <=1.2.0 remain MIT-licensed).
Metadata
Release files for brow-cli 1.3.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| brow_cli-1.3.0.tar.gz | 38.7 kB | With provenance | Details for brow_cli-1.3.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| brow_cli-1.3.0-py3-none-any.whl | Python 3 | none | any | Details for brow_cli-1.3.0-py3-none-any.whl |
Total release size: 69.9 kB
Release files / brow_cli-1.3.0.tar.gz
| Download URL | brow_cli-1.3.0.tar.gz |
|---|---|
| Size | 38.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
dff9a948e81f53969d0d72ed4ae6a2f68c6ade6974265203a0110444fbf10169
|
|
BLAKE2b-256 checksum How to use checksums |
28bd331feeb82bb5c30b18b9afffa2b32f3ebc303a4b39f7d66a95bee1e92314
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 15, 2026.
Transparency logRelease files / brow_cli-1.3.0-py3-none-any.whl
| Download URL | brow_cli-1.3.0-py3-none-any.whl |
|---|---|
| Size | 31.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
bf2615069e7c7e077770c8686e1ff11be78fd58a47ef6234fa00d0b3a3fa8f77
|
|
BLAKE2b-256 checksum How to use checksums |
0eefb2285eed874ccf75b26614a57f473fbfb34bff37128225c808af6d6fb4e7
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 15, 2026.
Transparency logSecurity for brow-cli 1.3.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for brow_cli-1.3.0.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 15, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.