File: README.md
agent-browser
Browser automation CLI for AI agents. Fast native Rust CLI.
Installation
Global Installation (recommended)
Installs the native Rust binary:
npm install agent-browser
agent-browser install # Download Chrome from Chrome for Testing (first time only)Project Installation (local dependency)
For projects that want to pin the version in package.json:
npm install agent-browser
agent-browser installThen use via package.json scripts or by invoking agent-browser directly.
Homebrew (macOS)
brew install agent-browser
agent-browser install # Download Chrome from Chrome for Testing (first time only)Cargo (Rust)
cargo install agent-browser
agent-browser install # Download Chrome from Chrome for Testing (first time only)From Source
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 installLinux Dependencies
On Linux, install system dependencies:
agent-browser install --with-depsThis exits nonzero if the package manager cannot install every required browser library.
Updating
Upgrade to the latest version:
agent-browser upgradeDetects your installation method (npm, Homebrew, or Cargo) and runs the appropriate update command automatically.
Requirements
- Chrome - Run
agent-browser installto 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. - Node.js 24+ and pnpm 11+ - Only needed when building from source.
- Rust - Only needed when building from source (see From Source above).
Quick Start
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 closeClicks 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.
Traditional Selectors (also supported)
agent-browser click "#submit"
agent-browser fill "#email" "[email protected]"
agent-browser find role button click --name "Submit"Commands
Core Commands
/* Detailed source-code truncated for AI context efficiency. */Get Info
agent-browser get text <sel> # Get text content
agent-browser get html <sel> # Get innerHTML
agent-browser get value <sel> # Get input value
agent-browser get attr <sel> <attr> # Get attribute
agent-browser get title # Get page title
agent-browser get url # Get current URL
agent-browser get cdp-url # Get CDP WebSocket URL (for DevTools, debugging)
agent-browser get count <sel> # Count matching elements
agent-browser get box <sel> # Get bounding box
agent-browser get styles <sel> # Get computed stylesRead Agent-Friendly Text
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 --jsonread 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.
Check State
agent-browser is visible <sel> # Check if visible
agent-browser is enabled <sel> # Check if enabled
agent-browser is checked <sel> # Check if checkedFind Elements (Semantic Locators)
agent-browser find role <role> <action> [value] # By ARIA role
agent-browser find text <text> <action> [value] # By text content
agent-browser find label <label> <action> [value] # By label
agent-browser find placeholder <action> [value] # By placeholder
agent-browser find alt <text> <action> [value] # By alt text
agent-browser find title <text> <action> [value] # By title attr
agent-browser find testid <action> [value] # By data-testid
agent-browser find first <sel> <action> [value] # First match
agent-browser find last <sel> <action> [value] # Last match
agent-browser find nth <n> <sel> <action> [value] # Nth matchActions: 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, =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" textWait
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 hiddenLoad states: load, domcontentloaded, networkidle
Batch Execution
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 --jsonClipboard
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)Mouse Control
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 wheelBrowser Settings
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 # HTTP basic auth
agent-browser set media [dark|light] # Emulate color schemeCookies & Storage
agent-browser cookies # Get all cookies
agent-browser cookies set <name> <val> # Set cookie
agent-browser cookies set --curl <file> # Import cookies from a Copy-as-cURL dump,
# JSON array, or bare Cookie header (auto-detected)
agent-browser cookies clear # Clear cookies
agent-browser storage local # Get all localStorage
agent-browser storage local <key> # Get specific key
agent-browser storage local set <k> <v> # Set value
agent-browser storage local clear # Clear all
agent-browser storage session # Same for sessionStorageNetwork
agent-browser network route # Intercept requests
agent-browser network route --abort # Block requests
agent-browser network route --body <json> # Mock response
agent-browser network route '*' --abort --resource-type script # Block scripts only
agent-browser network unroute [url] # Remove routes
agent-browser network requests # View tracked requests
agent-browser network requests --filter api # Filter requests
agent-browser network requests --type xhr,fetch # Filter by resource type
agent-browser network requests --method POST # Filter by HTTP method
agent-browser network requests --status 2xx # Filter by status (200, 2xx, 400-499)
agent-browser network request <requestId> # View full request/response detail
agent-browser network har start # Start HAR recording (embeds text response bodies)
agent-browser network har start --content all # Embed all response bodies (binary as base64)
agent-browser network har start --content none # Metadata only, no bodies
agent-browser network har stop [output.har] # Stop and save HAR (temp path if omitted)Tabs & Windows
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 windowTab 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 labeltab 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 dialog dismiss before interacting. Closing the active tab onto a discarded successor revives it the same way and reports "activeTabRevived": true.
Frames
agent-browser frame <sel> # Switch to iframe
agent-browser frame main # Back to main frameDialogs
agent-browser dialog accept [text] # Accept (with optional prompt text)
agent-browser dialog dismiss # Dismiss
agent-browser dialog status # Check if a dialog is currently openBy default, alert and beforeunload dialogs are automatically accepted so they never block the agent. confirm and prompt dialogs still require explicit handling. Use --no-auto-dialog (or AGENT_BROWSER_NO_AUTO_DIALOG=1) to disable automatic handling.
When a JavaScript dialog is pending, all command responses include a warning field with the dialog type and message.
Diff
agent-browser diff snapshot # Compare current vs last snapshot
agent-browser diff snapshot --baseline before.txt # Compare current vs saved snapshot file
agent-browser diff snapshot --selector "#main" --compact # Scoped snapshot diff
agent-browser diff screenshot --baseline before.png # Visual pixel diff against baseline
agent-browser diff screenshot --baseline b.png -o d.png # Save diff image to custom path
agent-browser diff screenshot --baseline b.png -t 0.2 # Adjust color threshold (0-1)
agent-browser diff url https://v1.com https://v2.com # Compare two URLs (snapshot diff)
agent-browser diff url https://v1.com https://v2.com --screenshot # Also visual diff
agent-browser diff url https://v1.com https://v2.com --wait-until networkidle # Custom wait strategy
agent-browser diff url https://v1.com https://v2.com --selector "#main" # Scope to elementDebug
agent-browser trace start # Start recording trace
agent-browser trace stop [path] # Stop and save trace
agent-browser profiler start # Start Chrome DevTools profiling
agent-browser profiler stop [path] # Stop and save profile (.json)
agent-browser console # View console messages (log, error, warn, info)
agent-browser console --json # JSON output with raw CDP args for programmatic access
agent-browser console --clear # Clear console
agent-browser errors # View page errors (uncaught JavaScript exceptions)
agent-browser errors --clear # Clear errors
agent-browser highlight <sel> # Highlight element
agent-browser inspect # Open Chrome DevTools for the active page
agent-browser state save # Save auth state
agent-browser state load # Load auth state
agent-browser state list # List saved state files
agent-browser state show <file> # Show state summary
agent-browser state rename <old> <new> # Rename state file
agent-browser state clear [name] # Clear states for session
agent-browser state clear --all # Clear all saved states
agent-browser state clean --older-than <days> # Delete old statesNavigation
agent-browser back # Go back
agent-browser forward # Go forward
agent-browser reload # Reload page
agent-browser pushstate # SPA client-side nav; auto-detects window.next.router.push,
# falls back to history.pushState + popstatePre-navigation setup
Some flows (SSR debug, auth cookies for protected origins, init scripts) need state set up before the first navigation. Use open with no URL to launch the browser, then stage cookies / routes / init scripts, then navigate. batch sends it all in one CLI call:
agent-browser batch \
'["open"]' \
'["network","route","*","--abort","--resource-type","script"]' \
'["cookies","set","--curl","cookies.curl","--domain","localhost"]' \
'["navigate","http://localhost:3000/target"]'Without batch the same sequence is three commands that all reuse the same daemon (fast, but not one turn).
React / Web Vitals
Agent-browser ships with first-class React introspection and universal Web Vitals metrics. The React commands need the React DevTools hook installed at launch; Web Vitals and pushstate are framework-agnostic.
agent-browser open --enable react-devtools # Launch with React hook installed
agent-browser react tree # Full component tree
agent-browser react inspect <fiberId> # props, hooks, state, source
agent-browser react renders start # Begin fiber render recording
agent-browser react renders stop [--json] # Stop and print profile (--json for raw data)
agent-browser react suspense [--only-dynamic] [--json] # Suspense boundaries + classifier
# --only-dynamic hides the "static" list
agent-browser vitals [url] [--json] # LCP/CLS/TTFB/FCP/INP + hydration summaryEach react ... subcommand requires --enable react-devtools to have been passed at launch (the React DevTools installHook.js is embedded in the binary). Without it the commands error with `React DevTools hook not installed
- relaunch with --enable react-devtools`.
Works on any React app — Next.js, Remix, Vite+React, CRA, TanStack Start, React Native Web, etc. vitals and pushstate are framework-agnostic. vitals prints a summary by default; pass --json for the full structured payload.
Accessibility audits
Run an axe-core accessibility audit against the current page or a URL. The axe-core engine is embedded in the binary, so it works offline and under strict CSP. It runs private partial audits across the page's frame tree and merges serialized results without page messaging, so page-provided window.axe values remain intact and iframe violations retain their frame selector paths. Accessibility audits require a CDP browser and are not available with Safari or iOS WebDriver sessions.
agent-browser a11y # Audit the current page
agent-browser a11y https://example.com # Navigate, then audit
agent-browser a11y --tags wcag2a,wcag2aa # Only rules with these axe tags
agent-browser a11y --selector "#main" # Scope the audit to a subtree
agent-browser a11y example.com --json # Full structured resultsThe default output lists each violation with its impact, rule id, fix guidance URL, and the CSS selectors of failing nodes:
url: https://example.com/
axe-core: 4.12.1 violations: 2 incomplete: 0 passes: 24
[critical] image-alt: Images must have alternative text (3 nodes)
https://dequeuniversity.com/rules/axe/4.12/image-alt
- img.hero
- #logo > img
- footer img
[serious] color-contrast: Elements must meet minimum color contrast ratio thresholds (1 node)
https://dequeuniversity.com/rules/axe/4.12/color-contrast
- .nav a.muted--json returns the same data structured for automation (counts, violations, incomplete, each violation's nodes with target, html, and failureSummary). Each target preserves axe's selector path arrays, including nested arrays for shadow DOM boundaries. Rules that axe could not evaluate automatically are reported under incomplete for manual review.
Init scripts
agent-browser open --init-script # Register page init script before first navigation
# (repeatable; also AGENT_BROWSER_INIT_SCRIPTS env)
agent-browser addinitscript <js> # Register at runtime (returns identifier)
agent-browser removeinitscript # Remove a previously registered init scriptSetup
agent-browser install # Download Chrome from Chrome for Testing (Google's official automation channel)
agent-browser install --with-deps # Also install system deps (Linux)
agent-browser upgrade # Upgrade agent-browser to the latest version
agent-browser doctor # Diagnose the install and auto-clean stale daemon files
agent-browser doctor --fix # Also run destructive repairs (reinstall Chrome, purge old state, ...)
agent-browser doctor --offline --quick # Skip network probes and the live launch test
agent-browser mcp # Start an MCP stdio serverdoctor checks your environment, Chrome install, daemon state, config files, encryption key, providers, network reachability, and runs a live headless browser launch test. Stale socket/pid sidecar files are auto-cleaned. Output is also available as --json for agents.
Skills
agent-browser skills # List available skills
agent-browser skills list # Same as above
agent-browser skills get <name> # Output a skill's full content
agent-browser skills get <name> --full # Include references and templates
agent-browser skills get protected-vercel-deployments # Access protected Vercel deployments
agent-browser skills get --all # Output every skill
agent-browser skills path [name] # Print skill directory pathServes bundled skill content that always matches the installed CLI version. AI agents use this to get current instructions rather than relying on cached copies. Set AGENT_BROWSER_SKILLS_DIR to override the skills directory path.
MCP Server
agent-browser mcp
agent-browser mcp --tools all
agent-browser mcp --tools core,network,reactStarts a Model Context Protocol server over stdio. MCP clients launch this command as a subprocess and exchange newline-delimited JSON-RPC on stdin and stdout. The server defaults to MCP protocol 2025-11-25 and accepts older supported client protocol versions during initialization.
The default tools profile is core, which keeps MCP context small for everyday browser automation. Use --tools all for the full typed CLI parity surface, or combine profiles with commas, such as --tools core,network,react.
Profiles:
core— Default. Navigation, snapshots, interaction, waits, reads, screenshots, JavaScript eval, close, tab basics, and profile discoverynetwork— Network routes, request inspection, HAR, headers, credentials, offlinestate— Cookies, storage, auth, saved state, sessions, profiles, skillsdebug— Console/errors, tracing, profiling, recording, a11y audit, clipboard, plugins, doctor, dashboard, install, upgrade, chat, diff, batch, confirm/denytabs— Back/forward/reload, tabs, windows, frames, dialogsreact— React tree/inspect/renders/suspense, vitals, pushstatemobile— Viewport/device/geolocation/media, touch, swipe, mouse, keyboardall— Every MCP tool, including the full typed CLI parity surface
Common tools include:
agent_browser_tools_profilesagent_browser_openagent_browser_snapshotagent_browser_clickagent_browser_fillagent_browser_typeagent_browser_pressagent_browser_wait_for_selectoragent_browser_screenshotagent_browser_get_urlagent_browser_evalagent_browser_close
Each tool has typed fields such as url, selector, text, key, session, and allowedDomains, so MCP clients show meaningful approval prompts instead of raw command arrays. The common allowedDomains array maps to --allowed-domains and activates the same WebRTC containment and launch-mode restrictions. Each tool also accepts extraArgs for advanced CLI flags and exact CLI parity. Tool discovery is paginated and includes read-only/open-world annotations so modern MCP clients can load the large typed surface incrementally.
Example MCP client config:
{
"mcpServers": {
"agent-browser": {
"command": "agent-browser",
"args": ["mcp"]
}
}
}Full parity MCP client config:
{
"mcpServers": {
"agent-browser": {
"command": "agent-browser",
"args": ["mcp", "--tools", "all"]
}
}
}Tool invocations use the same config files and environment variables as the CLI. Use session in the tool arguments, or set AGENT_BROWSER_SESSION, to isolate browser state.
Authentication
agent-browser provides multiple ways to persist login sessions so you don't re-authenticate every run.
Quick summary
| Approach | Best for | Flag / Env |
|---|---|---|
| Chrome profile reuse | Reuse your existing Chrome login state (cookies, sessions) with zero setup | --profile <name> / AGENT_BROWSER_PROFILE |
| Persistent profile | Full browser state (cookies, IndexedDB, service workers, cache) across restarts | --profile / AGENT_BROWSER_PROFILE |
| Session persistence | Auto-save/restore cookies + localStorage from a stable session key | --session --restore / AGENT_BROWSER_RESTORE |
| Import from your browser | Grab auth from a Chrome session you already logged into | --auto-connect + state save |
| State file | Load a previously saved state JSON on launch | --state / AGENT_BROWSER_STATE |
| Auth vault | Store credentials locally (encrypted), login by name | auth save / auth login |
Import auth from your browser
If you are already logged in to a site in Chrome, you can grab that auth state and reuse it:
# 1. Launch Chrome with remote debugging enabled
# macOS:
"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" --remote-debugging-port=9222
# Or use --auto-connect to discover an already-running Chrome
# 2. Connect and save the authenticated state
agent-browser --auto-connect state save ./my-auth.json
# 3. Use the saved auth in future sessions
agent-browser --state ./my-auth.json open https://app.example.com/dashboard
# 4. Or use --restore for automatic persistence
SESSION="$(agent-browser session id --scope worktree --prefix myapp)"
agent-browser --session "$SESSION" --restore --state ./my-auth.json open https://app.example.com/dashboard
# From now on, --session "$SESSION" --restore auto-saves/restores this stateSecurity notes:
--remote-debugging-portexposes full browser control on localhost. Any local process can connect. Only use on trusted machines and close Chrome when done.- State files contain session tokens in plaintext. Add them to
.gitignoreand delete when no longer needed. For encryption at rest, setAGENT_BROWSER_ENCRYPTION_KEY(see State Encryption).
For full details on login flows, OAuth, 2FA, cookie-based auth, and the auth vault, see the Authentication docs.
Sessions
Run multiple isolated browser instances:
# Different sessions
agent-browser --session agent1 open site-a.com
agent-browser --session agent2 open site-b.com
# Or via environment variable
AGENT_BROWSER_SESSION=agent1 agent-browser click "#btn"
# List active sessions
agent-browser session list
# Output:
# Active sessions:
# -> default
# agent1
# Show current session
agent-browser session
# Generate a stable worktree-scoped session id
agent-browser session id --scope worktree --prefix next-dev-loop
# Inspect daemon, launch, and restore status
agent-browser session info --jsonEach session has its own:
- Browser instance
- Cookies and storage
- Navigation history
- Authentication state
Tab pinning
When several sessions share one Chrome over --cdp, each session remembers which tab it is bound to (by CDP target id, persisted across daemon restarts). A restarted daemon reattaches to the session's own tab instead of adopting whatever tab happens to be active, which is usually another session's.
By default, if the bound tab is closed the session falls back to a neighboring tab (legacy behavior). Pass --pin-tab (or set AGENT_BROWSER_PIN_TAB=1) to make the binding strict:
# Two agents sharing one Chrome, each pinned to its own tab
agent-browser --session agent1 --cdp 9222 --pin-tab open site-a.com
agent-browser --session agent2 --cdp 9222 --pin-tab open site-b.comWith --pin-tab:
- Attaching with no binding opens a fresh tab instead of adopting an existing one
- If the bound tab is closed, commands fail with a
tab_goneerror (exit code 1) instead of silently acting on another tab. JSON responses carry"code": "tab_gone"and recovery metadata indata.targetIdplus optionaldata.lastUrl tab list,tab new, andtab <ref>still work in that state, so an agent can recover by binding a new tab- Tabs opened by other sessions or the user never steal the pinned session's active tab
The flag is sticky per session: pass it once and later commands and daemon restarts keep the strict semantics. Pass --no-pin-tab to explicitly turn the pin off again.
data.lastUrl is emitted only for sanitized HTTP(S) URLs and about:blank. HTTP(S) credentials, query strings, and fragments are removed, and opaque URLs such as data: are omitted. Batch output exposes the same object as result.
When re-running a shared-tab script such as the repro from #1530, add --pin-tab to the first command for every session. Without it, open intentionally preserves the legacy behavior and navigates the shared active tab, so the original script still collides. The same rule applies when sessions attach with --auto-connect instead of --cdp.
Chrome Profile Reuse
The fastest way to use your existing login state: pass a Chrome profile name to --profile:
# List available Chrome profiles
agent-browser profiles
# Reuse your default Chrome profile's login state
agent-browser --profile Default open https://gmail.com
# Use a named profile (by display name or directory name)
agent-browser --profile "Work" open https://app.example.com
# Or via environment variable
AGENT_BROWSER_PROFILE=Default agent-browser open https://gmail.comThis copies your Chrome profile to a temp directory (read-only snapshot, no changes to your original profile), so the browser launches with your existing cookies and sessions.
Note: On Windows, close Chrome before using
--profile <name>if Chrome is running, as some profile files may be locked.
Persistent Profiles
For a persistent custom profile directory that stores state across browser restarts, pass a path to --profile:
# Use a persistent profile directory
agent-browser --profile ~/.myapp-profile open myapp.com
# Login once, then reuse the authenticated session
agent-browser --profile ~/.myapp-profile open myapp.com/dashboard
# Or via environment variable
AGENT_BROWSER_PROFILE=~/.myapp-profile agent-browser open myapp.comThe profile directory stores:
- Cookies and localStorage
- IndexedDB data
- Service workers
- Browser cache
- Login sessions
Tip: Use different profile paths for different projects to keep their browser state isolated.
Session Persistence
Use --restore with a stable --session to automatically save and restore cookies and localStorage across browser restarts:
# Generate a stable id for this worktree and auto-save/load state
SESSION="$(agent-browser session id --scope worktree --prefix twitter)"
agent-browser --session "$SESSION" --restore open twitter.com
# Login once, then state persists automatically
# State files stored in ~/.agent-browser/sessions/
# Optional: validate restored state before auto-saving again
agent-browser --session "$SESSION" --restore --restore-check-text Dashboard open twitter.comState is saved when the browser closes (explicit close, idle timeout, or daemon shutdown) and also periodically while the browser is open, so a browser window you close by hand still leaves a recent save behind. Periodic autosave waits for commands to settle, then saves at most once per AGENT_BROWSER_AUTOSAVE_INTERVAL_MS (default 30000; set to 0 to save only on close). Idle sessions keep saving on the same interval, so changes the page makes on its own (token refreshes, background requests) are captured too. It respects the --restore-save policy.
State Encryption
Encrypt saved session data at rest with AES-256-GCM:
# Generate key: openssl rand -hex 32
export AGENT_BROWSER_ENCRYPTION_KEY=<64-char-hex-key>
# State files are now encrypted automatically
agent-browser --session secure --restore open example.com| Variable | Description |
|---|---|
AGENT_BROWSER_RESTORE |
Auto-save/load state persistence name |
AGENT_BROWSER_RESTORE_SAVE |
Restore save policy: auto, always, or never |
AGENT_BROWSER_AUTOSAVE_INTERVAL_MS |
Min ms between periodic autosaves (default: 30000, 0 disables) |
AGENT_BROWSER_NAMESPACE |
Namespace for daemon sockets and restore state |
AGENT_BROWSER_SESSION_NAME |
Legacy auto-save/load state persistence name |
AGENT_BROWSER_ENCRYPTION_KEY |
64-char hex key for AES-256-GCM encryption |
AGENT_BROWSER_STATE_EXPIRE_DAYS |
Auto-delete states older than N days (default: 30) |
Security
agent-browser includes security features for safe AI agent deployments. All features are opt-in, and existing workflows are unaffected until you explicitly enable a feature:
- Authentication Vault: Store credentials locally (always encrypted), reference by name. The LLM never sees passwords.
auth loginnavigates withloadand then waits for login form selectors to appear (SPA-friendly, timeout follows the default action timeout). A key is auto-generated at~/.agent-browser/.encryption-keyifAGENT_BROWSER_ENCRYPTION_KEYis not set:echo "pass" | agent-browser auth save github --url https://github.com/login --username user --password-stdinthenagent-browser auth login github - Plugin System: Extend agent-browser with external executable plugins. Plugins run out-of-process over the
agent-browser.plugin.v1stdio JSON protocol and declare capabilities such ascredential.read,browser.provider,launch.mutate, orcommand.run. - Content Boundary Markers: Wrap page output in delimiters so LLMs can distinguish tool output from untrusted content:
--content-boundaries - Domain Allowlist: Restrict navigation to trusted domains (wildcards like
*.example.comalso match the bare domain):--allowed-domains "example.com,*.example.com". Sub-resource requests (scripts, images, fetch), WebSocket/EventSource connections, andsendBeaconcalls to non-allowed domains are blocked. WebRTC peer connections are disabled in supported Chromium sessions while the allowlist is active to prevent STUN, TURN, and DNS traffic from bypassing HTTP interception. Dedicated and shared workers are guarded with a bootstrap wrapper; if a page CSP forbids that wrapper, the worker fails closed rather than running without the allowlist guard. Pre-existing CDP sessions, auto-connect, Chrome profiles, direct-page provider plugins, agent-browser restore or state-file replay, raw Chrome args that select profiles, restore sessions, or open startup pages, iOS, and Safari reject this option because agent-browser cannot install equivalent containment before page scripts run. Include any CDN domains your target pages depend on (e.g.,*.cdn.example.com). - Action Policy: Gate destructive actions with a static policy file:
--action-policy ./policy.json - Action Confirmation: Require explicit approval for sensitive action categories:
--confirm-actions eval,download - Output Length Limits: Prevent context flooding:
--max-output 50000
| Variable | Description |
|---|---|
AGENT_BROWSER_CONTENT_BOUNDARIES |
Wrap page output in boundary markers |
AGENT_BROWSER_MAX_OUTPUT |
Max characters for page output |
AGENT_BROWSER_ALLOWED_DOMAINS |
Comma-separated allowed domain patterns; requires a fresh controllable browser context without profile/session startup args, restore/state replay, or direct-page provider plugins |
AGENT_BROWSER_ACTION_POLICY |
Path to action policy JSON file |
AGENT_BROWSER_CONFIRM_ACTIONS |
Action categories requiring confirmation |
AGENT_BROWSER_CONFIRM_INTERACTIVE |
Enable interactive confirmation prompts |
AGENT_BROWSER_PLUGINS |
JSON plugin registry override |
See Security documentation for details.
Plugin System
Plugins let third-party tools integrate without becoming built-in agent-browser dependencies. Add a plugin from npm or GitHub:
agent-browser plugin add agent-browser-plugin-captcha
agent-browser plugin add @company/agent-browser-plugin-vault --name vault
agent-browser plugin add org/agent-browser-plugin-cloud-browserReferences are resolved by shape: name uses npm, @scope/name uses npm, and owner/repo uses GitHub. plugin add writes ./agent-browser.json by default; use --global for ~/.agent-browser/config.json.
Plugin packages should support plugin.manifest so plugin add can discover their name and capabilities automatically. If a plugin does not support manifests, pass --capability <name> during add.
Plugins can also be configured manually in agent-browser.json:
{
"plugins": [
{
"name": "vault",
"command": "agent-browser-plugin-vault",
"capabilities": ["credential.read"]
},
{
"name": "cloud-browser",
"command": "agent-browser-plugin-cloud-browser",
"capabilities": ["browser.provider"]
},
{
"name": "stealth",
"command": "agent-browser-plugin-stealth",
"capabilities": ["launch.mutate"]
},
{
"name": "captcha",
"command": "agent-browser-plugin-captcha",
"capabilities": ["command.run", "captcha.solve"]
}
]
}Inspect configured plugins:
agent-browser plugin list
agent-browser plugin show vaultUse a credential provider plugin for one login:
agent-browser auth login my-app --credential-provider vault --item "My App"
agent-browser auth login my-app --credential-provider vault --item "My App" --url https://app.example.com/login --username-selector "#email" --password-selector "#password" --submit-selector "button[type=submit]"Use a browser provider plugin:
agent-browser --provider cloud-browser open https://example.comUse a launch mutator plugin for stealth or local launch customization. The plugin can append Chrome args, extensions, and init scripts before the browser starts:
agent-browser open https://example.comUse a generic plugin command for domain-specific tools such as CAPTCHA solvers:
agent-browser plugin run captcha captcha.solve --payload '{"siteKey":"...","url":"https://example.com"}'The protocol request always includes protocol, type, capability, and request. A credential plugin receives credential.resolve, a browser provider receives browser.launch, a launch mutator receives launch.mutate, and generic commands receive the supplied request type. plugin run is for command.run and custom capabilities; core capabilities and protocol request types use their dedicated command paths. agent-browser keeps browser automation, redaction-sensitive output, and policy enforcement in core.
Gate plugin access by capability action:
agent-browser --confirm-actions plugin:vault:credential.read auth login my-app --credential-provider vault --item "My App"
agent-browser --confirm-actions plugin:cloud-browser:browser.provider --provider cloud-browser open https://example.com
agent-browser --confirm-actions plugin:stealth:launch.mutate open https://example.comDo not put vault tokens or passwords in plugin command args. Use the vault vendor's own login/session mechanism or environment outside agent-browser config.
Snapshot Options
The snapshot command supports filtering to reduce output size:
agent-browser snapshot # Full accessibility tree
agent-browser snapshot -i # Interactive elements only (buttons, inputs, links)
agent-browser snapshot -i --urls # Interactive elements with link URLs
agent-browser snapshot -c # Compact (remove empty structural elements)
agent-browser snapshot -d 3 # Limit depth to 3 levels
agent-browser snapshot -s "#main" # Scope to CSS selector
agent-browser snapshot -i -c -d 5 # Combine options| Option | Description |
|---|---|
-i, --interactive |
Only show interactive elements (buttons, links, inputs) |
-u, --urls |
Include href URLs for link elements |
-c, --compact |
Remove empty structural elements |
-d, --depth <n> |
Limit tree depth |
-s, --selector <sel> |
Scope to CSS selector |
Annotated Screenshots
The --annotate flag overlays numbered labels on interactive elements in the screenshot. Each label [N] corresponds to ref @eN, so the same refs work for both visual and text-based workflows.
Annotated screenshots are supported on the CDP-backed browser path (Chrome/Lightpanda). The Safari/WebDriver backend does not yet support --annotate.
agent-browser screenshot --annotate
# -> Screenshot saved to /tmp/screenshot-2026-02-17T12-00-00-abc123.png
# [1] @e1 button "Submit"
# [2] @e2 link "Home"
# [3] @e3 textbox "Email"After an annotated screenshot, refs are cached so you can immediately interact with elements:
agent-browser screenshot --annotate ./page.png
agent-browser click @e2 # Click the "Home" link labeled [2]This is useful for multimodal AI models that can reason about visual layout, unlabeled icon buttons, canvas elements, or visual state that the text accessibility tree cannot capture.
Options
| Option | Description |
|---|---|
--session <name> |
Use isolated session (or AGENT_BROWSER_SESSION env) |
--restore [name] |
Auto-save/restore session state. Bare --restore uses --session as the key |
--restore-save |
Restore save policy: auto, always, or never |
--restore-check-url <glob> |
Validate restored state against a URL pattern |
--restore-check-text <text> |
Validate restored state against page text |
--restore-check-fn <js> |
Validate restored state against a truthy JavaScript expression |
--namespace <name> |
Isolate daemon sockets and restore-state directories |
--session-name <name> |
Legacy alias for restore persistence key |
--profile <name|path> |
Chrome profile name or persistent directory path (or AGENT_BROWSER_PROFILE env) |
--state |
Load storage state from JSON file (or AGENT_BROWSER_STATE env) |
--headers <json> |
Set HTTP headers scoped to the URL's origin |
--executable-path |
Custom browser executable (or AGENT_BROWSER_EXECUTABLE_PATH env) |
--extension |
Load browser extension (repeatable; or AGENT_BROWSER_EXTENSIONS env) |
--init-script |
Register a page init script before the first navigation (repeatable; or AGENT_BROWSER_INIT_SCRIPTS env) |
--enable <feature> |
Built-in init scripts: react-devtools (repeatable or comma-list; or AGENT_BROWSER_ENABLE env) |
--args <args> |
Browser launch args, comma or newline separated (or AGENT_BROWSER_ARGS env) |
--user-agent |
Custom User-Agent string (or AGENT_BROWSER_USER_AGENT env) |
--proxy |
Proxy server URL with optional auth (or AGENT_BROWSER_PROXY env) |
--proxy-bypass <hosts> |
Hosts to bypass proxy (or AGENT_BROWSER_PROXY_BYPASS env) |
--ignore-https-errors |
Ignore HTTPS certificate errors (useful for self-signed certs) |
--ca-cert |
Trust a CA certificate or PEM bundle for locally launched Chromium on Linux; later commands in the same running session retain it when omitted (or AGENT_BROWSER_CA_CERT env) |
--no-ca-cert |
Clear CA trust retained by the running browser session (or AGENT_BROWSER_CLEAR_CA_CERT) |
--allow-file-access |
Allow file:// URLs to access local files (Chromium only) |
--hide-scrollbars |
Hide native scrollbars in headless Chromium screenshots, enabled by default (or AGENT_BROWSER_HIDE_SCROLLBARS env) |
-p, --provider <name> |
Browser provider, including configured browser.provider plugins (or AGENT_BROWSER_PROVIDER env) |
--device <name> |
iOS device name, e.g. "iPhone 15 Pro" (or AGENT_BROWSER_IOS_DEVICE env) |
--json |
JSON output (for agents) |
--annotate |
Annotated screenshot with numbered element labels (or AGENT_BROWSER_ANNOTATE env) |
--screenshot-dir |
Default screenshot output directory (or AGENT_BROWSER_SCREENSHOT_DIR env) |
--screenshot-quality <n> |
JPEG quality 0-100 (or AGENT_BROWSER_SCREENSHOT_QUALITY env) |
--screenshot-format <fmt> |
Screenshot format: png, jpeg (or AGENT_BROWSER_SCREENSHOT_FORMAT env) |
--headed |
Show browser window (not headless) (or AGENT_BROWSER_HEADED env) |
--webgpu |
Enable WebGPU; SwiftShader software Vulkan on Linux, no GPU required (or AGENT_BROWSER_WEBGPU env) |
--cdp |
Connect via Chrome DevTools Protocol (port or WebSocket URL) |
--auto-connect |
Auto-discover and connect to running Chrome (or AGENT_BROWSER_AUTO_CONNECT env) |
--pin-tab |
Pin the session to its bound tab; fail with tab_gone instead of falling back to another tab (or AGENT_BROWSER_PIN_TAB env) |
--no-pin-tab |
Disable a sticky pin previously enabled with --pin-tab |
--color-scheme <scheme> |
Color scheme: dark, light, no-preference (or AGENT_BROWSER_COLOR_SCHEME env) |
--download-path |
Default download directory (or AGENT_BROWSER_DOWNLOAD_PATH env) |
--content-boundaries |
Wrap page output in boundary markers for LLM safety (or AGENT_BROWSER_CONTENT_BOUNDARIES env) |
--max-output <chars> |
Truncate page output to N characters (or AGENT_BROWSER_MAX_OUTPUT env) |
--allowed-domains <list> |
Comma-separated allowed domain patterns; also disables WebRTC peer connections in supported Chromium sessions and rejects CDP, auto-connect, Chrome profiles, restore/state replay, direct-page provider plugins, unsafe startup --args, iOS, and Safari (or AGENT_BROWSER_ALLOWED_DOMAINS env) |
--action-policy |
Path to action policy JSON file (or AGENT_BROWSER_ACTION_POLICY env) |
--confirm-actions <list> |
Action categories requiring confirmation (or AGENT_BROWSER_CONFIRM_ACTIONS env) |
--confirm-interactive |
Interactive confirmation prompts; auto-denies if stdin is not a TTY (or AGENT_BROWSER_CONFIRM_INTERACTIVE env) |
--engine <name> |
Browser engine: chrome (default), lightpanda (or AGENT_BROWSER_ENGINE env) |
--idle-timeout <time> |
Shut down the daemon after inactivity (10s, 3m, 1h, or raw ms). Defaults to 1h; use 0 to disable (or AGENT_BROWSER_IDLE_TIMEOUT_MS env) |
--no-auto-dialog |
Disable automatic dismissal of alert/beforeunload dialogs (or AGENT_BROWSER_NO_AUTO_DIALOG env) |
--model <name> |
AI model for chat command (or AI_GATEWAY_MODEL env) |
-v, --verbose |
Show tool commands and their raw output (chat) |
-q, --quiet |
Show only AI text responses, hide tool calls (chat) |
--config |
Use a custom config file (or AGENT_BROWSER_CONFIG env) |
--debug |
Debug output |
Observability Dashboard
Monitor agent-browser sessions in real time with a local web dashboard showing a live viewport and command activity feed.
# Start the dashboard server (runs in background on port 4848)
agent-browser dashboard start
agent-browser dashboard start --port 8080 # Custom port
# All sessions are automatically visible in the dashboard
agent-browser open example.com
# Stop the dashboard
agent-browser dashboard stopThe dashboard runs as a standalone background process on port 4848, independent of browser sessions. It stays available even when no sessions are running, and it works from http://localhost:4848 or a proxied/forwarded URL that reaches the dashboard server, such as https://dashboard.agent-browser.localhost or a Coder workspace URL. The browser stays on the dashboard origin; session-specific tabs, status, and stream traffic are proxied internally, so session ports do not need to be exposed.
The dashboard displays:
- Live viewport: real-time JPEG frames from the browser
- Activity feed: chronological command/result stream with timing and expandable details
- Console output: browser console messages (log, warn, error)
- Session creation: create new sessions from the UI with local engines (Chrome, Lightpanda) or cloud providers (AgentCore, Browserbase, Browserless, Browser Use, Kernel)
- AI Chat: chat with an AI assistant directly in the dashboard (requires Vercel AI Gateway configuration)
AI Chat
The dashboard includes an optional AI chat panel powered by the Vercel AI Gateway. The same functionality is available directly from the CLI via the chat command. Set these environment variables to enable AI chat:
export AI_GATEWAY_API_KEY=gw_your_key_here
export AI_GATEWAY_MODEL=anthropic/claude-sonnet-4.6 # optional, this is the default
export AI_GATEWAY_URL=https://ai-gateway.vercel.sh # optional, this is the defaultCLI usage:
agent-browser chat "open google.com and search for cats" # Single-shot
agent-browser chat # Interactive REPL
agent-browser -q chat "summarize this page" # Quiet mode (text only)
agent-browser -v chat "fill in the login form" # Verbose (show command output)
agent-browser --model openai/gpt-4o chat "take a screenshot" # Override modelThe chat command translates natural language instructions into agent-browser commands, executes them, and streams the AI response. In interactive mode, type quit to exit. Use --json for structured output suitable for agent consumption.
Dashboard usage:
The Chat tab is always visible in the dashboard. When AI_GATEWAY_API_KEY is set, the Rust server proxies requests to the gateway and streams responses back using the Vercel AI SDK's UI Message Stream protocol. Without the key, sending a message shows an error inline.
Configuration
Create an agent-browser.json file to set persistent defaults instead of repeating flags on every command.
Locations (lowest to highest priority):
~/.agent-browser/config.json: user-level defaults./agent-browser.json: project-level overrides (in working directory)AGENT_BROWSER_*environment variables override config file values- CLI flags override everything
Example agent-browser.json:
{
"headed": true,
"proxy": "http://localhost:8080",
"profile": "./browser-data",
"userAgent": "my-agent/1.0",
"hideScrollbars": false,
"ignoreHttpsErrors": true,
"plugins": [
{
"name": "vault",
"command": "agent-browser-plugin-vault",
"capabilities": ["credential.read"]
}
]
}Example proxy CA configuration:
{
"proxy": "http://localhost:8080",
"caCert": "/etc/ssl/certs/proxy-ca.crt"
}caCert remains effective for later commands in the same running session. Use "clearCaCert": true, --no-ca-cert, or AGENT_BROWSER_CLEAR_CA_CERT=1 to remove it. Setting, changing, or clearing the CA relaunches Chromium without restarting the daemon. Repeating the same certificate content, including from a different path, reuses the current browser. On Linux, agent-browser install --with-deps installs the required certutil; otherwise install libnss3-tools on Debian/Ubuntu or nss-tools on RPM Linux.
Use --config or AGENT_BROWSER_CONFIG to load a specific config file instead of the defaults:
agent-browser --config ./ci-config.json open example.com
AGENT_BROWSER_CONFIG=./ci-config.json agent-browser open example.comAll options from the table above can be set in the config file using camelCase keys (e.g., --executable-path becomes "executablePath", --proxy-bypass becomes "proxyBypass"). Plugins are configured with the "plugins" array shown above. Unknown keys are ignored for forward compatibility.
A JSON Schema is available for IDE autocomplete and validation. Add a $schema key to your config file to enable it:
{
"$schema": "https://agent-browser.dev/schema.json",
"headed": true
}Boolean flags accept an optional true/false value to override config settings. For example, --headed false disables "headed": true from config. A bare --headed is equivalent to --headed true.
Auto-discovered config files that are missing are silently ignored. If --config points to a missing or invalid file, agent-browser exits with an error. Extensions from user and project configs are merged (concatenated), not replaced.
Tip: If your project-level
agent-browser.jsoncontains environment-specific values (paths, proxies), consider adding it to.gitignore.
Default Timeout
The default timeout for standard operations (clicks, waits, fills, etc.) is 25 seconds. This is intentionally below the CLI's 30-second IPC read timeout so that the daemon returns a proper error instead of the CLI timing out with EAGAIN.
Override the default timeout via environment variable:
# Set a longer timeout for slow pages (in milliseconds)
export AGENT_BROWSER_DEFAULT_TIMEOUT=45000Note: Setting this above 30000 (30s) may cause EAGAIN errors on slow operations because the CLI's read timeout will expire before the daemon responds. The CLI retries transient errors automatically, but response times will increase.
| Variable | Description |
|---|---|
AGENT_BROWSER_DEFAULT_TIMEOUT |
Default operation timeout in ms (default: 25000) |
Selectors
Refs (Recommended for AI)
Refs provide deterministic element selection from snapshots:
# 1. Get snapshot with refs
agent-browser snapshot
# Output:
# - heading "Example Domain" [ref=e1] [level=1]
# - button "Submit" [ref=e2]
# - textbox "Email" [ref=e3]
# - link "Learn more" [ref=e4]
# 2. Use refs to interact
agent-browser click @e2 # Click the button
agent-browser fill @e3 "[email protected]" # Fill the textbox
agent-browser get text @e1 # Get heading text
agent-browser hover @e4 # Hover the linkWhen a ref click is blocked by an overlay, the error includes the covering element, such as covered by . Click the banner or dialog control first, then run snapshot again before reusing refs.
Why use refs?
- Deterministic: Ref points to exact element from snapshot
- Fast: No DOM re-query needed
- AI-friendly: Snapshot + ref workflow is optimal for LLMs
CSS Selectors
agent-browser click "#id"
agent-browser click ".class"
agent-browser click "div > button"Text & XPath
agent-browser click "text=Submit"
agent-browser click "xpath=//button"Semantic Locators
agent-browser find role button click --name "Submit"
agent-browser find label "Email" fill "[email protected]"Agent Mode
Use --json for machine-readable output:
agent-browser snapshot --json
# Returns: {"success":true,"data":{"snapshot":"...","refs":{"e1":{"role":"heading","name":"Title"},...}}}
agent-browser get text @e1 --json
agent-browser is visible @e2 --jsonOptimal AI Workflow
# 1. Navigate and get snapshot
agent-browser open example.com
agent-browser snapshot -i --json # AI parses tree and refs
# 2. AI identifies target refs from snapshot
# 3. Execute actions using refs
agent-browser click @e2
agent-browser fill @e3 "input text"
# 4. Get new snapshot if page changed
agent-browser snapshot -i --jsonCommand Chaining
Commands can be chained with && in a single shell invocation. The browser persists via a background daemon, so chaining is safe and more efficient:
# Open, wait for load, and snapshot in one call
agent-browser open example.com && agent-browser wait --load networkidle && agent-browser snapshot -i
# Chain multiple interactions
agent-browser fill @e1 "[email protected]" && agent-browser fill @e2 "pass" && agent-browser click @e3
# Navigate and screenshot
agent-browser open example.com && agent-browser wait --load networkidle && agent-browser screenshot page.pngUse && when you don't need intermediate output. Run commands separately when you need to parse output first (e.g., snapshot to discover refs before interacting).
Headed Mode
Show the browser window for debugging:
agent-browser open example.com --headedThis opens a visible browser window instead of running headless.
On Linux hosts with no display (servers, containers), --headed still works: when DISPLAY is unset and Xvfb is installed, agent-browser starts a private virtual display for the browser and cleans it up on close (opt out with AGENT_BROWSER_NO_XVFB=1). Needed for WebGPU screenshots, and useful for extensions that misbehave headless.
Note: Browser extensions work in both headed and headless mode (Chrome's
--headless=new).
WebGPU
Headless Chrome does not expose WebGPU by default, so pages using it (three.js WebGPURenderer, Babylon.js, etc.) silently render black. The --webgpu flag enables a launch preset that makes WebGPU work, including in GPU-less containers and CI:
agent-browser --webgpu open https://my-webgpu-app.example.com
agent-browser screenshot app.pngOn macOS and Windows this uses the hardware Metal/D3D backend. On Linux it routes WebGPU through SwiftShader's software Vulkan (no GPU needed), which requires the system Vulkan loader and Mesa ICD:
apt-get install -y libvulkan1 mesa-vulkan-driversOne upstream caveat: headless Chrome cannot capture WebGPU canvas presentation in screenshots on Windows and Linux (rendering and in-page readbacks work; the capture is black). Screenshots of WebGPU pages work headless on macOS; on Windows run --headed in a logged-in desktop session; on Linux just add --headed — when no DISPLAY is set and Xvfb is installed, agent-browser starts a private virtual display automatically (opt out with AGENT_BROWSER_NO_XVFB=1).
Verify the full pipeline (adapter, render pass, and screenshot capture) with:
agent-browser doctor --webgpuNotes for WebGPU pages:
- WebGPU only exists in secure contexts (
https://,http://localhost, orfile://). - three.js
WebGPURendererinitializes asynchronously and silently falls back to WebGL2 when no adapter is available — wait for the app to render its first frame before taking a screenshot. - To prefer a real GPU on Linux instead of SwiftShader, override both the Vulkan driver and the adapter with
--args "--use-vulkan=native,--use-webgpu-adapter=default"(user args win over the preset;--use-webgpu-adapteralone still enumerates only SwiftShader).
See the WebGPU docs page for the full platform matrix and container recipe.
Authenticated Sessions
Use --headers to set HTTP headers for a specific origin, enabling authentication without login flows:
# Headers are scoped to api.example.com only
agent-browser open api.example.com --headers '{"Authorization": "Bearer <token>"}'
# Requests to api.example.com include the auth header
agent-browser snapshot -i --json
agent-browser click @e2
# Navigate to another domain - headers are NOT sent (safe!)
agent-browser open other-site.comThis is useful for:
- Skipping login flows - Authenticate via headers instead of UI
- Switching users - Start new sessions with different auth tokens
- API testing - Access protected endpoints directly
- Security - Headers are scoped to the origin, not leaked to other domains
To set headers for multiple origins, use --headers with each open command:
agent-browser open api.example.com --headers '{"Authorization": "Bearer token1"}'
agent-browser open api.acme.com --headers '{"Authorization": "Bearer token2"}'For global headers (all domains), use set headers:
agent-browser set headers '{"X-Custom-Header": "value"}'Custom Browser Executable
Use a custom browser executable instead of the bundled Chromium. This is useful for:
- Serverless deployment: Use lightweight Chromium builds like
@sparticuz/chromium(~50MB vs ~684MB) - System browsers: Use an existing Chrome/Chromium installation
- Custom builds: Use modified browser builds
CLI Usage
# Via flag
agent-browser --executable-path /path/to/chromium open example.com
# Via environment variable
AGENT_BROWSER_EXECUTABLE_PATH=/path/to/chromium agent-browser open example.comServerless (Vercel)
Run agent-browser + Chrome in an ephemeral Vercel Sandbox microVM. No external server needed:
import { runAgentBrowserCommand, withAgentBrowserSandbox } from "@agent-browser/sandbox/vercel";
const result = await withAgentBrowserSandbox(async (sandbox) => {
await runAgentBrowserCommand(sandbox, ["open", "https://example.com"]);
return runAgentBrowserCommand(sandbox, ["screenshot"]);
});Install @agent-browser/sandbox and @vercel/sandbox in the consuming app. See the sandbox helper example for minimal Vercel Sandbox usage, or the environments example for a full UI demo with a deploy-to-Vercel button.
Fresh Vercel and eve sandboxes install Chromium system dependencies by default. Pass installSystemDependencies: false only when your sandbox image already includes those libraries.
eve extension
Give an eve agent the full browser tool set by mounting the @agent-browser/eve extension:
// agent/extensions/browser.ts
import browser from "@agent-browser/eve";
export default browser({});This composes ~20 namespaced tools into the agent — browser__navigate, browser__snapshot, browser__click, browser__fill, browser__find, browser__screenshot, and more — all running agent-browser inside the agent's sandbox. agent-browser installs automatically on first use; pre-install it in agent/sandbox.ts with the @agent-browser/eve/sandbox helpers to bake the cost into the sandbox template instead. Configuration (domain allowlists, output limits, session naming) and per-tool overrides are covered in the package README, and the eve example is a complete app with the extension mounted.
Serverless (AWS Lambda)
import chromium from '@sparticuz/chromium';
import { execSync } from 'child_process';
export async function handler() {
const executablePath = await chromium.executablePath();
const result = execSync(
`AGENT_BROWSER_EXECUTABLE_PATH=${executablePath} agent-browser open https://example.com && agent-browser snapshot -i --json`,
{ encoding: 'utf-8' }
);
return JSON.parse(result);
}Local Files
Open and interact with local files (PDFs, HTML, etc.) using file:// URLs:
# Enable file access (required for JavaScript to access local files)
agent-browser --allow-file-access open file:///path/to/document.pdf
agent-browser --allow-file-access open file:///path/to/page.html
# Take screenshot of a local PDF
agent-browser --allow-file-access open file:///Users/me/report.pdf
agent-browser screenshot report.pngThe --allow-file-access flag adds Chromium flags (--allow-file-access-from-files, --allow-file-access) that allow file:// URLs to:
- Load and render local files
- Access other local files via JavaScript (XHR, fetch)
- Load local resources (images, scripts, stylesheets)
Note: This flag only works with Chromium. For security, it's disabled by default.
CDP Mode
Connect to an existing browser via Chrome DevTools Protocol:
# Start Chrome with: google-chrome --remote-debugging-port=9222
# Connect once, then run commands without --cdp
agent-browser connect 9222
agent-browser snapshot
agent-browser tab
agent-browser close
# Or pass --cdp on each command
agent-browser --cdp 9222 snapshot
# Connect to remote browser via WebSocket URL
agent-browser --cdp "wss://your-browser-service.com/cdp?token=..." snapshotThe --cdp flag accepts either:
- A port number (e.g.,
9222) for local connections viahttp://localhost:{port} - A full WebSocket URL (e.g.,
wss://...orws://...) for remote browser services
This enables control of:
- Electron apps
- Chrome/Chromium instances with remote debugging
- WebView2 applications
- Any browser exposing a CDP endpoint
Auto-Connect
Use --auto-connect to automatically discover and connect to a running Chrome instance without specifying a port:
# Auto-discover running Chrome with remote debugging
agent-browser --auto-connect open example.com
agent-browser --auto-connect snapshot
# Or via environment variable
AGENT_BROWSER_AUTO_CONNECT=1 agent-browser snapshotAuto-connect discovers Chrome by:
- Reading Chrome's
DevToolsActivePortfile from the default user data directory - Falling back to probing common debugging ports (9222, 9229)
- If HTTP-based discovery (
/json/version,/json/list) fails, falling back to a direct WebSocket connection
This is useful when:
- Chrome 144+ has remote debugging enabled via
chrome://inspect/#remote-debugging(which uses a dynamic port) - You want a zero-configuration connection to your existing browser
- You don't want to track which port Chrome is using
Streaming (Browser Preview)
Stream the browser viewport via WebSocket for live preview or "pair browsing" where a human can watch and interact alongside an AI agent.
Streaming
Every session automatically starts a WebSocket stream server on an OS-assigned port. Use stream status to see the bound port and connection state:
agent-browser stream statusTo bind to a specific port, set AGENT_BROWSER_STREAM_PORT:
AGENT_BROWSER_STREAM_PORT=9223 agent-browser open example.comFrame encoding is daemon-wide:
| Variable | Default | Description |
|---|---|---|
AGENT_BROWSER_STREAM_QUALITY |
80 |
JPEG quality, 0 to 100 |
AGENT_BROWSER_STREAM_MAX_WIDTH |
the viewport | Caps frame width in pixels |
AGENT_BROWSER_STREAM_MAX_HEIGHT |
the viewport | Caps frame height in pixels |
Width and height cap the encoded frame and leave the page size alone, so a portrait or HiDPI viewport keeps its resolution unless you cap it. The live stream requests jpeg. An explicit screencast_start reconfigures the same screencast, so a client can see the format change mid-stream. On a busy page at 1280x720, quality 80 costs about 54 KB per frame, quality 20 about 25 KB, and quality 20 at 640x360 about 9 KB.
# Cheaper frames for a constrained link
AGENT_BROWSER_STREAM_QUALITY=20 \
AGENT_BROWSER_STREAM_MAX_WIDTH=640 \
AGENT_BROWSER_STREAM_MAX_HEIGHT=360 \
agent-browser open example.comYou can also manage streaming at runtime with stream enable, stream disable, and stream status:
agent-browser stream enable --port 9223 # Re-enable on a specific port
agent-browser stream disable # Stop streaming for the sessionThe WebSocket server streams the browser viewport and accepts input events.
WebSocket Protocol
Connect to ws://localhost:9223 to receive frames and send input:
Receive frames:
{
"type": "frame",
"seq": 41,
"data": "",
"metadata": {
"deviceWidth": 1280,
"deviceHeight": 720,
"pageScaleFactor": 1,
"offsetTop": 0,
"scrollOffsetX": 0,
"scrollOffsetY": 0,
"timestamp": 1785038682238
}
}seq is a monotonic frame id, echoed back in an ack message under ack pacing. metadata.timestamp is the capture time in epoch milliseconds, so a client can tell how old a frame is by the time it draws it.
Send mouse events:
{
"type": "input_mouse",
"eventType": "mousePressed",
"x": 100,
"y": 200,
"button": "left",
"clickCount": 1
}Send keyboard events:
{
"type": "input_keyboard",
"eventType": "keyDown",
"key": "Enter",
"code": "Enter"
}Send touch events:
{
"type": "input_touch",
"eventType": "touchStart",
"touchPoints": [{ "x": 100, "y": 200 }]
}Cap the frame rate (per client):
{
"type": "config",
"maxFps": 10
}Frames are delivered latest-first: the server picks the newest frame at send time, so frames produced while an earlier one is still being written are skipped rather than queued. maxFps (1 to 120, 0 = uncapped) limits delivery for that client only. A client that sends {"type":"config","pacing":"ack"} receives one frame at a time and acknowledges it with {"type":"ack","seq":N}, so nothing stale reaches the socket even if that client stalls; in the default push pacing, frames already handed to the transport are still delivered in order. Both settings can also be declared on the URL (ws://127.0.0.1:/?pacing=ack&maxFps=10), which is the only way to cover the connection's opening frame. Input events are read on a dedicated task per connection, so clicks and keystrokes dispatch immediately even while frames are mid-write to a slow client. They are sent to the browser without waiting for its reply, so a click stays responsive behind a burst of mouse moves, and ordering is preserved.
Architecture
agent-browser uses a client-daemon architecture:
- Rust CLI - Parses commands, communicates with daemon
- Rust Daemon - Pure Rust daemon using direct CDP, no Node.js required
The daemon starts automatically on first command and persists between commands for fast subsequent operations. After 1 hour with no commands or dashboard input it saves configured restore state, closes the browser, and exits, so an integration that dies without calling close cannot leak the daemon and its browser indefinitely; the next command starts a fresh daemon and configured state restore works as usual. A session without --restore or another restore key does not save browser state, so its transient state and open tabs are discarded at shutdown. Set --idle-timeout to a duration such as 30s, 5m, or 1h, or set AGENT_BROWSER_IDLE_TIMEOUT_MS to a value in milliseconds. Use 0 to disable idle shutdown entirely. The default never closes a headed browser, including Safari and iOS WebDriver sessions, or a user-attached browser because those may be in direct human use. Provider-owned cloud browsers remain eligible for cleanup. An explicitly set timeout applies to every browser.
Browser Engine: Uses Chrome (from Chrome for Testing) by default. The --engine flag selects between chrome and lightpanda. Supported browsers: Chromium/Chrome (via CDP) and Safari (via WebDriver for iOS).
Platforms
| Platform | Binary |
|---|---|
| macOS ARM64 | Native Rust |
| macOS x64 | Native Rust |
| Linux ARM64 | Native Rust |
| Linux x64 | Native Rust |
| Windows x64 | Native Rust |
Usage with AI Agents
Just ask the agent
The simplest approach is to tell your agent to use it:
Use agent-browser to test the login flow. Run agent-browser --help to see available commands.The --help output is comprehensive and most agents can figure it out from there.
AI Coding Assistants (recommended)
Add the skill to your AI coding assistant for richer context:
npx skills add vercel-labs/agent-browserThis works with Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, Goose, OpenCode, and Windsurf. The skill is fetched from the repository, so it stays up to date automatically. Do not copy SKILL.md from node_modules as it will become stale.
Claude Code
Install as a Claude Code skill:
npx skills add vercel-labs/agent-browserThis adds a thin discovery stub at .claude/skills/agent-browser/SKILL.md. The stub is intentionally minimal — it points Claude Code at agent-browser skills get core to load the actual workflow content at runtime. This way the instructions always match the installed CLI version instead of going stale between releases.
AGENTS.md / CLAUDE.md
For more consistent results, add to your project or global instructions file:
## Browser Automation
Use `agent-browser` for web automation. Run `agent-browser --help` for all commands.
Core workflow:
1. `agent-browser open ` - Navigate to page
2. `agent-browser snapshot -i` - Get interactive elements with refs (@e1, @e2)
3. `agent-browser click @e1` / `fill @e2 "text"` - Interact using refs
4. Re-snapshot after page changesIntegrations
iOS Simulator
Control real Mobile Safari in the iOS Simulator for authentic mobile web testing. Requires macOS with Xcode.
Setup:
# Install Appium and XCUITest driver
npm install appium
appium driver install xcuitestUsage:
# List available iOS simulators
agent-browser device list
# Launch Safari on a specific device
agent-browser -p ios --device "iPhone 16 Pro" open https://example.com
# Same commands as desktop
agent-browser -p ios snapshot -i
agent-browser -p ios tap @e1
agent-browser -p ios fill @e2 "text"
agent-browser -p ios screenshot mobile.png
# Mobile-specific commands
agent-browser -p ios swipe up
agent-browser -p ios swipe down 500
# Close session
agent-browser -p ios closeOr use environment variables:
export AGENT_BROWSER_PROVIDER=ios
export AGENT_BROWSER_IOS_DEVICE="iPhone 16 Pro"
agent-browser open https://example.com| Variable | Description |
|---|---|
AGENT_BROWSER_PROVIDER |
Set to ios to enable iOS mode |
AGENT_BROWSER_IOS_DEVICE |
Device name (e.g., "iPhone 16 Pro", "iPad Pro") |
AGENT_BROWSER_IOS_UDID |
Device UDID (alternative to device name) |
Supported devices: All iOS Simulators available in Xcode (iPhones, iPads), plus real iOS devices.
Note: The iOS provider boots the simulator, starts Appium, and controls Safari. First launch takes ~30-60 seconds; subsequent commands are fast.
Real Device Support
Appium also supports real iOS devices connected via USB. This requires additional one-time setup:
1. Get your device UDID:
xcrun xctrace list devices
# or
system_profiler SPUSBDataType | grep -A 5 "iPhone\|iPad"2. Sign WebDriverAgent (one-time):
# Open the WebDriverAgent Xcode project
cd ~/.appium/node_modules/appium-xcuitest-driver/node_modules/appium-webdriveragent
open WebDriverAgent.xcodeprojIn Xcode:
- Select the
WebDriverAgentRunnertarget - Go to Signing & Capabilities
- Select your Team (requires Apple Developer account, free tier works)
- Let Xcode manage signing automatically
3. Use with agent-browser:
# Connect device via USB, then:
agent-browser -p ios --device "<DEVICE_UDID>" open https://example.com
# Or use the device name if unique
agent-browser -p ios --device "John's iPhone" open https://example.comReal device notes:
- First run installs WebDriverAgent to the device (may require Trust prompt)
- Device must be unlocked and connected via USB
- Slightly slower initial connection than simulator
- Tests against real Safari performance and behavior
Browserless
Browserless provides cloud browser infrastructure with a Sessions API. Use it when running agent-browser in environments where a local browser isn't available.
To enable Browserless, use the -p flag:
export BROWSERLESS_API_KEY="your-api-token"
agent-browser -p browserless open https://example.comOr use environment variables for CI/scripts:
export AGENT_BROWSER_PROVIDER=browserless
export BROWSERLESS_API_KEY="your-api-token"
agent-browser open https://example.comOptional configuration via environment variables:
| Variable | Description | Default |
|---|---|---|
BROWSERLESS_API_URL |
Base API URL (for custom regions or self-hosted) | https://production-sfo.browserless.io |
BROWSERLESS_BROWSER_TYPE |
Type of browser to use (chromium or chrome) | chromium |
BROWSERLESS_TTL |
Session TTL in milliseconds | 300000 |
BROWSERLESS_STEALTH |
Enable stealth mode (true/false) |
true |
When enabled, agent-browser connects to a Browserless cloud session instead of launching a local browser. All commands work identically.
Get your API token from the Browserless Dashboard.
Browserbase
Browserbase provides remote browser infrastructure to make deployment of agentic browsing agents easy. Use it when running the agent-browser CLI in an environment where a local browser isn't feasible.
To enable Browserbase, use the -p flag:
export BROWSERBASE_API_KEY="your-api-key"
agent-browser -p browserbase open https://example.comOr use environment variables for CI/scripts:
export AGENT_BROWSER_PROVIDER=browserbase
export BROWSERBASE_API_KEY="your-api-key"
agent-browser open https://example.comWhen enabled, agent-browser connects to a Browserbase session instead of launching a local browser. All commands work identically.
Get your API key from the Browserbase Dashboard.
Browser Use
Browser Use provides cloud browser infrastructure for AI agents. Use it when running agent-browser in environments where a local browser isn't available (serverless, CI/CD, etc.).
To enable Browser Use, use the -p flag:
export BROWSER_USE_API_KEY="your-api-key"
agent-browser -p browseruse open https://example.comOr use environment variables for CI/scripts:
export AGENT_BROWSER_PROVIDER=browseruse
export BROWSER_USE_API_KEY="your-api-key"
agent-browser open https://example.comWhen enabled, agent-browser connects to a Browser Use cloud session instead of launching a local browser. All commands work identically.
Get your API key from the Browser Use Cloud Dashboard. Free credits are available to get started, with pay-as-you-go pricing after.
Kernel
Kernel provides cloud browser infrastructure for AI agents with features like stealth mode and persistent profiles.
To enable Kernel, use the -p flag:
export KERNEL_API_KEY="your-api-key"
agent-browser -p kernel open https://example.comOr use environment variables for CI/scripts:
export AGENT_BROWSER_PROVIDER=kernel
export KERNEL_API_KEY="your-api-key"
agent-browser open https://example.comOptional configuration via environment variables:
| Variable | Description | Default |
|---|---|---|
KERNEL_HEADLESS |
Run browser in headless mode (true/false) |
true |
KERNEL_STEALTH |
Enable stealth mode to avoid bot detection (true/false) |
false |
KERNEL_TIMEOUT_SECONDS |
Session timeout in seconds | 300 |
KERNEL_PROFILE_NAME |
Browser profile name for persistent cookies/logins (created if it doesn't exist) | (none) |
When enabled, agent-browser connects to a Kernel cloud session instead of launching a local browser. All commands work identically.
Profile Persistence: When KERNEL_PROFILE_NAME is set, the profile will be created if it doesn't already exist. Cookies, logins, and session data are automatically saved back to the profile when the browser session ends, making them available for future sessions.
Get your API key from the Kernel Dashboard.
AgentCore
AWS Bedrock AgentCore provides cloud browser sessions with SigV4 authentication.
To enable AgentCore, use the -p flag:
agent-browser -p agentcore open https://example.comOr use environment variables for CI/scripts:
export AGENT_BROWSER_PROVIDER=agentcore
agent-browser open https://example.comCredentials are automatically resolved from environment variables (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY) or the AWS CLI (aws configure export-credentials), which supports SSO, profiles, and IAM roles.
Optional configuration via environment variables:
| Variable | Description | Default |
|---|---|---|
AGENTCORE_REGION |
AWS region for the AgentCore endpoint | us-east-1 |
AGENTCORE_BROWSER_ID |
Browser identifier | aws.browser.v1 |
AGENTCORE_PROFILE_ID |
Browser profile for persistent state (cookies, localStorage) | (none) |
AGENTCORE_SESSION_TIMEOUT |
Session timeout in seconds | 3600 |
AWS_PROFILE |
AWS CLI profile for credential resolution | default |
Browser profiles: When AGENTCORE_PROFILE_ID is set, browser state (cookies, localStorage) is persisted across sessions automatically.
When enabled, agent-browser connects to an AgentCore cloud browser session instead of launching a local browser. All commands work identically.
License
Apache-2.0
File: docs/src/app/commands/page.mdx
Commands
Core
/* Detailed source-code truncated for AI context efficiency. */Clicks fail before dispatch when another element covers the target's click point. The error names the covering element, for example covered by . Dismiss or interact with that element, take a fresh snapshot, then retry the original action.
Headless Chromium screenshots hide native scrollbars for consistent image output. Pass --hide-scrollbars false when launching to keep native scrollbars visible.
Get info
agent-browser get text <sel> # Get text content
agent-browser get html <sel> # Get innerHTML
agent-browser get value <sel> # Get input value
agent-browser get attr <sel> <attr> # Get attribute
agent-browser get title # Get page title
agent-browser get url # Get current URL
agent-browser get cdp-url # Get CDP WebSocket URL
agent-browser get count <sel> # Count matching elements
agent-browser get box <sel> # Get bounding box
agent-browser get styles <sel> # Get computed stylesRead agent-friendly text
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 --jsonread 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.
Check state
agent-browser is visible <sel> # Check if visible
agent-browser is enabled <sel> # Check if enabled
agent-browser is checked <sel> # Check if checkedFind elements
Semantic locators with actions (click, fill, check, hover, text):
agent-browser find role <role> <action> [value]
agent-browser find text <text> <action> [value]
agent-browser find label <label> <action> [value]
agent-browser find placeholder <action> [value]
agent-browser find alt <text> <action> [value]
agent-browser find title <text> <action> [value]
agent-browser find testid <action> [value]
agent-browser find first <sel> <action> [value]
agent-browser find last <sel> <action> [value]
agent-browser find nth <n> <sel> <action> [value]Options:
--name <name>: filter role by accessible name--exact: exact, case-sensitive match. Forroleit 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, =list, top-level <header>=banner
agent-browser find label "Email" fill "[email protected]"
agent-browser find alt "Logo" click
agent-browser find first ".item" click
agent-browser find last ".item" text
agent-browser find nth 2 ".card" hoverWait
agent-browser wait <selector> # Wait for element
agent-browser wait <ms> # Wait for time
agent-browser wait --text "Welcome" # Wait for text (substring match)
agent-browser wait --url "**/dash" # Wait for URL pattern
agent-browser wait --load networkidle # Wait for load state
agent-browser wait --fn "condition" # Wait for JS condition
agent-browser wait --download [path] # Wait for download
agent-browser wait --fn "!document.body.innerText.includes('Loading...')" # Wait for text to disappear
agent-browser wait "#spinner" --state hidden # Wait for element to disappearDownloads
agent-browser download <sel> # Click element to trigger download
agent-browser wait --download [path] # Wait for any download to completeUse --download-path <dir> (or AGENT_BROWSER_DOWNLOAD_PATH env) to set a default download directory. Without it, downloads go to a temporary directory that is deleted when the browser closes.
See Files & Clipboard for upload, download, local file, screenshot, PDF, and clipboard workflows.
Mouse
agent-browser mouse move <x> <y> # Move mouse
agent-browser mouse down [button] # Press button
agent-browser mouse up [button] # Release button
agent-browser mouse wheel <dy> [dx] # Scroll wheelClipboard
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)See Files & Clipboard for clipboard, upload, download, local file, screenshot, and PDF workflows.
Settings
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 # HTTP basic auth
agent-browser set media [dark|light] # Emulate color scheme (persists for session)Use --color-scheme for persistent dark/light mode across all commands:
agent-browser --color-scheme dark open https://example.comCookies & storage
agent-browser cookies # Get all cookies
agent-browser cookies set <name> <val> # Set cookie
agent-browser cookies clear # Clear cookies
agent-browser storage local # Get all localStorage
agent-browser storage local <key> # Get specific key
agent-browser storage local set <k> <v> # Set value
agent-browser storage local clear # Clear all
agent-browser storage session # Same for sessionStorageNetwork
agent-browser network route # Intercept requests
agent-browser network route --abort # Block requests
agent-browser network route --body <json> # Mock response
agent-browser network route '*' --abort --resource-type script # Block scripts only
agent-browser network unroute [url] # Remove routes
agent-browser network requests # View tracked requests
agent-browser network requests --clear # Clear request log
agent-browser network requests --filter # Filter by URL pattern
agent-browser network requests --type xhr,fetch # Filter by resource type
agent-browser network requests --method POST # Filter by HTTP method
agent-browser network requests --status 2xx # Filter by status (200, 2xx, 400-499)
agent-browser network request <requestId> # View full request/response detail
agent-browser network har start # Start HAR recording (embeds text response bodies)
agent-browser network har start --content all # Embed all response bodies (binary as base64)
agent-browser network har start --content none # Metadata only, no bodies
agent-browser network har stop [output.har] # Stop and save HAR (temp path if omitted)See Network for pre-navigation routing, request filters, HAR export, and SSR/no-JavaScript debugging.
Tabs & frames
agent-browser tab # List tabs (each row shows tabId and label)
agent-browser tab new [url] # New tab
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 # Open new browser window
agent-browser frame <sel> # Switch to iframe by CSS selector
agent-browser frame @e3 # Switch to iframe by element ref
agent-browser frame main # Back to main frameStable tab ids and labels
Tab ids are stable strings of the form t1, t2, t3. They're never reused within a session, so t2 keeps pointing at the same tab even as other tabs are opened or closed. The t prefix mirrors the @e1 element-ref convention and is not interchangeable with positional integers — agent-browser tab 2 errors with a teaching message; use t2.
You can also assign a memorable label (docs, app, admin) at tab-creation time and use it anywhere an id is accepted:
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 labelLabels are never auto-generated and never rewritten on navigation — an agent that names a tab docs keeps that name until the tab is closed. Labels are unique within a session; creating a second tab with an existing label errors.
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. Each session is bound to its active tab by target id and returns to it after a daemon restart; with --pin-tab the binding is strict and a closed bound tab produces a tab_gone error instead of a silent fallback. JSON errors include code: "tab_gone", data.targetId, and optional sanitized data.lastUrl. Batch output carries the recovery object under result. See CDP Mode for the multi-session workflow.
Refs (@e1, etc.) are scoped to the tab that was active when the snapshot ran, so switch tabs first, then snapshot and interact:
agent-browser tab docs # switch first
agent-browser snapshot # refs for docs
agent-browser click @e3 # uses docs's refsDiscarded tab revival
Browsers discard background tabs to save memory, leaving a tab with no renderer to drive. Switching to a discarded tab reactivates it, which reloads the page and resets its unsaved state; the switch result adds "revived": true so the reload is visible rather than silent. A tab whose page is paused by a JavaScript dialog is alive rather than discarded: the switch leaves it untouched and adds "dialogBlocked": true. Resolve the dialog with dialog accept or dialog dismiss and the tab keeps its state. Closing the active tab onto a discarded successor revives it the same way and reports "activeTabRevived": true.
Iframe support
Iframes are detected automatically during snapshots. Iframe nodes are resolved and their content is inlined beneath the iframe element in the snapshot output. Refs assigned to elements inside iframes carry frame context, so click, fill, and other interactions work without manually switching frames.
agent-browser snapshot -i
# @e3 [Iframe] "payment-frame"
# @e4 [input] "Card number"
# @e5 [button] "Pay"
# Interact directly using refs — no frame switch needed
agent-browser fill @e4 "4111111111111111"
agent-browser click @e5
# Or switch frame context for scoped snapshots
agent-browser frame @e3
agent-browser snapshot -i # Only elements inside that iframe
agent-browser frame main # Return to main frameThe frame command accepts element refs (@e3), CSS selectors ("#my-iframe"), or frame name/URL.
Dialogs
agent-browser dialog accept [text] # Accept dialog (with optional prompt text)
agent-browser dialog dismiss # Dismiss dialog
agent-browser dialog status # Check if a dialog is currently openBy default, alert and beforeunload dialogs are automatically accepted so they never block the agent. confirm and prompt dialogs still require explicit handling. Use --no-auto-dialog (or AGENT_BROWSER_NO_AUTO_DIALOG=1) to disable automatic handling.
When a JavaScript dialog (alert, confirm, prompt) is pending, all command responses include a warning field with the dialog type and message.
Streaming
agent-browser stream enable # Start runtime WebSocket streaming on an auto-selected port
agent-browser stream enable --port 9223 # Bind a specific localhost port
agent-browser stream status # Show enabled state, port, browser connection, screencasting
agent-browser stream disable # Stop runtime streaming and remove the .stream metadata fileStreaming is enabled automatically for all sessions. Use these commands to check status, re-enable on a specific port, or disable streaming.
Streaming is separate from file-based recordings. Use Video Recording when you need a saved WebM artifact.
Debug
agent-browser trace start # Start trace
agent-browser trace stop [path] # Stop and save trace
agent-browser profiler start # Start Chrome DevTools profiling
agent-browser profiler stop [path] # Stop and save profile (.json)
agent-browser record start # Start video recording (WebM)
agent-browser record stop # Stop and save video
agent-browser record restart # Stop current and start new recording
agent-browser console # View console messages
agent-browser console --json # JSON output with raw CDP args
agent-browser console --clear # Clear console log
agent-browser errors # View page errors
agent-browser errors --clear # Clear error log
agent-browser highlight <sel> # Highlight element
agent-browser inspect # Open Chrome DevTools for the active pageSee Debugging for console, error, dialog, trace, highlight, and DevTools workflows. See Video Recording for record workflows and Profiler for performance profiles.
Auth vault
agent-browser auth save <name> [opts] # Save auth profile
agent-browser auth login <name> # Login using saved credentials
agent-browser auth login <name> --credential-provider [--item <ref>] [--url ]
# Resolve credentials from plugin
agent-browser auth login <name> --username-selector <s> --password-selector <s> [--submit-selector <s>]
# Override selectors for one login
agent-browser auth list # List saved profiles (names and URLs only)
agent-browser auth show <name> # Show profile metadata (no passwords)
agent-browser auth delete <name> # Delete a saved profile
agent-browser plugin add <ref> # Add a plugin from npm or GitHub
agent-browser plugin list # List configured plugins
agent-browser plugin show <name> # Show one configured plugin
agent-browser plugin run <name> <type> --payload <json>
# Run an arbitrary plugin requestSave options:
--url: login page URL (required)--username: username (required)--password: password (required unless--password-stdin)--password-stdin: read password from stdin (recommended to avoid shell history exposure)--username-selector <sel>: custom CSS selector for username field--password-selector <sel>: custom CSS selector for password field--submit-selector <sel>: custom CSS selector for submit button
auth login navigates with load and then waits for the username/password/submit selectors to appear before interacting. This improves reliability on SPA login pages where fields render after initial page load.
Plugin login options:
--credential-provider: resolve credentials from a configured plugin--item <ref>: provider-specific vault item reference--url: login URL override--username-selector <sel>: selector override for this login--password-selector <sel>: selector override for this login--submit-selector <sel>: selector override for this login
Credential provider plugins run out-of-process over the agent-browser.plugin.v1 stdio JSON protocol. They return credentials to the daemon for a single login and agent-browser does not save those credentials locally.
Other plugin capabilities use the same protocol:
browser.provider: use the plugin with--provider <name>to return a CDP WebSocket URLlaunch.mutate: append local launch args, extensions, or init scripts before Chrome startscommand.run: run arbitrary namespaced requests throughagent-browser plugin run
plugin run is for command.run and custom capabilities. Core capabilities and protocol request types use their dedicated command paths.
echo "pass" | agent-browser auth save github --url https://github.com/login --username user --password-stdin
agent-browser auth login github
agent-browser plugin add agent-browser-plugin-vault --name vault
agent-browser auth login my-app --credential-provider vault --item "My App"
agent-browser --provider cloud-browser open https://example.com
agent-browser plugin run captcha captcha.solve --payload '{"siteKey":"...","url":"https://example.com"}'
agent-browser auth listConfirmation
When --confirm-actions is set, certain action categories return a confirmation_required response instead of executing immediately. Use confirm or deny to approve or reject the action.
agent-browser confirm <confirmation-id> # Approve a pending action
agent-browser deny <confirmation-id> # Deny a pending actionPending confirmations auto-deny after 60 seconds.
agent-browser --confirm-actions eval,download eval "document.title"
# Returns confirmation_required with ID
agent-browser confirm c_8f3a1234State management
agent-browser state save # Save auth state to file
agent-browser state load # Load auth state from file
agent-browser state list # List saved state files
agent-browser state show <file> # Show state summary
agent-browser state rename <old> <new> # Rename state file
agent-browser state clear [name] # Clear states for session name
agent-browser state clear --all # Clear all saved states
agent-browser state clean --older-than <days> # Delete old statesSessions
agent-browser session # Show current session name
agent-browser session list # List active sessionsChrome profiles
agent-browser profiles # List available Chrome profiles
agent-browser profiles --json # List profiles as JSON
agent-browser --profile Default open https://gmail.com # Reuse a profile's login stateDashboard
agent-browser dashboard [start] # Start the dashboard server (default port: 4848)
agent-browser dashboard start --port <n> # Start on a specific port
agent-browser dashboard stop # Stop the dashboard serverOpen the dashboard through http://localhost:4848 or a proxied/forwarded dashboard URL such as https://dashboard.agent-browser.localhost. The browser stays on the dashboard origin; per-session tabs, status, and stream traffic are proxied internally, so session ports do not need to be exposed.
Doctor
Diagnose your install, auto-clean stale daemon files, and optionally repair common problems.
agent-browser doctor # Full diagnosis (env, Chrome, daemons, config, providers, network, launch test)
agent-browser doctor --offline --quick # Local-only, fastest
agent-browser doctor --fix # Also run destructive repairs (reinstall Chrome, purge old state, ...)
agent-browser doctor --webgpu # Also run a live WebGPU render probe (see the WebGPU page)
agent-browser doctor --json # Structured JSON output for agentsExit code is 0 if all checks pass (warnings are fine), 1 if any fail. See the Installation page for the full check catalog.
Chat
Use natural language to control the browser via AI. The chat command translates instructions into agent-browser commands, executes them, and streams the AI response. Requires AI_GATEWAY_API_KEY to be set.
agent-browser chat "open google.com and search for cats" # Single-shot instruction
agent-browser chat # Interactive REPL (type quit to exit)
echo "summarize this page" | agent-browser chat # Piped input
agent-browser -q chat "summarize this page" # Quiet: text only, no tool calls shown
agent-browser -v chat "fill in the login form" # Verbose: show commands and their output
agent-browser --model openai/gpt-4o chat "take a screenshot" # Override the default AI model
agent-browser --json chat "open example.com" # Structured JSON outputChat-specific options:
--model <name> # AI model (or AI_GATEWAY_MODEL env, default: anthropic/claude-sonnet-4.6)
-v, --verbose # Show tool commands and their raw output
-q, --quiet # Show only the AI text response (hide tool calls)Navigation
agent-browser back # Go back
agent-browser forward # Go forward
agent-browser reload # Reload page
agent-browser pushstate # SPA client-side nav; auto-detects window.next.router.push,
# falls back to history.pushState + popstatePre-navigation setup
Some flows need routes, cookies, or init scripts configured before the first navigation (SSR debug, auth on protected origins, etc.). open without a URL launches the browser but stays on about:blank, leaving room to stage state. batch makes it one CLI invocation:
agent-browser batch \
'["open"]' \
'["network","route","*","--abort","--resource-type","script"]' \
'["cookies","set","--curl","cookies.curl","--domain","localhost"]' \
'["navigate","http://localhost:3000/target"]'React / Web Vitals
React commands require --enable react-devtools at launch (installs the React DevTools hook before any page JS runs). vitals and pushstate work on any site.
agent-browser open --enable react-devtools # Launch with React hook installed
agent-browser react tree # Full component tree
agent-browser react inspect <fiberId> # Inspect one component
agent-browser react renders start # Begin fiber render recording
agent-browser react renders stop [--json] # Stop + print profile
agent-browser react suspense [--only-dynamic] [--json] # Suspense boundaries + classifier
# --only-dynamic hides the "static" list
agent-browser vitals [url] [--json] # LCP/CLS/TTFB/FCP/INP + hydrationWorks on any React app (Next.js, Remix, Vite+React, CRA, TanStack Start, React Native Web, etc.). vitals and pushstate are framework-agnostic.
See React & Web Vitals for full command details and examples.
Accessibility audits
Run an embedded axe-core audit against the current page or navigate to a URL first. The vendored engine works without a CDN request and runs under strict page CSP. It runs private partial audits across the page's frame tree and merges serialized results without page messaging, so page-provided window.axe values remain intact and iframe violations retain their frame selector paths. Accessibility audits require a CDP browser and are not available with Safari or iOS WebDriver sessions.
agent-browser a11y # Audit the current page
agent-browser a11y https://example.com # Navigate, then audit
agent-browser a11y --tags wcag2a,wcag2aa # Filter by axe rule tags
agent-browser a11y --selector "#main" # Scope to a subtree
agent-browser a11y https://example.com --json # Structured resultsThe default output lists violations and incomplete checks with impact, rule ID, fix guidance, and failing-node paths. JSON output preserves axe's target selector path arrays, including nested arrays for shadow DOM boundaries and multiple entries for frame boundaries.
Init scripts
agent-browser open --init-script # Register before first navigation (repeatable)
agent-browser addinitscript <js> # Register at runtime (returns identifier)
agent-browser removeinitscript # Remove a previously registered init scriptSee Init Scripts & Extensions for launch-time scripts, runtime scripts, built-in React DevTools, and extensions.
Global options
/* Detailed source-code truncated for AI context efficiency. */See Configuration for config files and environment variables. See Proxy for proxy server, bypass, and credential settings.
Batch execution
Execute multiple commands in a single invocation. Commands can be passed as quoted arguments or piped as JSON via stdin.
# 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| Option | Description |
|---|---|
--bail |
Stop on first error (default: continue all commands) |
--json |
Output results as a JSON array |
MCP server
agent-browser mcp
agent-browser mcp --tools all
agent-browser mcp --tools core,network,reactStarts a Model Context Protocol server over stdio. MCP clients launch this command as a subprocess and exchange newline-delimited JSON-RPC on stdin and stdout. The server defaults to MCP protocol 2025-11-25 and accepts older supported client protocol versions during initialization.
The default tools profile is core, which keeps MCP context small for everyday browser automation. Use --tools all for the full typed CLI parity surface, or combine profiles with commas, such as --tools core,network,react.
Profiles:
core- Default. Navigation, snapshots, interaction, waits, reads, screenshots, JavaScript eval, close, tab basics, and profile discoverynetwork- Network routes, request inspection, HAR, headers, credentials, offlinestate- Cookies, storage, auth, saved state, sessions, profiles, skillsdebug- Console/errors, tracing, profiling, recording, accessibility audits, clipboard, plugins, doctor, dashboard, install, upgrade, chat, diff, batch, confirm/denytabs- Back/forward/reload, tabs, windows, frames, dialogsreact- React tree/inspect/renders/suspense, vitals, pushstatemobile- Viewport/device/geolocation/media, touch, swipe, mouse, keyboardall- Every MCP tool, including the full typed CLI parity surface
Example MCP client config:
{
"mcpServers": {
"agent-browser": {
"command": "agent-browser",
"args": ["mcp"]
}
}
}With --tools all, the server exposes typed tools across the CLI command surface, including navigation, snapshots, input, waits, screenshots/PDF, get/is/find, mouse, network, storage, cookies, tabs, windows, frames, dialogs, tracing, recording, accessibility audits, clipboard, auth, state, iOS, diff, React, vitals, sessions, skills, plugins, doctor, dashboard, install, upgrade, chat, eval, and close.
Common tools include:
agent_browser_tools_profilesagent_browser_openagent_browser_snapshotagent_browser_clickagent_browser_fillagent_browser_typeagent_browser_pressagent_browser_wait_for_selectoragent_browser_screenshotagent_browser_get_urlagent_browser_evalagent_browser_close
Each tool has typed fields such as url, selector, text, key, session, allowedDomains, and idleTimeout, so MCP clients show meaningful approval prompts instead of raw command arrays. The common allowedDomains array maps to --allowed-domains and activates the same WebRTC containment and launch-mode restrictions. The common idleTimeout string maps to --idle-timeout, accepts values such as 30s, 5m, 1h, or raw milliseconds, and accepts 0 to disable idle shutdown. Each tool also accepts extraArgs for advanced CLI flags and exact CLI parity. Tool discovery is paginated and includes read-only/open-world annotations so modern MCP clients can load the large typed surface incrementally.
Tool invocations use the same config files and environment variables as the CLI. Use session in the tool arguments, or set AGENT_BROWSER_SESSION, to isolate browser state.
Command chaining
Chain commands with && in a single shell invocation. The browser persists via a background daemon, so chaining works naturally and is more efficient than separate calls:
agent-browser open example.com && agent-browser wait --load networkidle && agent-browser snapshot -i
agent-browser fill @e1 "[email protected]" && agent-browser fill @e2 "pass" && agent-browser click @e3
agent-browser open example.com && agent-browser wait --load networkidle && agent-browser screenshot page.pngUse && when you don't need to read intermediate output. Run commands separately when you need to parse output first (e.g., snapshot to discover refs, then interact with those refs).
Local files
Open local files (PDFs, HTML) using file:// URLs:
agent-browser --allow-file-access open file:///path/to/document.pdf
agent-browser --allow-file-access open file:///path/to/page.html
agent-browser screenshot output.pngThe --allow-file-access flag enables JavaScript to access other local files. Chromium only.
See Files & Clipboard for local files, uploads, downloads, screenshots, PDFs, and clipboard workflows.
File: docs/src/app/changelog/page.mdx
Changelog
v0.34.0
August 10, 2026
New Features
- Added persistent session-to-tab binding for shared Chrome sessions. Named sessions connected through
--cdpor--auto-connectnow remember their CDP target across commands and daemon restarts, and CDP target ids can be used directly as tab references. Start each session with--pin-tabto make the binding strict, so a tab closed externally returns a stabletab_goneerror instead of silently adopting a neighboring tab. JSON output includesdata.targetIdand an optional sanitizeddata.lastUrl; batch exposes the same recovery data underresult(#1589)
Improvements
- Added a Remote Agent Browser provider guide covering Vercel authentication, disposable and stable sessions, custom VCR images, snapshots, and live-view URLs (#1648)
Bug Fixes
- Fixed parallel sessions sharing one Chrome hijacking each other's tabs. Event-discovered targets no longer steal a pinned session's active tab, re-attach restores the persisted target instead of selecting index 0, and preliminary plus existing-daemon
--cdpand--auto-connectpaths preserve explicit pin enable and disable. Agent skill guidance now requires a named--sessionbefore the first command (#1589) - Fixed
agent-browser doctorhanging on Chrome version detection. Windows reads the version from the executable resource table without spawning Chrome; other platforms bound the version subprocess with a deadline, kill, and reap so inherited output handles cannot block forever or leave an orphan browser (#1641)
v0.33.2
July 31, 2026
New Features
- Added input priority and per-client delivery settings to the stream server: each WebSocket connection now splits into a reader task and a writer loop, so clicks and keystrokes dispatch to the browser without queueing behind a frame write. Adds a per-client
{"type":"config","maxFps":N}cap (1 to 120,0uncapped) and opt-in ack pacing via{"type":"config","pacing":"ack"}with{"type":"ack","seq":N}, which keeps one frame in flight so a stalled client never drains a backlog. Both settings can also be declared on the connection URL (?pacing=ack&maxFps=10), the only way to cover the opening frame. Every frame now carries a monotonicseq(#1594) - Added configurable stream encoding: frames were hardcoded to jpeg quality 80 at the session viewport, so frame rate was the only bandwidth lever.
AGENT_BROWSER_STREAM_QUALITY,AGENT_BROWSER_STREAM_MAX_WIDTHandAGENT_BROWSER_STREAM_MAX_HEIGHTare read once per daemon and cut bytes without dropping frames: on a busy page at 1280x720, quality 20 takes a frame from 54 KB to 25 KB, and quality 20 at 640x360 takes it to 9 KB, frame rate unchanged in both. Width and height default to the session viewport, so a larger viewport is never downscaled unless both are set (#1626)
Behavior Changes
- Frame delivery is now latest-wins. The stream server holds only the newest frame and reads it at send time, so frames produced while an earlier one is still being written are skipped. A client that assumed it received every frame from the WebSocket now receives fewer. Nothing in this repo consumes the stream that way, since
recordcaptures through CDP and the dashboard is a viewer, so this affects external consumers only (#1594) metadata.timestampnow carries a real value. It was always 0, because CDP sends the capture time as a float in seconds and the code read it as an integer. It is now epoch milliseconds, so a client can measure how stale the frame it is drawing is. A client that treated 0 as unknown is unaffected (#1594)
Bug Fixes
- Fixed keyboard input over the stream, which worked in none of the three shapes the docs publish: an absent
key,code, ortextreached CDP as an explicit null, which rejects the whole command, so every key release and every non-printable key was silently dropped, the dashboard's own payloads included (#1594) - Fixed click latency behind mouse movement: input dispatch awaited Chrome's reply before reading the next message, so a click sat one round trip behind every queued mouse move. After a 300-event sweep a click landed 2471ms late; it now lands in 6ms (#1627)
- Fixed
stream disablereturning while a slow client's input reader was still running (#1594)
v0.33.1
July 28, 2026
Behavior Changes
- The daemon now ships a default idle timeout of 1 hour: after an hour with no commands or dashboard input it saves configured restore state, closes the browser, and exits, so integrations that die without calling
closeno longer leak the daemon and its Chrome tree indefinitely. Sessions without--restoreor another restore key discard transient browser state and open tabs when they shut down. SetAGENT_BROWSER_IDLE_TIMEOUT_MS=0to restore the old always-persist behavior, or any other value to tune it. Dashboard mouse, keyboard, and touch input reset the timer. The default never closes headed browsers, including Safari and iOS WebDriver sessions, or user-attached browsers that may be in direct human use. Provider-owned cloud browsers remain eligible for cleanup, and an explicitly configured timeout applies to all browsers, as before (#1605)
Bug Fixes
- Fixed tab recovery and selection to avoid daemon hangs on Memory Saver-discarded tabs by selecting a live renderer on CDP connect, reviving tabs on switch or after close, treating dialog-blocked tabs as live, preserving refs on rejected operations, and surfacing recovery state across CLI, JSON, and MCP output (#1543)
- Fixed a11y selector errors to report invalid CSS selectors cleanly instead of exposing raw browser evaluation stack traces in text and JSON output (#1604)
v0.33.0
July 23, 2026
New Features
- Added axe-core accessibility audits with
agent-browser a11y [url], WCAG tag filtering, selector scoping, iframe-aware text and JSON results, an embedded offline and CSP-safe audit engine, and a matching MCP tool (#1596)
v0.32.4
July 22, 2026
Bug Fixes
- Fixed find role to match implicit ARIA roles and browser-computed accessible names through the accessibility tree, so semantic elements like
<h2>(heading) and `` (list) resolve, with case-insensitive substring name matching that mirrors Playwright'sgetByRole(#1552) - Fixed element-not-found errors to preserve the locator detail (selector, role, name, or index) instead of flattening every miss into one generic message, and aligned the advertised
findactions with the set the dispatcher actually accepts (#1553)
v0.32.3
July 19, 2026
New Features
- Added HAR response body capture with text bodies embedded by default and configurable
all,text, andnonecontent modes across the CLI and MCP surfaces (#1578) - Added a derive-client skill for recording browser traffic and generating reusable API clients from HAR request and response data (#1578)
v0.32.2
July 17, 2026
Improvements
- Updated eve extension packaging for eve 0.25.1, adopting the new source and dist extension manifest format, updating the eve example to stable AI SDK releases, and keeping extension tests aligned with eve's scoped config registry (#1570)
v0.32.1
July 16, 2026
Improvements
- Widened eve compatibility for
@agent-browser/eveto accept eve 0.23 and future major releases without peer-resolution warnings (#1563)
Documentation
- Standardized eve branding to use lowercase styling across the docs, examples, package readmes, and release notes (#1557)
v0.32.0
July 15, 2026
New Features
- eve extension - Added
@agent-browser/eve, an eve extension that mounts the agent-browser tool set with namespaced browser tools, sandbox bootstrap helpers, docs, examples, CI, and release packaging (#1547)
Security
- Hardened domain allowlists by blocking WebRTC bypasses, applying network containment across launch modes, workers, popups, restored state, and reused daemon sessions, rejecting unsafe startup arguments, and adding Chrome regression coverage (#1546)
Bug Fixes
- Fixed completed-page waits so load and DOMContentLoaded waits resolve immediately when the current document is already ready, with structured eve wait timeout handling and focused coverage (#1554)
v0.31.2
July 13, 2026
New Features
- WebGPU launch preset - Added
--webgpuacross the CLI, config, environment, and MCP surfaces, with hardware backends on macOS and Windows, software Vulkan on Linux, automatic Xvfb for displayless headed sessions, and adoctor --webgpurender and screenshot probe (#1529)
Improvements
- Added periodic restore-state autosaves while the browser remains open, preserving recent state after a browser window is closed by hand and capturing background page changes while honoring the restore save policy. The interval is configurable with
AGENT_BROWSER_AUTOSAVE_INTERVAL_MS(#1509)
v0.31.1
June 26, 2026
Bug Fixes
- Fixed the React renderer so it picks the react-dom renderer instead of hardcoding renderer id 1, which prevented reading an empty tree on Next.js 16.3 Turbopack (#1491)
v0.31.0
June 25, 2026
New Features
- Restore workflow - Added
--restore,--restore-save, restore validation flags, worktree-scopedsession id,session info, and--namespaceso agent runs can use stable, isolated, automatically restored browser state without managing state files by hand (#1486)
Improvements
- Hardened session lifecycle handling with explicit daemon and browser compatibility checks, lifecycle status output, MCP support for restore options, and safer auto-save behavior that avoids overwriting good state after a failed restore or failed validation (#1486)
Bug Fixes
- Fixed restore lifecycle edge cases around switching restore keys with a live browser, daemon configuration startup races, launch mode validation, and clearing restore failures after an explicit state load (#1486)
v0.30.1
June 24, 2026
Bug Fixes
- Fixed URL waits so
wait --urlandwaitforurlhonor glob patterns such as**/dashboardagainst the full active URL (#1483)
v0.30.0
June 24, 2026
New Features
- Read command - Added
agent-browser read [url]and the matching MCP tool for agent-readable text extraction. URL reads prefer Markdown, try.mdand nearbyllms.txtdocs, support outlines, filters, raw and JSON output, headers, and domain/output safeguards; omitting the URL reads the rendered active tab DOM with current browser state (#1480)
v0.29.1
June 20, 2026
Improvements
- Defaulted sandbox system dependency installs so the eve and Vercel sandbox helpers install Chromium's required libraries unless explicitly disabled, making first-run sandbox setup simpler (#1469)
v0.29.0
June 20, 2026
New Features
- Sandbox package - Added
@agent-browser/sandboxwith shared, eve, and Vercel Sandbox helpers, example projects, and docs for running agent-browser in hosted sandbox environments (#1465)
Improvements
- Updated sandbox release flow so the new package stays version-synced with the CLI release and publishes from the correct workspace path (#1465)
- Reflowed documentation prose across the README, docs site, examples, and skills so Markdown and MDX wrap naturally in editors and renderers (#1466)
v0.28.0
June 16, 2026
New Features
- MCP server - Added
agent-browser mcp, a stdio Model Context Protocol server with typed tools, paginated discovery, protocol negotiation, and startup tool profiles. The defaultcoreprofile keeps context small, while--tools allexposes full CLI parity and composed profiles such ascore,network,reactare supported (#1454) - Plugin system - Added out-of-process plugin support over the
agent-browser.plugin.v1stdio protocol, withplugin add/list/show/run, manifest discovery, npm and GitHub refs, credential providers, browser provider plugins, launch mutators, custom command capabilities, config and env registry support, and capability-scoped policy gates (#1452)
Infrastructure
- Added context footprint eval coverage for CLI skills, MCP core, and MCP full-profile surfaces, plus MCP parity tests to keep tool behavior aligned with the CLI (#1454)
v0.27.3
June 12, 2026
Bug Fixes
- Fixed Windows ARM64 installs by falling back to the Windows x64 binary during postinstall, avoiding failed downloads for a native ARM64 artifact that is not published (#1269)
v0.27.2
June 10, 2026
Bug Fixes
- Fixed click reliability by scrolling off-viewport elements into view before resolving coordinates, handling JavaScript dialogs promptly, recovering mouse state after dialog-opening clicks, and detecting click interception by overlays before dispatching input (#1432, #1434)
- Fixed frame-scoped selectors and waits so CSS-selector actions and
waitrespect the selected iframe, including cross-process iframes, with translated click coordinates (#1432) - Fixed wait timeout handling so the documented 25s default is used,
--timeoutis honored across wait variants, and long waits receive an appropriate client read budget (#1432) - Fixed agent-facing form commands so
find labelmatchesaria-labelandaria-labelledby,selecterrors when no option matches, andtypeparses--clearand--delayinstead of typing them as text (#1432)
Improvements
- Cut warm CLI command latency from about 150ms to about 1ms by removing the unconditional daemon settle sleep and retrying once when a stale daemon socket is discovered (#1432)
- Extended daemon respawn and retry handling to batch commands so batches recover from a daemon exit after the initial liveness check (#1432)
Infrastructure
- Pinned GNU Linux release artifacts to glibc 2.28 with zigbuild, added a release guard for newer GLIBC symbols, and aligned Docker release helpers with the pinned target (#1417)
v0.27.1
June 1, 2026
Improvements
- Improved
vitalscommand output formatting for better readability (#1404)
Documentation
- Surfaced agent-browser feature coverage in documentation (#1403)
v0.27.0
May 7, 2026
New Features
- React introspection - First-class React DevTools integration with new
react tree,react inspect <fiberId>,react renders start|stop, andreact suspensecommands for full component-tree visibility, per-fiber props/hooks/state inspection, render profiling with mount/re-render counts and change details, and Suspense boundary classification with root-cause grouping and recommendations. React DevTools hook is vendored (MIT) and embedded in the binary with zero runtime dependencies (#1257) - Web Vitals - New
vitals [url]command that reports Core Web Vitals (LCP, CLS, TTFB, FCP, INP) plus React hydration phases for any page (#1257) - SPA navigation - New
pushstatecommand for client-side SPA navigations without a full page load (#1257) - Init scripts and feature flags - New
--init-scriptflag (repeatable; envAGENT_BROWSER_INIT_SCRIPTS) to register scripts before first navigation, and--enable <feature>flag (repeatable; envAGENT_BROWSER_ENABLE) for built-in init scripts such asreact-devtools(#1257) - Network route resource type filter -
network routenow accepts--resource-type <csv>to filter intercepted requests by CDP resource type (#1257) - cURL cookie import -
cookies set --curl <file>auto-detects JSON, cURL, and Cookie-header formats for bulk cookie import (#1257) - Dashboard proxy support - The observability dashboard now works from proxied origins via a same-origin proxy, enabling deployment behind reverse proxies and path-based routing (#1111)
Bug Fixes
- Fixed
doctorcommand generating duplicate check ids when called multiple times in the same process (#1330)
Infrastructure
- Switched npm publishing to trusted publishing via GitHub Actions OIDC, removing the need for manually managed npm tokens (#1273)
v0.26.0
April 16, 2026
New Features
doctorcommand - Addedagent-browser doctorfor one-shot diagnosis of an install. Checks environment, Chrome, running daemons, config files, security, providers, and network connectivity; auto-cleans stale daemon sidecar files on every run; and performs a live headless launch test. Supports--offlineto skip network probes,--quickto skip the launch test,--fixfor opt-in repairs (install missing Chrome, close version-mismatched daemons, prune expired state files), and--jsonfor structured output (#1254)- Stable tab ids and labels - Tabs now have stable string ids like
t1,t2,t3that don't shift when other tabs close or popups appear. Tabs can be created with a memorable label viatab new --label <name> [], and labels are interchangeable witht<N>ids everywhere a tab ref is accepted (tab,tab close). Bare-integer input is rejected with a teaching error so agents can't mistake stable handles for positional indices (#892, #1249, #1250) coreskill - Renamed the built-inagent-browserskill tocoreand replaced its ~40-line discovery stub with a ~420-line usage guide covering the core snapshot-ref-act loop, reading, interacting, waiting, common workflows, troubleshooting, and global flags.agent-browser skills get corenow returns content agents can use directly;--fulladds references and templates. Added ahidden:frontmatter flag so the originalagent-browserstub stays reachable fornpx skills adddiscovery without pollutingskills list(#1253)- JSON Schema for config files - Added
agent-browser.schema.jsondescribing every config option with types and descriptions, enabling IDE autocomplete and validation when referenced via$schemainagent-browser.jsonor~/.agent-browser/config.json. The schema is served from the docs site athttps://agent-browser.dev/schema.json(#1242, #1248)
Bug Fixes
- Fixed
--state/AGENT_BROWSER_STATEnot actually loading saved browser state (cookies and localStorage) at launch. The flag had been fully plumbed through parsing, env propagation, and validation since the native Rust rewrite, but the load step was never wired up. Storage state now loads after launch across all four paths: explicit launch, auto-connect, provider, and local Chrome (#1241)
Documentation
--helpoutput now shows the skills section first so agents discoverskills get core(the canonical usage guide) before the core command list (#1251)
v0.25.5
April 16, 2026
Bug Fixes
- Fixed
--auto-connectCDP discovery preferring HTTP endpoint discovery over the DevToolsActivePort websocket path, which could fail on some setups. The CLI now reads the websocket path from DevToolsActivePort first and only falls back to HTTP discovery (#1218) - Fixed recording context viewport not inheriting the active viewport dimensions, causing recordings to use default resolution instead of the configured viewport (#1208)
- Fixed
get boxandget stylesprinting no data in text mode (#1231, #1233) - Fixed active page changing when closing or removing earlier tabs. The previously focused page is now preserved correctly (#1220)
v0.25.4
April 12, 2026
New Features
skillscommand - Addedagent-browser skillscommand for discovering and installing agent skills, with built-in evaluation support for testing skills against live browser sessions (#1225, #1227)
Bug Fixes
- Fixed custom viewport dimensions not being used in streaming frame metadata and image resolution (#1033)
- Fixed
--ignore-https-errorsnot being re-applied to recording contexts, causing TLS errors during screen recordings (#1178) - Fixed duplicate option numbering in the auth skill documentation (#1161)
Documentation
- The docs site header now dynamically fetches the GitHub star count (#1202)
v0.25.3
April 7, 2026
Bug Fixes
- Fixed hidden radio/checkbox inputs missing from snapshot refs when a
<label>wraps adisplay:noneor. Chrome excludes these inputs from the accessibility tree entirely, making it impossible for AI agents to identify radio buttons and checkboxes via refs. Hidden inputs inside elements are now detected during cursor-interactive scanning and their parent nodes are promoted to the correct role with proper name and checked state (#1085)
Documentation
- Added clickable heading anchors to the docs site, making it easy to link directly to any section (#1175)
v0.25.2
April 6, 2026
Bug Fixes
- Fixed Chrome being killed after ~10s idle on Linux caused by
PR_SET_PDEATHSIGtracking the blocking thread that spawned Chrome rather than the daemon process. When Tokio reaped the idle thread, the kernel sent SIGKILL to Chrome even though the daemon was still alive (#1157, #1173)
v0.25.1
April 6, 2026
Improvements
- Embedded dashboard - The observability dashboard is now bundled directly into the CLI binary using
rust-embed, eliminating the need fordashboard install. The dashboard is available immediately after installing agent-browser (#1169)
v0.25.0
April 6, 2026
New Features
- AI chat command - Added
chatcommand for AI-powered browser automation. Supports single-shot mode (chat "open google.com") and an interactive REPL. The AI agent can execute any agent-browser command via tool calls. RequiresAI_GATEWAY_API_KEY. Configure the model with--modelorAI_GATEWAY_MODEL(#1160, #1163) - Dashboard AI chat - The observability dashboard now includes a built-in AI chat interface for conversational browser control alongside live session views (#1160, #1163)
snapshot --urls- New-u/--urlsflag to include href URLs for link elements in snapshot output, giving agents direct access to link targets without additional queries (#1160)- Batch argument mode - The
batchcommand now accepts commands as inline arguments in addition to reading from stdin, simplifying single-invocation multi-command workflows (#1160)
Bug Fixes
- Fixed
getByRolematching wrong elements (e.g.<link>stylesheet elements instead of<a>anchors) by rewriting the implementation to use the CDP accessibility tree with ref-based element resolution instead of CSS selectors (#1145) - Fixed
uploadcommand not supporting accessibility tree refs (@eN) for file upload element selection (#1156) - Fixed
AGENT_BROWSER_DEFAULT_TIMEOUTnot being applied towaitcommands. The environment variable now propagates to all wait variants (wait,wait --url,wait --text,wait --load,wait --fn,wait --download) (#1153) - Fixed dashboard download error handling with improved retry logic for more reliable dashboard installation (#1154)
v0.24.1
April 4, 2026
New Features
- Chrome profile login state reuse -
--profile <name>now resolves Chrome profile names (e.g.Default,Profile 1) and copies the profile to a temp directory to reuse login state, cookies, and extensions without modifying the original. Addedprofilescommand to list available Chrome profiles with--jsonsupport (#1131)
Bug Fixes
- Fixed
--ignore-https-errorsnot passing--ignore-certificate-errorsas a Chrome launch flag, causing TLS errors likeERR_SSL_PROTOCOL_ERRORto be rejected at the network layer before CDP could intervene (#1132) - Fixed orphaned Chrome processes on daemon exit by spawning Chrome in its own process group and killing the entire group on shutdown. On Linux,
PR_SET_PDEATHSIGensures Chrome is killed even if the daemon is OOM-killed (#1137) - Fixed CDP attach hang on Chrome 144+ when connecting to real browser sessions. Targets paused waiting for the debugger after attach are now resumed with
Runtime.runIfWaitingForDebugger(#1133) - Fixed stale daemon after upgrade silently reusing the old daemon process with broken CDP behavior. The daemon now writes a
.versionsidecar file and auto-restarts on version mismatch (#1134) - Fixed stale daemon/socket recovery where
close --allfailed to clean up zombie daemons and stale files. Unreachable daemons are now force-killed and orphaned socket/pid files are removed (#1136) - Fixed idle timeout not being respected because the sleep future was recreated on every select loop iteration, preventing the deadline from being reached (#1110)
- Fixed browser not relaunching when launch options change (e.g. adding extensions to
config.json) between consecutive launch commands (#996) - Fixed
auto_launch()not honouringAGENT_BROWSER_PROVIDERfor cloud providers, causing non-launch commands to fall back to local Chrome instead of connecting via the provider API (#1126) - Fixed HAR capture missing API requests under heavy traffic by increasing the CDP broadcast buffer from 256 to 4096 events, reducing the drain interval from 500ms to 100ms, and enabling network tracking in cross-origin iframes (#1135)
v0.24.0
April 2, 2026
New Features
- AWS Bedrock AgentCore provider - Added AWS Bedrock AgentCore as a cloud browser provider. Connect with
--provider agentcoreorAGENT_BROWSER_PROVIDER=agentcore. Uses lightweight manual SigV4 signing for authentication with support for the full AWS credential provider chain (environment variables, AWS CLI, SSO, IAM roles). Configure withAGENTCORE_REGION,AGENTCORE_PROFILE_ID, andAGENTCORE_BROWSER_IDenvironment variables. Returns session ID and Live View URL in the launch response (#397)
Documentation
- Added AgentCore provider page to docs site, README options table, SKILL.md, and dashboard provider icons (#1120)
v0.23.4
March 31, 2026
Bug Fixes
- Fixed daemon hang on Linux caused by a
waitpid(-1)race condition in the SIGCHLD handler that stole exit statuses from Rust'sChildhandles, leaving the daemon in a broken state. Replaced the global signal handler with targeted crash detection via the existing drain interval (#1098)
v0.23.3
March 30, 2026
Bug Fixes
- Fixed drag and drop not working because
mouseMovedevents during the drag omitted thebuttonsbitmask, causing the browser to seeevent.buttons === 0and never firedragstart/dragover/drop(#1087)
v0.23.2
March 30, 2026
New Features
- Dashboard session creation - Sessions can now be created directly from the dashboard UI. A new session dialog provides a unified selector grid for local engines (Chrome, Lightpanda) and cloud providers (Browserbase, Browserless, Browser Use, Kernel) with async creation, loading state, and error display (#1092)
- Dashboard provider icons - The session sidebar now shows the provider or engine icon for each session, making it easy to identify which backend a session is using (#1092)
Bug Fixes
- Fixed Browser Use provider using an intermediate API call instead of connecting directly via WSS, which caused connection failures (#1092)
- Fixed Browserbase provider not sending an explicit JSON body and
Content-Typeheader, causing session creation to fail (#1092) - Fixed provider navigation hanging because
wait_for_lifecyclewaited for page load events that remote providers may not emit. Navigation with--providernow automatically setswaitUntil=none(#1092) - Fixed remote CDP connections timing out by increasing the CDP connect timeout from 10s to 25s for cloud providers (#1092)
- Fixed zombie daemon processes not being cleaned up when a provider connection fails during session creation from the dashboard (#1092)
v0.23.1
March 30, 2026
New Features
- Auto-dismissal for alert and beforeunload dialogs - JavaScript
alert()andbeforeunloaddialogs are now automatically accepted to prevent the agent from blocking indefinitely.confirmandpromptdialogs still require explicitdialog accept/dismisscommands. Disable with--no-auto-dialogflag orAGENT_BROWSER_NO_AUTO_DIALOGenvironment variable (#1075) - Puppeteer browser cache fallback - Chrome discovery now searches
~/.cache/puppeteer/chrome/(orPUPPETEER_CACHE_DIR) for Chrome binaries, so users with an existing Puppeteer installation can use agent-browser without a separate install step (#1088) - Console output improvements -
console.logof objects now shows the actual object preview (e.g.{userId: "abc", count: 42}) instead of"Object". JSON output includes a rawargsarray for programmatic access (#1040)
Bug Fixes
- Fixed same-document navigation (e.g. SPA hash routing) hanging forever because
wait_for_lifecyclewaited for aPage.loadEventFiredthat never fires on same-document navigations (#1059) - Fixed save_state only capturing cookies and localStorage for the current origin, silently dropping cross-domain data (e.g. SSO/CAS auth cookies). Now uses
Network.getAllCookiesand collects localStorage from all visited origins (#1064) - Fixed externally opened tabs not appearing in
tab listwhen using--cdpmode. Tabs opened by the user or another CDP client are now detected and tracked (#1042) - Fixed dashboard server not picking up installed files without a restart.
dashboard installnow takes effect immediately on a running server (#1066) - Fixed Windows Chrome extraction failing because zip path normalization used forward slashes while the extraction code expected backslashes (#1088)
v0.23.0
March 27, 2026
New Features
- Observability dashboard - Added a local web UI (
dashboard) that shows live browser viewports, command activity feeds, console output, network requests, storage, and extensions for all sessions. Manage it withdashboard start,dashboard stop, anddashboard install. The dashboard runs as a standalone background process and all sessions stream to it automatically (#1034)
agent-browser dashboard install
agent-browser dashboard start
agent-browser open example.com # session appears in dashboard
agent-browser dashboard stop- Runtime stream management - Added
stream enable,stream disable, andstream statuscommands to control WebSocket streaming at runtime. Streaming is now always enabled by default;AGENT_BROWSER_STREAM_PORToverrides the port instead of toggling the feature (#951) - Close all sessions - Added
close --allflag to close every active browser session at once
Bug Fixes
- Fixed Lightpanda engine compatibility (#1050)
- Fixed Windows daemon TCP bind failing when Hyper-V reserves the port by falling back to an OS-assigned port and writing it to a
.portfile (#1041) - Fixed Windows dashboard relay using Unix socket instead of TCP (#1038)
- Fixed radio/checkbox elements being dropped from compact snapshot tree because the
ref=check required a leading[that those elements lack (#1008)
v0.22.3
March 25, 2026
Bug Fixes
- Re-apply download behavior on recording context - Fixed an issue where downloads were silently dropped in recording contexts because
Browser.setDownloadBehaviorset at launch only applied to the default context. The download behavior is now re-applied when a new recording context is created (#1019) - Reap zombie Chrome process and fast-detect crash for auto-restart - Added a non-blocking process-exit check before attempting CDP connection checks. This prevents a 3-second CDP timeout when Chrome has already crashed or exited, enabling faster detection and auto-restart of the browser (#1023)
- Route keyboard
typethrough text input - Fixed keyboardtypesubaction to correctly route through the text input handler, and added support for aninsertTextsubaction usingInput.insertText(#1014) - Handle
--clearflag inconsolecommand - Fixed theconsolecommand to accept and process aclearparameter, allowing console event history to be cleared (#1015)
v0.22.2
March 24, 2026
New Features
- Dialog status command - Added
dialog statuscommand to check whether a JavaScript dialog is currently open (#999) - Dialog warning field - Command responses now include a
warningfield when a JavaScript dialog is pending, indicating the dialog type and message (#999)
Improvements
- Standard proxy environment variables - The proxy setting now automatically falls back to standard environment variables (
HTTP_PROXY,HTTPS_PROXY,ALL_PROXY, and their lowercase variants), withNO_PROXY/no_proxyrespected for bypass rules (#1000) - Font packages for
--with-deps- Installing with--with-depsnow includes CJK and emoji font packages on Linux (Debian, RPM, and yum-based distros) to prevent missing glyphs when rendering international content (#1002)
Bug Fixes
- Fixed
state showalways failing with "Missing 'path' parameter" due to a mismatched JSON field name (#994) - Fixed
consolecommand returning onlyDonedue to a JSON field name mismatch in the response (#986) - Fixed browser-domain CDP events being dropped during downloads due to a
sessionIdmismatch (#998) - Fixed proxy authentication by handling credentials via the CDP
Fetch.authRequiredevent rather than passing them inline (#1000)
v0.22.1
March 24, 2026
Bug Fixes
- Fixed modifier key chords (e.g.
Control+a,Shift+Enter,Control+Shift+a) not being handled correctly when usingpress. Modifier keys are now parsed and forwarded as CDP modifier bitmasks rather than treated as part of the key name (#980) - Fixed query parameters being dropped from
--cdpHTTP URLs (e.g.http://host:9222?mode=Hello). Query strings are now preserved and forwarded to the remote CDP endpoint (#982)
v0.22.0
March 23, 2026
New Features
- Cross-origin iframe support - Added support for snapshots and interactions within cross-origin iframes via
Target.setAutoAttach(#949) - Network request detail and filtering - Added
network request <requestId>command to view full request/response detail, and new filtering options fornetwork requestsincluding--type(e.g.xhr,fetch),--method(e.g.POST), and--status(e.g.2xx,400-499) (#935)
agent-browser network requests --type xhr,fetch --method POST
agent-browser network request <requestId>Improvements
- Snapshot usability - Reduced AI cognitive load by filtering semantic noise from snapshot output; cursor-interactive elements are now included by default, making the
-Cflag unnecessary (#968) - Upgrade command - Improved robustness of installation method detection in the upgrade command (#960)
- Target tracking - Enhanced target tracking and page information handling for more reliable browser session management (#969)
Bug Fixes
- Fixed viewport dimensions being reported incorrectly in streaming status messages and screencast (#952)
- Fixed
findcommand flags such as--exactand--nameleaking into fill values when used with fill actions (#955) - Fixed state commands incorrectly starting the daemon when no
session_nameis provided (#677, #964) - Fixed auto-connect triggering when the daemon is already running, preventing duplicate connections (#971)
- Fixed Enter key press not working by adding a text field to
keyDownevents (#972) - Fixed download command to properly handle absolute paths and correctly click target elements (#970)
Breaking Changes
- The
-C/--cursorflag forsnapshotis deprecated; cursor-interactive elements are now included by default and the flag has no additional effect (#968)
v0.21.4
March 20, 2026
Bug Fixes
- Auth login readiness -
agent-browser auth loginnow navigates withload, waits for usable login form selectors, and uses staged username detection (targeted email/username selectors first, then broad text-input fallback). This reduces SPA timing failures, avoids false matches on unrelated text fields, and preventsnetworkidlehangs on pages with continuous background requests.
v0.21.3
March 20, 2026
Bug Fixes
- WebSocket keepalive for remote browsers - Added WebSocket Ping frames and TCP
SO_KEEPALIVEto prevent CDP connections from being silently dropped by intermediate proxies during idle periods (#936) - XPath selector support - Fixed element resolution to correctly handle the
xpath=selector prefix (#908)
Performance
- Fast-path for identical snapshots - Short-circuits the Myers diff algorithm when comparing a snapshot to itself, avoiding unnecessary computation in retry and loop workloads (#922)
v0.21.2
March 18, 2026
Bug Fixes
- Deduplicate text content in snapshots - Fixed an issue where duplicate text content appeared in page snapshots (#909)
- Native mouse drag state - Fixed incorrect raw native mouse drag state not being properly tracked across
down,move, andupevents (#872) - Chrome headless launch failures - Fixed browser launch failures caused by the
--enable-unsafe-swiftshaderflag in Chrome headless mode (#915) - Origin-scoped
--headerspersistence - Restored correct persistence of origin-scoped headers set via--headersacross navigation commands (#894) - Relative URLs in WebSocket domain filter - Fixed handling of relative URLs in the WebSocket domain filter script (#624)
v0.21.1
March 18, 2026
New Features
- HAR 1.2 network capture - Added commands to capture and export network traffic in HAR 1.2 format, including accurate request/response timing, headers, body sizes, and resource types sourced from Chrome DevTools Protocol events (#864)
- Built-in
upgradecommand - Addedagent-browser upgradeto self-update the CLI; automatically detects your installation method (npm, Homebrew, or Cargo) and runs the appropriate update command (#898)
agent-browser upgradev0.21.0
March 17, 2026
New Commands
batch-- Execute multiple commands in a single invocation. Pipe a JSON array of string arrays to stdin and receive results sequentially. Supports--bailto stop on first error and--jsonfor structured output.
echo '[["open","example.com"],["snapshot"]]' | agent-browser batch --jsonnetwork har start/stop-- Capture and export network traffic in HAR 1.2 format.
agent-browser network har start
# ... interact with the page ...
agent-browser network har stop ./trace.harNew Features
- iframe support -- CLI interactions and snapshots now traverse into iframe content, enabling automation of cross-frame pages.
--idle-timeoutflag -- Automatically shut down the daemon after a period of inactivity. Accepts human-friendly formats such as10s,3m,1h, or raw milliseconds. Also available asAGENT_BROWSER_IDLE_TIMEOUT_MS.- Cursor-interactive elements in snapshots -- Cursor-interactive elements are now embedded directly into the snapshot tree for richer context.
- Brave Browser auto-connect -- Auto-discovery of Brave Browser for CDP connections on macOS, Linux, and Windows.
- linux-musl (Alpine) builds -- Pre-built binaries for linux-musl targeting both x64 and arm64, enabling native support for Alpine Linux and other musl-based distributions.
- WebSocket fallback for CDP discovery -- When HTTP-based CDP endpoint discovery fails, the CLI now falls back to a WebSocket connection automatically.
Improvements
--full/-frefactored to command-level flag -- Moved from a global flag to a per-command flag for clearer scoping.- Enhanced Chrome launch -- Added
--user-data-dirsupport and configurable launch timeout for more reliable browser startup. Chrome now retries launching up to 3 times on transient startup failures. - Consecutive
--auto-connectcommands -- Multiple consecutive auto-connect commands no longer require a full browser relaunch; external connections are correctly identified and reused. - Batched CDP calls --
snapshot -Candscreenshot --annotatenow batch CDP calls instead of issuing sequential round-trips per element, preventing timeouts on high-latency WSS connections.
Bug Fixes
- Fixed remote CDP (WSS) snapshot and screenshot hangs by removing WebSocket message/frame size limits
- Fixed Material Design
check/uncheckfalling back to JS.click()for overlay-based controls - Fixed punctuation characters being dropped in the
typecommand - Fixed WebSocket streaming by keeping the StreamServer instance alive
- Filtered internal Chrome targets (
chrome://,devtools://) from auto-connect discovery - Fixed
snapshot --selectorscoping to the matched element's subtree - Fixed network idle detection returning prematurely for cached pages
- Fixed daemon panic on broken stderr pipe during Chrome launch
- Fixed broadcast channel lag being treated as stream closure
- Fixed daemon liveness detection for PID namespace isolation (e.g.
unshare) - Fixed Ubuntu dependency install accidentally removing system packages
v0.20.0
March 13, 2026
Full Native Rust
agent-browser is now 100% native Rust. The Node.js/Playwright daemon has been completely removed -- no Node.js runtime or Playwright dependency is required to run the daemon. The Rust native daemon is now the only implementation.
| Metric | Node.js | Rust | |
|---|---|---|---|
| Cold start | 1002ms | 617ms | 1.6x faster |
| Daemon memory | 143 MB | 8 MB | 18x less |
| Install size | 710 MB | 7 MB | 99x smaller |
npm install agent-browser # 7 MB install
agent-browser install # download Chrome
agent-browser open example.com
agent-browser snapshotImprovements
- Benchmarks -- Added benchmark suite for comparing native vs Node.js daemon performance across cold start, warm start, memory, and install size.
- Chromium installer hardened -- Fixed zip path traversal vulnerability in Chrome for Testing installer.
Bug Fixes
- Fixed
--headed falseflag not being respected in CLI - Fixed "not found" error pattern in
to_ai_friendly_errorincorrectly catching non-element errors - Fixed storage local key lookup parsing and text output
- Fixed Lightpanda engine launch with release binaries
- Hardened Lightpanda startup timeouts
v0.19.0
March 13, 2026
New Features
- Browserless.io provider -- Added browserless.io as a browser provider, supported in both Node.js and native daemon paths. Connect to remote Browserless instances using the
--provider browserlessflag orAGENT_BROWSER_PROVIDER=browserlessenvironment variable.
export BROWSERLESS_API_KEY="your-api-key"
agent-browser --provider browserless open example.com
agent-browser --provider browserless screenshot ./page.pngclipboardcommand -- Read from and write to the browser clipboard. Supportsread,write,copy(simulates Ctrl+C), andpaste(simulates Ctrl+V) operations.
agent-browser clipboard read
agent-browser clipboard write "Hello, World!"
agent-browser clipboard copy
agent-browser clipboard paste- Screenshot output configuration -- New global flags for persistent screenshot settings:
--screenshot-dir,--screenshot-quality, and--screenshot-format. Also available as environment variablesAGENT_BROWSER_SCREENSHOT_DIR,AGENT_BROWSER_SCREENSHOT_QUALITY, andAGENT_BROWSER_SCREENSHOT_FORMAT.
agent-browser screenshot --screenshot-dir ./shots
agent-browser screenshot --screenshot-format jpeg --screenshot-quality 80Bug Fixes
- Fixed
wait --textnot working in native daemon path - Fixed
BrowserManager.navigate()and package entry point - Fixed extensions not being loaded from
config.json - Fixed scroll on page load
- Fixed HTML retrieval by using
browser.getLocator()for selector operations
v0.18.0
March 12, 2026
New Features
inspectcommand -- Opens Chrome DevTools for the active page by launching a local proxy server that forwards the DevTools frontend to the browser's CDP WebSocket. Agent commands continue to work while DevTools is open.
agent-browser open example.com
agent-browser inspect # opens DevTools in your browser
agent-browser click "Submit" # commands still work while DevTools is openget cdp-urlsubcommand -- Retrieve the Chrome DevTools Protocol WebSocket URL for the active page, useful for connecting external debugging tools.
agent-browser get cdp-url- Screenshot annotate -- The
--annotateflag overlays numbered labels on interactive elements in screenshots.
Improvements
- KERNEL_API_KEY now optional -- External credential injection no longer requires
KERNEL_API_KEYto be set, making it easier to use Kernel with pre-configured environments. - Browserbase simplified -- Removed the
BROWSERBASE_PROJECT_IDrequirement, reducing setup friction for Browserbase users.
Bug Fixes
- Fixed Browserbase API using incorrect endpoint to release sessions
- Fixed CDP connect paths using hardcoded 10s timeout instead of the configurable default timeout
- Fixed lone Unicode surrogates causing errors by sanitizing with
toWellFormed() - Fixed CDP connection failure on IPv6-first systems
- Fixed recordings not inheriting the current viewport settings
v0.17.1
March 9, 2026
Improvements
- Viewport scale factor -- Added support for device scale factor (retina display) in the viewport command via an optional
scaleparameter. - Webview target support -- Added webview target type support for better Electron application compatibility. The pages list now includes target type information.
v0.17.0
March 8, 2026
New Features
- Lightpanda browser engine support -- Added
--engine <name>flag to select the browser engine (chromeby default, orlightpanda), implying--nativemode. Configurable viaAGENT_BROWSER_ENGINEenvironment variable.
agent-browser --engine lightpanda open example.com- Dialog dismiss command -- Added support for
dismisssubcommand in dialog command parsing.
Improvements
- Daemon startup error reporting -- Daemon startup errors are now surfaced directly instead of showing an opaque timeout message.
- CDP port discovery -- Replaced hand-rolled HTTP client with
reqwestfor more reliable CDP port discovery. - Chrome extensions -- Extensions now load correctly by forcing headed mode when extensions are present.
- Google Translate bar suppression -- Suppressed the Google Translate bar in native headless mode to avoid interference.
- Auth cookie persistence -- Auth cookies are now persisted on browser close in native mode.
Bug Fixes
- Fixed native auth login failing due to incompatible encryption format.
Performance
- Added benchmarks to the CLI codebase.
v0.16.0
March 3, 2026
New Features
- Native Rust daemon (experimental). A pure Rust daemon that communicates with Chrome directly via the Chrome DevTools Protocol (CDP), eliminating Node.js and Playwright dependencies entirely. Enable with
--native,AGENT_BROWSER_NATIVE=1, or"native": truein your config file. Supports 150+ commands with full parity to the default Node.js daemon.
# Via flag
agent-browser --native open example.com
# Via environment variable
export AGENT_BROWSER_NATIVE=1
agent-browser open example.comOr add to agent-browser.json:
{"native": true}Architecture
| Default (Node.js) | Native (--native) |
|
|---|---|---|
| Runtime | Node.js + Playwright | Pure Rust binary |
| Protocol | Playwright protocol | Direct CDP / WebDriver |
| Install size | Larger (Node.js + npm deps) | Smaller (single binary) |
| Browser support | Chromium, Firefox, WebKit | Chromium, Safari (via WebDriver) |
| Stability | Stable | Experimental |
What's Supported
All core commands work in native mode: navigation, interaction (click, fill, type, press, hover, scroll, drag), observation (snapshot, screenshot, eval), state management (cookies, storage, state save/load), tabs, emulation (viewport, device, timezone, locale, geolocation), streaming, diffing, recording, and profiling.
The native daemon also includes a WebDriver backend for Safari and iOS support.
Known Limitations
- Firefox and WebKit are not yet supported (Chromium and Safari only)
- Playwright trace format is not available (uses Chrome's built-in tracing)
- HAR export is not available
- Network route interception uses CDP Fetch domain instead of Playwright's route API
- The native and Node.js daemons share the same session socket. Use
agent-browser closebefore switching between modes.
See the Native Mode page for full details.
v0.15.0
February 25, 2026
New Features
- Authentication vault -- Store credentials locally (always AES-256-GCM encrypted) and reference them by name. The LLM never sees passwords. Commands:
auth save,auth login,auth list,auth show,auth delete. Passwords can be piped via stdin (--password-stdin) to avoid shell history exposure. - Content boundary markers --
--content-boundarieswraps page-sourced output in structural delimiters with a per-process CSPRNG nonce, so LLMs can distinguish trusted tool output from untrusted page content. In--jsonmode, a_boundaryobject is injected withnonceandoriginfields. - Domain allowlist --
--allowed-domainsrestricts navigation, sub-resource requests, WebSocket connections, and EventSource streams to trusted domains. Supports exact match and wildcard prefix patterns (e.g.,*.example.com). - Action policy --
--action-policygates actions using a static JSON policy file withallow/denylists across 13 action categories. Auth vault operations bypass policy enforcement. - Action confirmation --
--confirm-actionsrequires explicit approval for sensitive action categories. Newconfirmanddenycommands for orchestrator use.--confirm-interactiveenables human-in-the-loop terminal prompts (auto-denies if stdin is not a TTY). Pending confirmations auto-deny after 60 seconds. - Output length limits --
--max-outputtruncates large page outputs to prevent LLM context flooding. --download-pathoption -- Set a default download directory via flag,AGENT_BROWSER_DOWNLOAD_PATHenv var, ordownloadPathconfig key. Without it, downloads go to a temporary directory deleted when the browser closes.--selectorflag for scroll -- Scroll within a specific container element instead of the page:agent-browser scroll down 500 --selector "div.scroll-container"
# Auth vault
echo "pass" | agent-browser auth save github --url https://github.com/login --username user --password-stdin
agent-browser auth login github
# Security flags
agent-browser --content-boundaries --allowed-domains "example.com,*.example.com" --max-output 50000 open https://example.com
# Download path
agent-browser --download-path ./downloads open https://example.com
# Scroll within container
agent-browser scroll down 500 --selector "div.content"Environment Variables
Six new environment variables for security configuration: AGENT_BROWSER_CONTENT_BOUNDARIES, AGENT_BROWSER_MAX_OUTPUT, AGENT_BROWSER_ALLOWED_DOMAINS, AGENT_BROWSER_ACTION_POLICY, AGENT_BROWSER_CONFIRM_ACTIONS, AGENT_BROWSER_CONFIRM_INTERACTIVE.
v0.14.0
February 23, 2026
New Features
keyboardcommand -- Type with real keystrokes, insert text, and press shortcuts at the currently focused element without needing a selector (keyboard type,keyboard inserttext).--color-schemeflag -- Persistent dark/light mode preference across browser sessions via flag orAGENT_BROWSER_COLOR_SCHEMEenv var.
agent-browser keyboard type "Hello world"
agent-browser keyboard inserttext "pasted text"
agent-browser --color-scheme dark open https://example.comBug Fixes
- Fixed IPC EAGAIN errors (os error 35/11) with backpressure-aware socket writes, command serialization, and lowered default Playwright timeout to 25s (configurable via
AGENT_BROWSER_DEFAULT_TIMEOUT). - Fixed remote debugging (CDP) reconnection.
- Fixed state load failing when no browser is running.
- Fixed
--annotateflag warning appearing when not explicitly passed via CLI.
v0.13.0
February 20, 2026
New Features
- Diff commands -- Compare snapshots, screenshots, and URLs between page states. Run visual pixel diffs against baseline images, compare accessibility tree snapshots with customizable depth and selectors, and diff two URLs side-by-side with optional screenshot comparison.
agent-browser diff snapshot
agent-browser diff screenshot --baseline before.png
agent-browser diff url https://staging.example.com https://prod.example.comv0.12.0
February 18, 2026
New Features
- Annotated screenshots --
--annotateflag overlays numbered labels on interactive elements and prints a legend mapping each label to its element ref. Enables multimodal AI models to reason about visual layout while using the same@eNrefs for subsequent interactions. Also settable viaAGENT_BROWSER_ANNOTATEenv var.
agent-browser screenshot --annotatev0.11.1
February 18, 2026
Documentation
- Added documentation for command chaining with
&&across README, CLI help output, docs, and skill files.
v0.11.0
February 17, 2026
New Features
- Configuration file support -- Automatic loading from user (
~/.agent-browser/config.json) and project (./agent-browser.json) directories with priority-based merging. - Profiler commands -- Chrome DevTools profiling with
profiler startandprofiler stop. - Browser extension loading --
--extensionflag to load browser extensions. - Storage state management --
state saveandstate loadcommands for auth state persistence. - iOS device emulation --
--deviceflag for device emulation. - Enhanced click --
--new-taboption for click commands. - Enhanced find -- Additional actions and filtering options.
- CDP WebSocket URLs --
--cdpnow accepts WebSocket URLs in addition to ports.
v0.10.0
February 13, 2026
New Features
- Session persistence - Automatic save/restore of cookies and localStorage across browser restarts using
--session-nameflag - Encrypted state - Optional AES-256-GCM encryption for saved session state data
- State management commands - New commands for listing, showing, renaming, clearing, and cleaning up session state files
- New tab on click - Added
--new-taboption for click commands to open links in new tabs
# Persist session state
agent-browser --session-name myapp open https://example.com
# Manage saved states
agent-browser state list
agent-browser state show myapp
agent-browser state clear myappv0.9.4
February 13, 2026
Bug Fixes
- Fixed all Clippy lint warnings in the Rust CLI
v0.9.3
February 12, 2026
Improvements
- Added support for custom executable path in CLI browser launch options
- Documentation site UI improvements including a new chat component with sheet-based interface
v0.9.2
February 10, 2026
Improvements
- Migrated documentation site to MDX for improved content authoring
- Added AI-powered docs chat feature
- Updated README with Homebrew installation instructions for macOS users
v0.9.1
February 5, 2026
New Features
--allow-file-accessflag - Enable opening and interacting with localfile://URLs (PDFs, HTML files) by passing Chromium flags that allow JavaScript access to local files-C/--cursorflag for snapshots - Include cursor-interactive elements like divs with onclick handlers orcursor:pointerstyles
agent-browser --allow-file-access open file:///path/to/document.pdf
agent-browser snapshot -Cv0.9.0
February 3, 2026
New Features
- iOS Simulator support - Mobile Safari testing via Appium with real device and simulator support
# List available iOS simulators
agent-browser device list
# Launch on iOS device
agent-browser -p ios --device "iPhone 16 Pro" open https://example.com
# Touch interactions
agent-browser tap @e1
agent-browser swipe upv0.8.10
February 2, 2026
Improvements
- Added
--stdinflag for eval command to read JavaScript from stdin, enabling heredoc usage for multiline scripts - Fixed binary permission issues on macOS/Linux when postinstall scripts don't run
v0.8.9
February 2, 2026
Improvements
- Added
--stdinflag for eval command to read JavaScript from stdin
v0.8.8
February 2, 2026
Improvements
- Added base64 encoding support for the eval command with
-b/--base64flag to avoid shell escaping issues - Updated documentation with AI agent setup instructions
v0.8.7
February 2, 2026
Bug Fixes
- Fixed browser launch options not being passed correctly when using persistent profiles
- Added pre-flight checks for socket path length limits and directory write permissions
- Improved error handling to properly exit with failure status when browser launch fails
v0.8.6
January 31, 2026
Bug Fixes
- Improved daemon connection reliability with automatic retry logic for transient errors
- CLI now cleans up stale socket and PID files before starting a new daemon
v0.8.5
January 29, 2026
Bug Fixes
- Fixed version synchronization to automatically update Cargo.lock alongside Cargo.toml during releases
- Made the CLI binary executable in the npm package
v0.8.4
January 27, 2026
Bug Fixes
- Fixed "Daemon not found" error when running through AI agents by resolving symlinks in the executable path
v0.8.3
January 27, 2026
Improvements
- Replaced shell-based CLI wrappers with a cross-platform Node.js wrapper to enable npx support on Windows
- Added postinstall logic to patch npm bin entry on global installs for zero-overhead native binary invocation
- Added CI tests to verify global installation across all platforms
v0.8.2
January 26, 2026
Bug Fixes
- Fixed the Windows CMD wrapper to use the native binary directly instead of routing through Node.js
- Added retry logic to CI install command for transient browser installation failures
v0.8.1
January 26, 2026
Improvements
- Improved release workflow to validate binary file sizes and ensure binaries are executable after npm install
- Updated documentation site with a new mobile navigation system
v0.8.0
January 26, 2026
New Features
- Kernel cloud browser provider - Connect to Kernel (kernel.sh) for remote browser infrastructure with stealth mode and persistent profiles
# Via -p flag
agent-browser -p kernel open https://example.com
# Via environment variable
export AGENT_BROWSER_PROVIDER=kernel
export KERNEL_API_KEY=your-api-key
agent-browser open https://example.com
# With persistent profile
export KERNEL_PROFILE_NAME=my-profile
agent-browser open https://example.com- Ignore HTTPS certificate errors - New flag for working with self-signed certificates and development environments
agent-browser --ignore-https-errors open https://localhost:3000- Enhanced cookie management - Extended
cookies setcommand with additional flags for setting cookies before page load
agent-browser cookies set session_id "abc123" --url https://app.example.com --httpOnly --secure
agent-browser cookies set token "xyz" --domain .example.com --path /api --expires 1735689600Bug Fixes
- Fixed tab list command not recognizing new pages opened via clicks or
target="_blank"links - Fixed
checkcommand hanging indefinitely - Fixed
set devicenot applying deviceScaleFactor - HiDPI screenshots now work correctly - Fixed state load and profile persistence not working in v0.7.6
- Screenshots now save to temp directory when no path is provided
Security
- Daemon and stream server now reject cross-origin connections
v0.7.1
January 23, 2026
Bug Fixes
- Fix native binary distribution - Native binaries for all platforms (Linux x64/arm64, macOS x64/arm64, Windows x64) are now included in the npm package. Previously, the release workflow published to npm before building binaries, causing "No binary found" errors on installation.
v0.7.0
January 23, 2026
New Features
- Cloud browser providers - Connect to Browserbase or Browser Use for remote browser infrastructure
# Via -p flag (recommended)
agent-browser -p browserbase open https://example.com
agent-browser -p browseruse open https://example.com
# Via environment variable
export AGENT_BROWSER_PROVIDER=browserbase
agent-browser open https://example.com- Persistent browser profiles - Store cookies, localStorage, and login sessions across browser restarts
agent-browser --profile ~/.myapp-profile open myapp.com
# Login persists across restarts- Remote CDP WebSocket URLs - Connect to remote browser services via WebSocket
agent-browser --cdp "wss://browser-service.com/cdp?token=..." snapshotdownloadcommand - Trigger downloads and wait for completion
agent-browser download @e1 ./file.pdf
agent-browser wait --download ./output.zip --timeout 30000- Browser launch configuration - Fine-grained control over browser startup
agent-browser --args "--disable-gpu,--no-sandbox" open example.com
agent-browser --user-agent "Custom UA" open example.com
agent-browser --proxy-bypass "localhost,*.internal" open example.com- Enhanced skills - Hierarchical structure with references and templates for Claude Code
Bug Fixes
- Screenshot command now supports refs and has improved error messages
- WebSocket URLs work in
connectcommand - Fixed socket file location (uses
~/.agent-browserinstead of TMPDIR) - Windows binary path fix (.exe extension)
- State load and path-based actions now show correct output messages
Documentation
- Added Claude Code marketplace plugin installation instructions
- Updated skill documentation with references and templates
- Improved error documentation
v0.6.0
January 18, 2026
New Features
- Video recording - Record browser sessions to WebM using Playwright's native recording
agent-browser record start ./demo.webm
agent-browser click @e1
agent-browser record stopconnectcommand - Connect to a browser via CDP and persist the connection for subsequent commands
agent-browser connect 9222
agent-browser snapshot # No --cdp needed after connect--proxyflag - Configure browser proxy with optional authentication
agent-browser --proxy http://user:[email protected]:8080 open example.comget stylescommand - Extract computed styles from elements
agent-browser get styles "button"- Claude marketplace plugin - Added
.claude-plugin/marketplace.jsonfor Claude Code integration - Enhanced network output -
network requestsnow shows method, URL, and resource type --versionflag - Display CLI version
Bug Fixes
- Fix Windows daemon startup and port calculation
- Support
libasound2t64on newer Ubuntu versions (24.04+) - Prevent CDP timeout on empty URL tabs
- Output screenshot as base64 when no path provided
- Resolve refs in
get valuecommand - Support URL parameter in
tab newcommand - Allow
about:,data:, andfile:URL schemes - Detect stale unix socket by attempting connection
- Respect
AGENT_BROWSER_HEADEDenvironment variable - Handle SIGPIPE to prevent panic when piping to
head/tail - Fix null path validation in screenshot command
Protocol Alignment
These changes align the CLI with the daemon protocol for consistency:
selectcommand now usesvaluesfield (supports multiple selections)frame mainusesmainframeactionmouse wheeluseswheelactionset mediausesemulatemediaaction- Console output uses
messagesfield
Documentation
- Expanded SKILL.md with comprehensive command reference
- Updated README with new commands and options
- Updated CDP mode documentation with
connectworkflow
File: docs/src/app/cdp-mode/page.mdx
CDP Mode
Connect to an existing browser via Chrome DevTools Protocol:
# Start Chrome with: google-chrome --remote-debugging-port=9222
# Connect once, then run commands without --cdp
agent-browser connect 9222
agent-browser snapshot
agent-browser tab
agent-browser close
# Or pass --cdp on each command
agent-browser --cdp 9222 snapshotRemote WebSocket URLs
Connect to remote browser services via WebSocket URL:
# Connect to remote browser service
agent-browser --cdp "wss://browser-service.com/cdp?token=..." snapshot
# Works with any CDP-compatible service
agent-browser --cdp "ws://localhost:9222/devtools/browser/abc123" open example.comThe --cdp flag accepts either:
- A port number (e.g.,
9222) for local connections viahttp://localhost:{port} - A full WebSocket URL (e.g.,
wss://...orws://...) for remote browser services
Auto-Connect
Use --auto-connect to automatically discover and connect to a running Chrome instance without specifying a port:
# Auto-discover running Chrome with remote debugging
agent-browser --auto-connect open example.com
agent-browser --auto-connect snapshot
# Or via environment variable
AGENT_BROWSER_AUTO_CONNECT=1 agent-browser snapshotAuto-connect discovers Chrome by:
- Reading Chrome's
DevToolsActivePortfile from the default user data directory - Falling back to probing common debugging ports (9222, 9229)
- If HTTP-based discovery (
/json/version,/json/list) fails, falling back to a direct WebSocket connection
This is useful when:
- Chrome 144+ has remote debugging enabled via
chrome://inspect/#remote-debugging(which uses a dynamic port) - You want a zero-configuration connection to your existing browser
- You don't want to track which port Chrome is using
Tab pinning
When several sessions share one browser over CDP, each session remembers which tab it is bound to (by CDP target id, persisted across daemon restarts). A restarted daemon reattaches to the session's own tab instead of adopting whatever tab is currently active, which in a shared browser is usually another session's.
Pass --pin-tab (or set AGENT_BROWSER_PIN_TAB=1) to make the binding strict:
# Two agents sharing one Chrome, each pinned to its own tab
agent-browser --session agent1 --cdp 9222 --pin-tab open https://site-a.com
agent-browser --session agent2 --cdp 9222 --pin-tab open https://site-b.comWith --pin-tab:
- Attaching with no binding opens a fresh tab instead of adopting an existing one
- If the bound tab is closed, commands fail with a
tab_goneerror instead of silently acting on another tab. JSON responses carry"code": "tab_gone",data.targetId, and optionaldata.lastUrl tab list,tab new, andtab <ref>still work in that state, so an agent can recover by binding a new tab- Tabs opened by other sessions or the user never steal the pinned session's active tab
The flag is sticky per session: pass it once and later commands and daemon restarts keep the strict semantics. Pass --no-pin-tab to explicitly turn the pin off again. See Sessions for the multi-session workflow and Commands for tab refs by CDP target id.
The structured lastUrl is emitted only for sanitized HTTP(S) URLs and about:blank. Credentials, query strings, and fragments are removed from HTTP(S) URLs, while opaque URLs such as data: are omitted. Batch JSON exposes the recovery object under result.
When re-running a shared-tab script such as the repro from #1530, add --pin-tab to the first command for every session. Without it, open intentionally preserves the legacy behavior and navigates the shared active tab, so the original script still collides. The same rule applies when sessions attach with --auto-connect instead of --cdp.
Color scheme
Use --color-scheme to set a persistent preference when connecting via CDP:
agent-browser --cdp 9222 --color-scheme dark open https://example.com
agent-browser --cdp 9222 snapshot # stays in dark modeOr set it globally via config or environment variable:
AGENT_BROWSER_COLOR_SCHEME=dark agent-browser --cdp 9222 open https://example.comUse cases
This enables control of:
- Electron apps
- Chrome/Chromium with remote debugging
- WebView2 applications
- Remote browser services (via WebSocket URL)
- Any browser exposing a CDP endpoint
Global options
| Option | Description |
|---|---|
--session <name> |
Use isolated session |
--profile <path> |
Persistent browser profile directory |
-p <provider> |
Browser provider (browserbase, browseruse, kernel, browserless, agentcore, or a configured browser.provider plugin) |
--headers <json> |
HTTP headers scoped to origin |
--executable-path |
Custom browser executable |
--args <args> |
Browser launch args (comma-separated) |
--user-agent <ua> |
Custom User-Agent string |
--proxy <url> |
Proxy server URL |
--proxy-bypass <hosts> |
Hosts to bypass proxy |
--json |
JSON output for scripts |
--name, -n |
Locator name filter |
--exact |
Exact, case-sensitive match (accessible name for role) |
--headed |
Show browser window |
{"--cdp "} |
CDP connection (port or WebSocket URL) |
--auto-connect |
Auto-discover and connect to running Chrome |
--pin-tab |
Pin the session to its bound tab (strict tab binding) |
--no-pin-tab |
Disable a sticky pin previously enabled with --pin-tab |
--color-scheme <scheme> |
Persistent color scheme (dark, light, no-preference) |
--debug |
Debug output |
Cloud providers
Use the -p flag to connect to a cloud browser provider or configured browser.provider plugin instead of launching a local browser:
agent-browser -p browserbase open https://example.comSee the Providers section for setup and configuration of each built-in provider: Browser Use, Browserbase, Browserless, Kernel, and AgentCore.
File: docs/src/app/installation/page.mdx
Installation
Global installation (recommended)
Installs the native Rust binary for maximum performance:
npm install agent-browser
agent-browser install # Download Chrome from Chrome for Testing (first time)This is the fastest option -- commands run through the native Rust CLI directly with sub-millisecond parsing overhead.
Quick start (no install)
npx agent-browser install # Download Chrome (first time only)
npx agent-browser open example.comProject installation (local dependency)
For projects that want to pin the version in package.json:
npm install agent-browser
npx agent-browser install # Download Chrome (first time)Then use via npx or package.json scripts.
Homebrew (macOS)
brew install agent-browser
agent-browser install # Download Chrome (first time)Cargo (Rust)
cargo install agent-browser
agent-browser install # Download Chrome (first time)Compiles from source (~2-3 min). Requires Node.js 24+, pnpm 11+, and the Rust toolchain (rustup.rs).
From source
git clone https://github.com/vercel-labs/agent-browser
cd agent-browser
pnpm install
pnpm build
pnpm build:native
./bin/agent-browser install
pnpm link --globalLinux dependencies
On Linux, install system dependencies:
agent-browser install --with-depsThis exits nonzero if the package manager cannot install every required browser library.
Updating
Upgrade to the latest version:
agent-browser upgradeDetects your installation method (npm, Homebrew, or Cargo) and runs the appropriate update command automatically. Displays the version change on success, or informs you if you are already on the latest version.
Doctor
doctor diagnoses your install and auto-cleans stale daemon files. Run it whenever something stops working unexpectedly, or after upgrades:
agent-browser doctor # Full diagnosis
agent-browser doctor --offline --quick # Local-only, fastest (~<1s)
agent-browser doctor --fix # Also run destructive repairs
agent-browser doctor --webgpu # Also run a live WebGPU render probe
agent-browser doctor --json # Structured outputIt checks:
| Category | What it checks |
|---|---|
| Environment | CLI version, platform, home directory, state and socket dirs, free disk space |
| Chrome | Chrome install path and version, cache dir, Puppeteer fallback, user-data dir and profile count, optional lightpanda engine |
| Daemons | Running daemons per session, stale .sock / .pid / .version / .stream files (auto-cleaned), version mismatch with the CLI, dashboard process liveness |
| Config | ~/.agent-browser/config.json, ./agent-browser.json, and any file at AGENT_BROWSER_CONFIG parse as valid JSON |
| Security | Encryption key env var or ~/.agent-browser/.encryption-key (with 0600 permissions on unix), state file count and age vs AGENT_BROWSER_STATE_EXPIRE_DAYS, action policy file |
| Providers | Env vars for Browserless, Browserbase, Browser Use, Kernel, AgentCore (AWS creds), Appium (for --provider ios), and AI_GATEWAY_API_KEY for chat |
| Network | Reachability of the Chrome for Testing CDN, AI Gateway (if configured), and any currently selected provider endpoint (skipped under --offline) |
| Launch test | Spawns a scratch session, launches headless Chrome, navigates to about:blank, then closes. Measures wall time (skipped under --quick) |
| WebGPU probe | Opt-in via --webgpu: launches a scratch session with the WebGPU preset, renders through a real WebGPU pass, and pixel-checks both an offscreen readback and a decoded screenshot. Add --headed to validate the headed/Xvfb capture path |
Stale sidecar files are always cleaned. Destructive actions are opt-in via --fix:
| Check | What --fix does |
|---|---|
| Chrome missing | Runs agent-browser install |
| Version-mismatched daemons | Sends close to each and cleans files |
| Old state files | Deletes state files older than AGENT_BROWSER_STATE_EXPIRE_DAYS (default 30) |
| Missing encryption key | Generates a new key at ~/.agent-browser/.encryption-key (0600, unix); never overwrites an existing key |
Exit code is 0 if all checks pass (warnings are fine), 1 if any fail.
Custom browser
Use a custom browser executable instead of bundled Chromium:
- Serverless - Use
@sparticuz/chromium(~50MB vs ~684MB) - System browser - Use existing Chrome installation
- Custom builds - Use modified browser builds
# Via flag
agent-browser --executable-path /path/to/chromium open example.com
# Via environment variable
AGENT_BROWSER_EXECUTABLE_PATH=/path/to/chromium agent-browser open example.comServerless example
Use @sparticuz/chromium or similar to obtain a Chromium executable path, then pass it via --executable-path or AGENT_BROWSER_EXECUTABLE_PATH.
AI agent setup
agent-browser works with any AI agent out of the box. For richer context:
AI coding assistants (recommended)
Install the skill for your AI coding assistant:
npx skills add vercel-labs/agent-browserThis works with Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, Goose, OpenCode, and Windsurf. The skill is fetched from the repository and stays up to date automatically.
Do not copy
SKILL.mdfromnode_modules-- it will become stale as new features are added. Always usenpx skills addor reference the repository version.
AGENTS.md / CLAUDE.md
Add to your instructions file:
## Browser Automation
Use `agent-browser` for web automation. Run `agent-browser --help` for all commands.
Core workflow:
1. `agent-browser open ` - Navigate to page
2. `agent-browser snapshot -i` - Get interactive elements with refs (@e1, @e2)
3. `agent-browser click @e1` / `fill @e2 "text"` - Interact using refs
4. Re-snapshot after page changesFile: docs/src/app/ios/page.mdx
iOS Simulator
Control real Mobile Safari in the iOS Simulator for authentic mobile web testing. Uses Appium with XCUITest for native automation.
Requirements
- macOS with Xcode installed
- iOS Simulator runtimes (download via Xcode)
- Appium with XCUITest driver
Setup
# Install Appium globally
npm install appium
# Install the XCUITest driver for iOS
appium driver install xcuitestList available devices
See all iOS simulators available on your system:
agent-browser device list
# Output:
# Available iOS Simulators:
#
# ○ iPhone 16 Pro (iOS 18.0)
# F21EEC0D-7618-419F-811B-33AF27A8B2FD
# ○ iPhone 16 Pro Max (iOS 18.0)
# 50402807-C9B8-4D37-9F13-2E00E782C744
# ○ iPad Pro 13-inch (M4) (iOS 18.0)
# 3A6C6436-B909-4593-866D-91D1062BB070
# ...Basic usage
Use the -p ios flag to enable iOS mode. The workflow is identical to desktop:
# Launch Safari on iPhone 16 Pro
agent-browser -p ios --device "iPhone 16 Pro" open https://example.com
# Get snapshot with refs (same as desktop)
agent-browser -p ios snapshot -i
# Interact using refs
agent-browser -p ios tap @e1
agent-browser -p ios fill @e2 "text"
# Take screenshot
agent-browser -p ios screenshot mobile.png
# Close session (shuts down simulator)
agent-browser -p ios closeMobile-specific commands
# Swipe gestures
agent-browser -p ios swipe up
agent-browser -p ios swipe down
agent-browser -p ios swipe left
agent-browser -p ios swipe right
# Swipe with distance (pixels)
agent-browser -p ios swipe up 500
# Tap (alias for click, semantically clearer for touch)
agent-browser -p ios tap @e1Environment variables
Configure iOS mode via environment variables:
export AGENT_BROWSER_PROVIDER=ios
export AGENT_BROWSER_IOS_DEVICE="iPhone 16 Pro"
# Now all commands use iOS
agent-browser open https://example.com
agent-browser snapshot -i
agent-browser tap @e1| Variable | Description |
|---|---|
AGENT_BROWSER_PROVIDER |
Set to ios to enable iOS mode |
AGENT_BROWSER_IOS_DEVICE |
Device name (e.g., "iPhone 16 Pro") |
AGENT_BROWSER_IOS_UDID |
Device UDID (alternative to device name) |
Supported devices
All iOS Simulators available in Xcode are supported, including:
- All iPhone models (iPhone 15, 16, 17, SE, etc.)
- All iPad models (iPad Pro, iPad Air, iPad mini, etc.)
- Multiple iOS versions (17.x, 18.x, etc.)
Real devices are also supported via USB connection (see below).
Real device support
Appium can control Safari on real iOS devices connected via USB. This requires additional one-time setup.
1. Get your device UDID
# List connected devices
xcrun xctrace list devices
# Or via system profiler
system_profiler SPUSBDataType | grep -A 5 "iPhone\|iPad"2. Sign WebDriverAgent (one-time)
WebDriverAgent needs to be signed with your Apple Developer certificate to run on real devices.
# Open the WebDriverAgent Xcode project
cd ~/.appium/node_modules/appium-xcuitest-driver/node_modules/appium-webdriveragent
open WebDriverAgent.xcodeprojIn Xcode:
- Select the
WebDriverAgentRunnertarget - Go to Signing & Capabilities
- Select your Team (requires Apple Developer account, free tier works)
- Let Xcode manage signing automatically
3. Use with agent-browser
# Connect device via USB, then use the UDID
agent-browser -p ios --device "<DEVICE_UDID>" open https://example.com
# Or use the device name if unique
agent-browser -p ios --device "John's iPhone" open https://example.comReal device notes
- First run installs WebDriverAgent to the device (may require Trust prompt on device)
- Device must be unlocked and connected via USB
- Slightly slower initial connection than simulator
- Tests against real Safari performance and behavior
- On first install, go to Settings → General → VPN & Device Management to trust the developer certificate
Performance notes
- First launch: Takes 30-60 seconds to boot the simulator and start Appium
- Subsequent commands: Fast (simulator stays running)
- Close command: Shuts down simulator and Appium server
Differences from desktop
| Feature | Desktop | iOS |
|---|---|---|
| Browser | Chrome, Lightpanda | Safari only |
| Tabs | Supported | Single tab only |
| PDF export | Supported | Not supported |
| Screencast | Supported | Not supported |
| Swipe gestures | Not native | Native support |
Troubleshooting
Appium not found
# Make sure Appium is installed globally
npm install appium
appium driver install xcuitest
# Verify installation
appium --versionNo simulators available
Open Xcode and download iOS Simulator runtimes from Settings → Platforms.
Simulator won't boot
Try booting the simulator manually from Xcode or the Simulator app to ensure it works, then retry with agent-browser.
File: docs/src/app/quick-start/page.mdx
Quick Start
Core workflow
Every browser automation follows this pattern:
# 1. Navigate
agent-browser open example.com
# 2. Snapshot to get element refs
agent-browser snapshot -i
# Output:
# @e1 [heading] "Example Domain"
# @e2 [link] "More information..."
# 3. Interact using refs
agent-browser click @e2
# 4. Re-snapshot after page changes
agent-browser snapshot -iCommon commands
agent-browser open example.com
agent-browser snapshot -i # Get interactive elements with refs
agent-browser click @e2 # Click by ref
agent-browser fill @e3 "[email protected]" # Fill input by ref
agent-browser get text @e1 # Get text content
agent-browser screenshot # Save to temp directory
agent-browser screenshot page.png # Save to specific path
agent-browser closeTraditional selectors
CSS selectors and semantic locators also supported:
agent-browser click "#submit"
agent-browser fill "#email" "[email protected]"
agent-browser find role button click --name "Submit"Headed mode
Show browser window for debugging:
agent-browser open example.com --headedWait for content
agent-browser wait @e1 # Wait for element
agent-browser wait --load networkidle # Wait for network idle
agent-browser wait --url "**/dashboard" # Wait for URL pattern
agent-browser wait 2000 # Wait millisecondsCommand chaining
Chain commands with && in a single shell call. The browser persists via a background daemon, so chaining is safe and efficient:
# Open, wait, and snapshot in one call
agent-browser open example.com && agent-browser wait --load networkidle && agent-browser snapshot -i
# Chain multiple interactions
agent-browser fill @e1 "[email protected]" && agent-browser fill @e2 "pass" && agent-browser click @e3
# Navigate and capture
agent-browser open example.com && agent-browser wait --load networkidle && agent-browser screenshot page.pngUse && when you don't need intermediate output. Run commands separately when you need to parse output first (e.g., snapshot to discover refs before interacting).
JSON output
For programmatic parsing in scripts:
agent-browser snapshot --json
agent-browser get text @e1 --jsonNote: The default text output is more compact and preferred for AI agents.
File: docs/src/app/selectors/page.mdx
Selectors
Refs (recommended)
Refs provide deterministic element selection from snapshots. Best for AI agents.
# 1. Get snapshot with refs
agent-browser snapshot
# Output:
# - heading "Example Domain" [ref=e1] [level=1]
# - button "Submit" [ref=e2]
# - textbox "Email" [ref=e3]
# - link "Learn more" [ref=e4]
# 2. Use refs to interact
agent-browser click @e2 # Click the button
agent-browser fill @e3 "[email protected]" # Fill the textbox
agent-browser get text @e1 # Get heading text
agent-browser hover @e4 # Hover the linkWhy refs?
- Deterministic - Ref points to exact element from snapshot
- Fast - No DOM re-query needed
- AI-friendly - LLMs can reliably parse and use refs
CSS selectors
agent-browser click "#id"
agent-browser click ".class"
agent-browser click "div > button"
agent-browser click "[data-testid='submit']"Text & XPath
agent-browser click "text=Submit"
agent-browser click "xpath=//button[@type='submit']"Semantic locators
Find elements by role, label, or other semantic properties:
agent-browser find role button click --name "Submit"
agent-browser find role heading text --name "Skills" # implicit roles work: <h2>=heading, =list, top-level <header>=banner
agent-browser find label "Email" fill "[email protected]"
agent-browser find placeholder "Search..." fill "query"
agent-browser find testid "submit-btn" clickFile: docs/src/app/sessions/page.mdx
Sessions
Run multiple isolated browser instances:
# Different sessions
agent-browser --session agent1 open site-a.com
agent-browser --session agent2 open site-b.com
# Or via environment variable
AGENT_BROWSER_SESSION=agent1 agent-browser click "#btn"
# List active sessions
agent-browser session list
# Output:
# Active sessions:
# -> default
# agent1
# Show current session
agent-browser session
# Generate a stable worktree-scoped session id
agent-browser session id --scope worktree --prefix next-dev-loop
# Inspect daemon, launch, and restore status
agent-browser session info --jsonSession isolation
Each session has its own:
- Browser instance
- Cookies and storage
- Navigation history
- Authentication state
Tab pinning in a shared browser
Full isolation applies when each session launches its own browser. When sessions instead share one Chrome over --cdp, only the tab selection separates them. Each session remembers which tab it is bound to (by CDP target id, persisted across daemon restarts), so a restarted daemon reattaches to the session's own tab instead of adopting the most recently active one.
Add --pin-tab (or set AGENT_BROWSER_PIN_TAB=1) to make the binding strict:
agent-browser --session agent1 --cdp 9222 --pin-tab open https://site-a.com
agent-browser --session agent2 --cdp 9222 --pin-tab open https://site-b.comWith --pin-tab, a session whose bound tab was closed gets a tab_gone error instead of silently acting on another session's tab; run tab new or pick a tab from tab list to recover. JSON output includes "code": "tab_gone", data.targetId, and optional sanitized data.lastUrl. Batch output uses result for the same recovery object. The flag is sticky per session; pass --no-pin-tab to turn it off again. See CDP Mode for details.
Chrome profile reuse
The simplest way to reuse your existing login state: pass a Chrome profile name to --profile. agent-browser copies the profile to a temp directory (read-only snapshot) and launches Chrome with your existing cookies and sessions.
# List available Chrome profiles
agent-browser profiles
# Reuse your default Chrome profile's login state
agent-browser --profile Default open https://gmail.com
# Use a named profile (by display name or directory name)
agent-browser --profile "Work" open https://app.example.com
# Or via environment variable
AGENT_BROWSER_PROFILE=Default agent-browser open https://gmail.com| Detail | Description |
|---|---|
| Supported browsers | Chrome, Chrome Canary, Chromium, Brave |
| What's copied | Cookies, local storage, extensions state (cache dirs excluded for speed) |
| Original profile | Never modified (read-only snapshot) |
| Cleanup | Temp copy deleted when browser closes |
| Windows note | Close Chrome before using --profile <name> if Chrome is running |
Persistent profiles
For a custom profile directory that persists state across browser restarts, pass a path to --profile:
# Use a persistent profile directory
agent-browser --profile ~/.myapp-profile open myapp.com
# Login once, then reuse the authenticated session
agent-browser --profile ~/.myapp-profile open myapp.com/dashboard
# Or via environment variable
AGENT_BROWSER_PROFILE=~/.myapp-profile agent-browser open myapp.comThe profile directory stores:
- Cookies and localStorage
- IndexedDB data
- Service workers
- Browser cache
- Login sessions
Import auth from your browser
If you are already logged in to a site in Chrome, you can grab that auth state and reuse it in agent-browser. This is the fastest way to bypass login flows, OAuth, SSO, or 2FA.
Step 1: Start Chrome with remote debugging:
# macOS
"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" --remote-debugging-port=9222
# Linux
google-chrome --remote-debugging-port=9222Log in to your target site(s) in this Chrome window.
--remote-debugging-port exposes full browser control on localhost. Any local process can connect. Only use on trusted machines and close Chrome when done.
Step 2: Connect and save the authenticated state:
agent-browser --auto-connect state save ./my-auth.jsonStep 3: Use the saved auth in future sessions:
# Load auth at launch
agent-browser --state ./my-auth.json open https://app.example.com/dashboard
# Or load into an already-launched session
agent-browser open about:blank
agent-browser state load ./my-auth.json
agent-browser open https://app.example.com/dashboardCombine with --session --restore so the imported auth auto-persists across restarts:
SESSION="$(agent-browser session id --scope worktree --prefix myapp)"
agent-browser --session "$SESSION" --restore --state ./my-auth.json open https://app.example.com/dashboard
# From now on, state auto-saves/restores for this sessionState files contain session tokens in plaintext. Add them to .gitignore and delete when no longer needed. For encryption at rest, see State encryption below.
Session persistence
Use --restore with a stable --session to automatically save and restore cookies and localStorage across browser restarts:
# Auto-save/load state for this worktree
SESSION="$(agent-browser session id --scope worktree --prefix twitter)"
agent-browser --session "$SESSION" --restore open twitter.com
# Login once, then state persists automatically
agent-browser --session "$SESSION" --restore click "#login"
# Optional validation prevents a bad restore from overwriting the previous good state
agent-browser --session "$SESSION" --restore --restore-check-text Dashboard open twitter.comState files are stored in ~/.agent-browser/sessions/ and automatically loaded before navigation. With the default --restore-save auto policy, failed restore or failed validation skips auto-save.
When --restore or another restore key is configured, state is saved when the browser closes (explicit close, idle timeout, or daemon shutdown) and also periodically while the browser is open, so a browser window you close by hand still leaves a recent save behind. A session ID by itself only isolates the daemon and does not enable persistence; without a restore key, shutdown discards transient browser state and open tabs. Periodic autosave waits for commands to settle, then saves at most once per AGENT_BROWSER_AUTOSAVE_INTERVAL_MS (default 30000; set to 0 to save only on close). Idle sessions with configured persistence keep saving on the same interval, so changes the page makes on its own (token refreshes, background requests) are captured too. The daemon exits after one hour without commands or dashboard input by default; --idle-timeout <time> or AGENT_BROWSER_IDLE_TIMEOUT_MS tunes this, and 0 disables it. Headed, Safari/iOS WebDriver, and user-attached browsers are exempt from the default timeout; provider-owned cloud browsers are not. State saving respects the --restore-save policy.
Restore key rules
Session and restore names must contain only alphanumeric characters, hyphens, and underscores. Use agent-browser session id to generate a valid key:
# Valid generated key
agent-browser session id --scope worktree --prefix my-project
# Invalid (will be rejected)
agent-browser --session "../bad" --restore open example.com # path traversal
agent-browser --session "my session" --restore open example.com # spaces
agent-browser --session "foo/bar" --restore open example.com # slashesState encryption
Encrypt saved state files (cookies, localStorage) using AES-256-GCM:
# Generate a 256-bit key (64 hex characters)
openssl rand -hex 32
# Set the encryption key
export AGENT_BROWSER_ENCRYPTION_KEY=<your-64-char-hex-key>
# State files are now encrypted automatically
agent-browser --session secure-session --restore open example.com
# List states shows encryption status
agent-browser state listState auto-expiration
Automatically delete old state files to prevent accumulation:
# Set expiration (default: 30 days)
export AGENT_BROWSER_STATE_EXPIRE_DAYS=7
# Manually clean old states
agent-browser state clean --older-than 7State management commands
# List all saved states
agent-browser state list
# Show state summary (cookies, origins, domains)
agent-browser state show my-session-default.json
# Rename a state file
agent-browser state rename old-name new-name
# Clear states for a specific session name
agent-browser state clear my-session
# Clear all saved states
agent-browser state clear --all
# Manual save/load (for custom paths)
agent-browser state save ./backup.json
agent-browser state load ./backup.jsonAuthenticated sessions
Use --headers to set HTTP headers for a specific origin:
# Headers scoped to api.example.com only
agent-browser open api.example.com --headers '{"Authorization": "Bearer <token>"}'
# Requests to api.example.com include the auth header
agent-browser snapshot -i --json
agent-browser click @e2
# Navigate to another domain - headers NOT sent
agent-browser open other-site.comUseful for:
- Skipping login flows - Authenticate via headers
- Switching users - Different auth tokens per session
- API testing - Access protected endpoints
- Security - Headers scoped to origin, not leaked
Multiple origins
agent-browser open api.example.com --headers '{"Authorization": "Bearer token1"}'
agent-browser open api.acme.com --headers '{"Authorization": "Bearer token2"}'Global headers
For headers on all domains:
agent-browser set headers '{"X-Custom-Header": "value"}'Environment variables
| Variable | Description |
|---|---|
AGENT_BROWSER_SESSION |
Browser session ID (default: "default") |
AGENT_BROWSER_NAMESPACE |
Namespace for daemon sockets and restore-state directories |
AGENT_BROWSER_PIN_TAB |
Pin the session to its bound tab (strict tab binding) |
AGENT_BROWSER_RESTORE |
Auto-save/load state persistence key |
AGENT_BROWSER_RESTORE_SAVE |
Restore save policy: auto, always, or never |
AGENT_BROWSER_AUTOSAVE_INTERVAL_MS |
Minimum ms between periodic session autosaves (default: 30000, 0 disables) |
AGENT_BROWSER_RESTORE_CHECK_URL |
URL pattern restored state must match |
AGENT_BROWSER_RESTORE_CHECK_TEXT |
Page text restored state must contain |
AGENT_BROWSER_RESTORE_CHECK_FN |
JavaScript expression restored state must satisfy |
AGENT_BROWSER_SESSION_NAME |
Legacy auto-save/load state persistence name |
AGENT_BROWSER_ENCRYPTION_KEY |
64-char hex key for AES-256-GCM encryption |
AGENT_BROWSER_STATE_EXPIRE_DAYS |
Auto-delete states older than N days (default: 30) |
File: docs/src/app/snapshots/page.mdx
Snapshots
The snapshot command returns a compact accessibility tree with refs for element interaction.
Options
Filter output to reduce size:
agent-browser snapshot # Full accessibility tree
agent-browser snapshot -i # Interactive elements only (recommended)
agent-browser snapshot -c # Compact (remove empty elements)
agent-browser snapshot -d 3 # Limit depth to 3 levels
agent-browser snapshot -s "#main" # Scope to CSS selector
agent-browser snapshot -i -c -d 5 # Combine options| Option | Description |
|---|---|
-i, --interactive |
Only interactive elements (buttons, links, inputs) |
-u, --urls |
Include href URLs for link elements |
-c, --compact |
Remove empty structural elements |
-d, --depth |
Limit tree depth |
-s, --selector |
Scope to CSS selector |
Output format
The default text output is compact and AI-friendly:
agent-browser snapshot -i
# Output:
# @e1 [heading] "Example Domain" [level=1]
# @e2 [button] "Submit"
# @e3 [input type="email"] placeholder="Email"
# @e4 [link] "Learn more"Using refs
Refs from the snapshot map directly to commands:
agent-browser click @e2 # Click the Submit button
agent-browser fill @e3 "[email protected]" # Fill the email input
agent-browser get text @e1 # Get heading textRef lifecycle
Refs are invalidated when the page changes. Always re-snapshot after navigation or DOM updates:
agent-browser click @e4 # Navigates to new page
agent-browser snapshot -i # Get fresh refs
agent-browser click @e1 # Use new refsAnnotated screenshots
For visual context alongside text snapshots, use screenshot --annotate to overlay numbered labels on interactive elements. Each label [N] maps to ref @eN:
In native mode, annotated screenshots currently work on the CDP-backed browser path (Chromium/Lightpanda). The Safari/WebDriver backend does not yet support --annotate.
agent-browser screenshot --annotate ./page.png
# -> Screenshot saved to ./page.png
# [1] @e1 button "Submit"
# [2] @e2 link "Home"
# [3] @e3 textbox "Email"
agent-browser click @e2Headless Chromium screenshots hide native scrollbars for consistent image output. Pass --hide-scrollbars false when launching to keep native scrollbars visible.
Annotated screenshots also cache refs, so you can interact with elements immediately. This is useful when the text snapshot is insufficient for unlabeled icons, canvas content, or visual layout verification.
Iframes
Snapshots automatically detect and inline iframe content. Each Iframe node in the main frame is resolved and its child accessibility tree is included directly beneath it. Refs assigned to elements inside iframes carry frame context, so interactions work without switching frames first.
agent-browser snapshot -i
# @e1 [heading] "Checkout"
# @e2 [Iframe] "payment-frame"
# @e3 [input] "Card number"
# @e4 [button] "Pay"
agent-browser fill @e3 "4111111111111111"
agent-browser click @e4Only one level of iframe nesting is expanded. Cross-origin iframes that block accessibility tree access and empty iframes are silently omitted.
To scope a snapshot to a single iframe, switch into it first:
agent-browser frame @e2
agent-browser snapshot -i # Only elements inside that iframe
agent-browser frame main # Return to main frameBest practices
- Use
-ito reduce output to actionable elements - Re-snapshot after page changes to get updated refs
- Scope with
-sfor specific page sections - Use
-dto limit depth on complex pages - Use
screenshot --annotatewhen visual context is needed alongside refs
JSON output
For programmatic parsing in scripts:
agent-browser snapshot --json
# {"success":true,"data":{"snapshot":"...","refs":{"e1":{"role":"heading","name":"Title"},...}}}Note: JSON uses more tokens than text output. The default text format is preferred for AI agents.