Browser automation CLI for AI agents
Browser automation CLI for AI agents. Fast native Rust CLI.
Installs the native Rust binary:
npm install -g agent-browser
agent-browser install # Download Chrome from Chrome for Testing (first time only)
For projects that want to pin the version in package.json:
npm install agent-browser
agent-browser install
Then use via package.json scripts or by invoking agent-browser directly.
brew install agent-browser
agent-browser install # Download Chrome from Chrome for Testing (first time only)
cargo install agent-browser
agent-browser install # Download Chrome from Chrome for Testing (first time only)
Requires Node.js 24+, pnpm 11+, and Rust.
git clone https://github.com/vercel-labs/agent-browser
cd agent-browser
pnpm install
pnpm build
pnpm build:native # Requires Rust (https://rustup.rs)
pnpm link --global # Makes agent-browser available globally
agent-browser install
On Linux, install system dependencies:
agent-browser install --with-deps
This exits nonzero if the package manager cannot install every required browser library.
Upgrade to the latest version:
agent-browser upgrade
Detects your installation method (npm, Homebrew, or Cargo) and runs the appropriate update command automatically.
agent-browser install to download Chrome from Chrome for Testing (Google's official automation channel). Existing Chrome, Brave, Playwright, and Puppeteer installations are detected automatically. No Playwright or Node.js required for the daemon.agent-browser open example.com
agent-browser snapshot # Get accessibility tree with refs
agent-browser click @e2 # Click by ref from snapshot
agent-browser fill @e3 "[email protected]" # Fill by ref
agent-browser get text @e1 # Get text by ref
agent-browser screenshot page.png
agent-browser close
Clicks fail early when another element covers the target's click point, for example a consent banner or modal. Dismiss or interact with the reported covering element, then take a fresh snapshot before retrying the original ref.
Headless Chromium screenshots hide native scrollbars for consistent image output. Pass --hide-scrollbars false when launching to keep native scrollbars visible.
agent-browser click "#submit"
agent-browser fill "#email" "[email protected]"
agent-browser find role button click --name "Submit"
…
WebMCP tools are ready by default in agent-browser-managed Chrome. Use --no-webmcp to disable the launch features. After a successful navigation, text output advertises when tools are available. JSON output includes data.webmcp with experimental, available, and toolCount.
agent-browser open https://example.com
agent-browser webmcp list
agent-browser webmcp invoke search --params '{"query":"browser agents"}'
agent-browser webmcp invoke slow_tool --params @input.json --detach
agent-browser webmcp result <invocation-id>
agent-browser webmcp cancel <invocation-id>
Use --frame <frame-id> when duplicate tool names are registered in multiple frames. Page-provided descriptions, schemas, annotations, and results are untrusted. Page JavaScript registers readOnlyHint and untrustedContentHint; CDP exposes those claims as readOnly and untrustedContent. The page tool executor owns authorization, and the agent host must confirm consequential actions.
The optional MCP profile keeps these generic tools out of the default profile:
agent-browser mcp --tools core,webmcp
For sites without WebMCP tools, load the generation and validation workflow with agent-browser skills get webmcp-gen.
…
agent-browser read
agent-browser read https://example.com/article
agent-browser read https://example.com/article --filter overview
agent-browser read https://example.com/article --outline
agent-browser read https://docs.example.com --llms index --filter auth
agent-browser read https://docs.example.com --llms full --filter auth
agent-browser read example.com/article --require-md
agent-browser read https://example.com/article --json
read fetches a URL without launching Chrome. Omit the URL to read the rendered DOM of the active tab in the current browser session, including browser auth state and client-side updates. Explicit URL reads send Accept: text/markdown by default, try the same URL with .md appended when the first response is not markdown, walk ancestor paths toward / to find the nearest llms.txt for a matching docs link, print markdown or plain text when available, and fall back to readable text extracted from HTML. --llms and --require-md with no URL use the active tab URL because they depend on HTTP resources. read does not read llms-full.txt unless you ask for it.
Options: --raw prints the response body without HTML extraction, --require-md fails unless the server returns Content-Type: text/markdown, --outline prints a compact heading outline for one page, --llms index prints a compact nearest-ancestor llms.txt link list, --llms full reads the nearest-ancestor llms-full.txt, --filter <text> narrows page sections, llms links/sections, or outline headings, and --timeout <ms> changes the request timeout. Global safeguards such as --allowed-domains, --content-boundaries, and --max-output also apply to read fetches and output.
agent-browser is visible <sel> # Check if visible
agent-browser is enabled <sel> # Check if enabled
agent-browser is checked <sel> # Check if checked
…
Actions: click, fill, check, hover, text
Options: --name <name> (filter role by accessible name), --exact (exact, case-sensitive match; for role it applies to the accessible name, whose default is a case-insensitive substring)
Examples:
agent-browser find role button click --name "Submit"
agent-browser find role heading text --name "Skills" # implicit roles work: <h2>=heading, <ul>=list, top-level <header>=banner
agent-browser find text "Sign In" click
agent-browser find label "Email" fill "[email protected]"
agent-browser find first ".item" click
agent-browser find nth 2 "a" text
agent-browser wait <selector> # Wait for element to be visible
agent-browser wait <ms> # Wait for time (milliseconds)
agent-browser wait --text "Welcome" # Wait for text to appear (substring match)
agent-browser wait --url "**/dash" # Wait for URL pattern
agent-browser wait --load networkidle # Wait for load state
agent-browser wait --fn "window.ready === true" # Wait for JS condition
# Wait for text/element to disappear
agent-browser wait --fn "!document.body.innerText.includes('Loading...')"
agent-browser wait "#spinner" --state hidden
Load states: load, domcontentloaded, networkidle
Execute multiple commands in a single invocation. Commands can be passed as quoted arguments or piped as JSON via stdin. This avoids per-command process startup overhead when running multi-step workflows.
# Argument mode: each quoted argument is a full command
agent-browser batch "open https://example.com" "snapshot -i" "screenshot"
# With --bail to stop on first error
agent-browser batch --bail "open https://example.com" "click @e1" "screenshot"
# Stdin mode: pipe commands as JSON
echo '[
["open", "https://example.com"],
["snapshot", "-i"],
["click", "@e1"],
["screenshot", "result.png"]
]' | agent-browser batch --json
agent-browser clipboard read # Read text from clipboard
agent-browser clipboard write "Hello, World!" # Write text to clipboard
agent-browser clipboard copy # Copy current selection (Ctrl+C)
agent-browser clipboard paste # Paste from clipboard (Ctrl+V)
agent-browser mouse move <x> <y> # Move mouse
agent-browser mouse down [button] # Press button (left/right/middle)
agent-browser mouse up [button] # Release button
agent-browser mouse wheel <dy> [dx] # Scroll wheel
agent-browser set viewport <w> <h> [scale] # Set viewport size (scale for retina, e.g. 2)
agent-browser set device <name> # Emulate device ("iPhone 14")
agent-browser set geo <lat> <lng> # Set geolocation
agent-browser set offline [on|off] # Toggle offline mode
agent-browser set headers <json> # Extra HTTP headers
agent-browser set credentials <u> <p> # HTTP basic auth for current and future tabs
agent-browser set media [dark|light] # Emulate color scheme
set credentials applies HTTP Basic Authentication to the current tab and tabs opened later. set offline off and set headers '{}' restore the default setup for future tabs.
…
…
agent-browser tab # List tabs (shows `tabId` and optional label)
agent-browser tab new [url] # New tab (optionally with URL)
agent-browser tab new --label docs [url] # New tab with a user-assigned label
agent-browser tab <t<N>|label> # Switch to a tab by id or label
agent-browser tab close [t<N>|label] # Close a tab (defaults to active)
agent-browser window new # New window
Tab ids are stable strings of the form t1, t2, t3. They're never reused within a session, so scripts and agents can keep referring to the same tab even after other tabs are opened or closed. Positional integers like tab 2 are not accepted; the t prefix disambiguates handles from indices and mirrors the @e1 convention used for element refs.
You can also assign a memorable label (docs, app, admin) and use it interchangeably with the id. Labels are never auto-generated and never rewritten on navigation — they're yours to name and keep:
agent-browser tab new --label docs https://docs.example.com
agent-browser tab docs # switch to the docs tab
agent-browser snapshot # populate refs for docs
agent-browser click @e3 # click uses docs's refs
agent-browser tab close docs # close by label
Tabs opened through tab new or click --new-tab inherit the session's user agent, headers, HTTP credentials, init scripts, routes, and emulation overrides before their first document loads.
tab list --json also reports each tab's CDP targetId, and target ids are accepted anywhere a tab ref is accepted (tab <targetId>, tab close <targetId>). Unlike t<N> ids, which are per-daemon counters, target ids stay stable across daemon restarts, so they're the right handle for scripts coordinating multiple sessions on one browser.
Switching to a tab discarded by Chrome's Memory Saver reactivates it, since a discarded tab has no renderer to drive. Reactivation reloads the discarded page and resets its unsaved state, and the switch result reports "revived": true. A tab whose page is paused by a JavaScript dialog is alive rather than discarded, so the switch leaves it untouched and reports "dialogBlocked": true; resolve the dialog with dialog accept or `dia
Orphaned headless Chrome Helpers spin at high CPU under agent-browser-chrome temp profile
Unknown commands and unknown subcommands exit 0, so failures read as success to agents branching on exit codes
react tree prints only "✓ Done" without --json, so agents conclude React introspection is unsupported
A user --use-angle silently cancels the --webgpu preset's own --use-angle=vulkan
First screenshot of a session blocks ~9.5s until ~10s after browser launch (GPU-less Linux, Chrome 153)
Silent tab drift on CDP-attached Edge: set viewport returns OK without applying, commands run in an unrelated tab
macOS: headless launches insert a spurious Google Chrome tile in the Dock
--args / AGENT_BROWSER_ARGS splits on every comma, including inside a --flag=a,b value (--window-position never reaches Chrome intact)
iOS default selection includes simulators with unavailable runtimes
Feature Request: Add stealth mode via AGENT_BROWSER_STEALTH environment variable