| name | browseruse |
| description | Launch, connect, and control Chrome browsers via CDP. Manages persistent browser profiles so login state survives across sessions. Run JS snippets through the `browseruse` CLI — it auto-spawns a Bun HTTP server holding a fully-typed CDP Session, and can launch/manage Chrome instances with remote debugging. |
browseruse
Full CDP SDK (56 domains, 652 typed methods) plus browser lifecycle management. Unlike raw CDP tools, browseruse can launch Chrome with persistent profiles — login state, cookies, and extensions survive across restarts.
Quick start
browseruse launch
browseruse connect
browseruse 'const t = await listPageTargets(); await session.use(t[0].targetId)'
browseruse 'await session.Page.navigate({url:"https://example.com"})'
browseruse screenshot --output /tmp/page.png
CLI commands
| Command | Behavior |
|---|
browseruse '<js>' | Auto-start REPL, eval JS, print result. |
browseruse eval '<js>' | Same as above, explicit subcommand. |
browseruse launch [opts] | Launch managed Chrome with persistent profile. |
browseruse browsers | List detected browsers (JSON). |
browseruse tabs | List page targets (JSON, requires connection). |
browseruse connect [opts] | Connect session (auto-launches if no browser found). |
browseruse screenshot [--output f] | Capture screenshot to file. |
browseruse --status | Health JSON or exit 1 if REPL down. |
browseruse --start | Start REPL server explicitly. |
browseruse --stop | Stop REPL + managed browser. |
browseruse --restart | Restart REPL fresh. |
browseruse --logs | Tail server log. |
Launch options
browseruse launch --profile work
browseruse launch --headless
browseruse launch --port 9222
Connect options
browseruse connect
browseruse connect --no-auto-launch
browseruse connect --profile-dir <path>
browseruse connect --ws-url ws://...
browseruse connect --timeout 30000
Profiles
Profiles live at ~/.browseruse/profiles/<name>/. The default profile is default.
- Each profile is a full Chrome user-data-dir
- Cookies, localStorage, extensions, bookmarks persist
- Multiple named profiles for different contexts (personal, work, etc.)
- Launch with
--profile <name> to use a specific profile
API surface inside eval snippets
Pre-loaded globals (no imports needed):
session — persistent Session with all 56 CDP domains: session.Page, session.DOM, session.Runtime, session.Network, …
listPageTargets() — list page targets (filtered, no chrome:// internals)
detectBrowsers() — scan for running Chromium browsers
launchBrowser(opts?) — launch a new managed browser
getManagedBrowser() — check managed browser status
closeManagedBrowser() — stop managed browser
resolveWsUrl(opts) — resolve WebSocket URL from options
CDP — generated namespaces for type reference
Connecting and targeting
browseruse 'await session.connect()'
browseruse 'const t = await listPageTargets(); await session.use(t[0].targetId)'
browseruse 'await session.Page.navigate({url:"https://example.com"})'
Common CDP patterns
Open a URL in a NEW tab (use Target.createTarget, not Page.navigate):
const {targetId} = await session.Target.createTarget({url: 'https://example.com'})
await session.use(targetId)
await session.Page.navigate({url: 'https://example.com'})
Navigate the current tab (replaces current page):
await session.Page.navigate({url: 'https://example.com'})
Close a tab:
await session.Target.closeTarget({targetId: 'TARGET_ID'})
Switch between tabs:
const tabs = await listPageTargets()
await session.use(tabs[0].targetId)
CDP method calls
Every method takes one object argument matching CDP wire params, returns the typed result:
await session.Page.navigate({ url: 'https://example.com' })
await session.Page.captureScreenshot({ format: 'png' })
const { root } = await session.DOM.getDocument()
const { nodeId } = await session.DOM.querySelector({ nodeId: root.nodeId, selector: 'h1' })
await session.Runtime.evaluate({ expression: 'document.title', returnByValue: true })
Events
const off = session.onEvent((method, params, sessionId) => { ... })
await session.Network.enable()
const ev = await session.waitFor('Page.frameNavigated', p => p.frame.url.includes('example.com'), 10000)
Multi-line (stdin/heredoc)
Multi-statement snippets require explicit return:
browseruse <<'EOF'
const tabs = await listPageTargets();
await session.use(tabs[0].targetId);
await session.Page.navigate({url:"https://example.com"});
return (await session.Runtime.evaluate({expression:"document.title",returnByValue:true})).result.value;
EOF
Output format
| Result type | stdout |
|---|
| string | bare text (no JSON quotes) |
| number / boolean | 42, true |
| object / array (non-empty) | compact JSON |
undefined / null / "" / {} / [] | empty (no output) |
Errors go to stderr, exit code 1.
Env vars
BROWSERUSE_PORT — REPL port (default: 9876)
BROWSERUSE_LOG — log file (default: /tmp/browseruse.log)