Standalone Playwright CLI for agent browser automation
Project description
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/brow
brew install brow
pip:
pip install brow-cli
playwright install chromium
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
brow -s <id> eval <code>
Variables available in eval: page, context, browser, state, pages.
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 |
Resource Usage
~150-300MB per Chromium instance. 10 sessions = ~2-3GB.
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file brow_cli-0.1.3.tar.gz.
File metadata
- Download URL: brow_cli-0.1.3.tar.gz
- Upload date:
- Size: 15.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
78279b18f48ee6560c3fbb08300bf76a8c95c177ebbc30bf38f098d66458f173
|
|
| MD5 |
056042d163759f209d66f34bf818339f
|
|
| BLAKE2b-256 |
da95dd31f843d30d4dd6635cfc3c575b4346092b8d69564f5a45ad543c69a588
|
Provenance
The following attestation bundles were made for brow_cli-0.1.3.tar.gz:
Publisher:
publish.yml on detrin/brow
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
brow_cli-0.1.3.tar.gz -
Subject digest:
78279b18f48ee6560c3fbb08300bf76a8c95c177ebbc30bf38f098d66458f173 - Sigstore transparency entry: 1154435007
- Sigstore integration time:
-
Permalink:
detrin/brow@c2a4cacb53ff646cd458cfa681aaa0656f71d6ce -
Branch / Tag:
refs/tags/v0.1.3 - Owner: https://github.com/detrin
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@c2a4cacb53ff646cd458cfa681aaa0656f71d6ce -
Trigger Event:
release
-
Statement type:
File details
Details for the file brow_cli-0.1.3-py3-none-any.whl.
File metadata
- Download URL: brow_cli-0.1.3-py3-none-any.whl
- Upload date:
- Size: 16.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8c055ddfe0f9ee48b11b30f46091dd518719024d4e462c4b6bc83a027b34174b
|
|
| MD5 |
26ee9b192389923c6ebd624028384025
|
|
| BLAKE2b-256 |
90b2706d41624760f6d1bb01bd3e4a53f2873c2425045873f3a7282551dd5c3d
|
Provenance
The following attestation bundles were made for brow_cli-0.1.3-py3-none-any.whl:
Publisher:
publish.yml on detrin/brow
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
brow_cli-0.1.3-py3-none-any.whl -
Subject digest:
8c055ddfe0f9ee48b11b30f46091dd518719024d4e462c4b6bc83a027b34174b - Sigstore transparency entry: 1154435008
- Sigstore integration time:
-
Permalink:
detrin/brow@c2a4cacb53ff646cd458cfa681aaa0656f71d6ce -
Branch / Tag:
refs/tags/v0.1.3 - Owner: https://github.com/detrin
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@c2a4cacb53ff646cd458cfa681aaa0656f71d6ce -
Trigger Event:
release
-
Statement type: