English | Português Brasileiro
One-shot Chrome CDP automation for AI agents. BORN, EXECUTE, FINALIZE, DIE.
cargo install browser-automation-cliAgent discovery map: llms.txt (short) and llms-full.txt (expanded).
- Single-process browser automation CLI for AI agents
- Talks to system Chrome or Chromium through chromiumoxide CDP
- No daemon, no npm packaging, no remote telemetry
- Lifecycle is always BORN, EXECUTE, FINALIZE, DIE
- JSON envelopes on stdout for programmatic agents
- XDG config and paths via
configcommands only
- Agent workflows need multi-step browser work without a sticky daemon
- Node and npm browser stacks add runtime weight and supply-chain surface
- Session-based tools leave orphan Chrome processes and unclear ownership
- JSON contracts often drift from real CLI flags and exit codes
- Product settings outside XDG
configmake agent prompts fragile
- One process owns one Chrome lifecycle from launch to kill fallback
- Multi-step work uses
run --scriptNDJSON or a JSON array of steps in the same process - Accessibility snapshot refs
@eNstay valid only inside that process --jsonenvelopes are stable for programmatic agents; clap usage errors also emit JSON when--jsonis on argv- Install path is pure Rust via cargo
- v0.2.0 is current: a Chrome started by the CLI drives DevTools over a pipe instead of a TCP port, and a headed Linux launch stays inside a private Xvfb protected by a cookie; inventory 71 agent names via
commands --json; 217 XDG keys
- Navigation and page lifecycle:
goto(init-script, beforeunload accept|dismiss),back,forward,reload,page - Input:
press,write,type,keys,hover,drag,fill-form,select-option,pick(native select + HIG badge/popover /role=optionwith pick events),submit,upload - Observation:
view(refuses empty about:blank unless--allow-empty),grab(formatspng|jpeg|webponly; AVIF removed),extract,text,attr,scroll,assert - Wait: multi
--textOR; CSS multi-selector OR (#a, #b); run fieldsurl/url_contains/navigation/wait_timeout_ms - Assert:
url/text/consoleplusconsole_empty/console_no_match(CLIconsole-empty/console-no-match) - Scrape: multi-format
--format/--formats(CSV or repeatable) with--engine http|browser; 15 live formatstext|markdown|html|rawHtml|links|metadata|screenshot|summary|product|branding|images|jsonld|json|feed|attributes(raw-htmlstays an accepted alias ofrawHtml); browser applies formats via outerHTML;format/formatsalso accepted inrunscrape steps - Local scrape/crawl/map/search/parse:
batch-scrapeandcrawlaccept--engine http|browser,map,search(cleansuddg=),parse(PDF/DOCX/xlsx/ods +--redact-pii) - Extract LLM:
extract --llm --question --schema-json(XDGopenrouter_api_key,llm_base_url,llm_model) - Capture:
console(dump always writes[]when empty) andnetwith optional global capture flags - Dialogs:
dialog accept|dismissreturns.data.dialog_settled; XDGdialog_settle_ms; multi-tab dialogsession_idisolation with e2e gate - Storage:
storage export|importfor cookies + per-origin state within one process - DevTools depth:
eval,emulate,resize,perf,lighthouse(flag → XDG → PATH;binary_sourcereal|mock; unit fixtures include chrome-captured LHR 13.4.1; e2e mock remains SKIP),heap - PDF print:
print-pdfone-shot and multi-steprun; refuses blank PDF without navigated content - Monitor:
monitor check --url --baseline [--write-baseline] - Utilities (no Chrome):
qr encode|decode,image info|convert|resize|download|exif,video info|download|convert|to-mp3|trim|thumbnail|manifest,audio info|download|convert|trim,find-paths(--glob),sheet-write,sg-scan,sg-rewrite - Assert aliases:
url_contains/text_contains;attrfalls back to DOM properties - Scroll aliases in
run:dy/dxfordelta_y/delta_x - Optional categories: memory, extensions, third-party, webmcp
- Experimental: vision
click-at, screencast with ffmpeg export - Anti-detection: stealth is ON by default, with
--no-stealth,--stealth-profile,--stealth-seed,--proxy,--proxy-bypass,--input-profile human|direct,--warmup,--no-xvfb - MITM one-shot:
status|list|get|har|export|domains|apis|init-ca|start|capture-url|graphql|ws|block|allow|redact(binds127.0.0.1; global--mitm*) - Workflow DAG:
workflow run|resume|statuswith SQLite journal (resume skips ok) - XDG config:
config path|init|show|set|get|unset|list-keysfor config.toml (discover full keys viaconfig list-keys --json) - Discovery:
doctor(incl.residual_disk),commands(71 agent names),schema <cmd>orschema --cmd,version,locale,man,completions - Global flags: the global help declares 57 long flags, 55 of them product flags plus
--helpand--version;browser-automation-cli --helpis the source of truth - Multi-step observability:
run --jsonfinal envelope includesok+ fullsteps[].data; global--json-stepsstreams one NDJSON line per step - Fail-fast multi-step:
runreturns partialdata.stepson error envelopes - Residual-zero disk (still true from 0.1.5 RES-01…12): BORN auto-GC of stale Singleton-only Chromium dirs under
/tmpolder than 60s; FINALIZE dual scavenge + re-scan; never kills host Flatpak Chrome; marker prefixbrowser-automation-cli-chrome- - Lifecycle: BORN + FINALIZE scavenge owned Chromium
/tmporphans; product law is residual-zero process + disk - Cache: XDG
cache_backend(sqlite|memory|redis) andcache_redis_url;rediss://fail-closed - Intentional residual: GAP-022 ~53 transitive multi-version dups; GAP-023/024 PRD divergences registered
- Full history in CHANGELOG.md
- The pipe bridge and the X11 pin below were validated live on Linux only
- A Chrome started by the CLI no longer opens a DevTools TCP port, so a local process can no longer read
/json/versionand drive the browser - Chrome now runs with
--remote-debugging-pipe, and a loopback WebSocket bridge relays exactly one valid client on a path holding the 122 random bits of a v4 UUID - The bridge caps each message at 256 MiB and waits at most two seconds for its pipe threads at teardown
- The private Xvfb requires a
MIT-MAGIC-COOKIE-1, kept in a mode 0600 file that teardown removes - A cookie file left by a CLI killed with
SIGKILLis removed by the next launch - The Lightpanda engine and the legacy launch path selected by
chrome_legacy_oxide_launchkeep their previous behaviour
- A headed Chrome inside the private Xvfb no longer opens a window on the Wayland desktop
- The launch pins
--ozone-platform=x11whenever the private display started, and no flag or XDG key passes a platform switch to Chrome, so--no-xvfbis the way to keep your own display - The pin follows the Xvfb that actually started, so a missing Xvfb no longer forces X11 onto a launch with no X server
display_backendreports the display really used:headless,xvfborhost- The extension launch path also starts the private display on headed runs
- The
virtual_displaymessage ofdoctornames the valueautoresolves to on this host
- Two concurrent headed launches no longer share one private display
- Readiness requires the lock file to name the pid of the Xvfb this launch started, and a server that exits is retried on the next free number
- A display number whose lock names a dead process is reused
- The private Xvfb stops with
SIGTERMand a grace period beforeSIGKILL, so it removes its own lock and socket - The private Xvfb writes to the null device instead of a pipe nobody read
- A launch cancelled between the fork and the first readiness wait no longer leaves a Chrome without an owner
- A failed launch kills Chrome's whole process group, not only its pid
--timeoutduring that teardown ends the command with exit 124 instead of 69- The Chrome and Lightpanda output drainers wait at most two seconds at teardown, so a descendant holding the output no longer holds the command
cargo install --path . --locked
browser-automation-cli --version
browser-automation-cli doctor --offline --quick --json
browser-automation-cli doctor --offline --quick --json | jaq '.residual // .data.residual // .'
browser-automation-cli locale --json
browser-automation-cli goto https://example.com --json
browser-automation-cli view --json- Local development install:
git clone https://github.com/danilo-aguiar-br/browser-automation-cli
cargo install --path browser-automation-cli --locked- From crates.io after the first publish:
cargo install browser-automation-cli --locked- Runtime needs Chrome or Chromium on the shell path (or
config set chrome_path) - Optional:
ffmpegfor screencast file export - Optional:
lighthousebinary for lighthouse audits (orconfig set lighthouse_path)
- Always pass
--jsonfor agent pipelines - Keep human diagnostics on stderr with
-qwhen piping - Use
--timeoutfor wall-clock process budget in seconds - Use
run --script(NDJSON lines or a JSON array of steps) for multi-step sessions that need shared@eNrefs - Stream per-step progress with global
--json-steps(NDJSON lines:step,cmd,ok,result) - Prefer CLI flags for one-off agent calls; use
configfor durable XDG defaults - Logging detail:
--verbose/--debug/-q, orconfig set log_level - Localize human suggestions with
--lang pt-BRorconfig set lang pt-BR - Optional scrape
--webhook-urlposts the result once to an operator URL (not product telemetry) - Optional MITM: global
--mitm,--mitm-ca-dir,--mitm-har,--mitm-hosts,--mitm-ws,--mitm-max-body-bytes,--mitm-no-media-bodies,--mitm-redact-secrets
browser-automation-cli config set openrouter_api_key sk-or-...
browser-automation-cli --json goto https://example.com
browser-automation-cli --json wait --text Hello --text Welcome --ms 5000
browser-automation-cli --json scrape https://example.com --format markdown --engine http
browser-automation-cli --json scrape https://example.com --format markdown,html,links --engine browser
browser-automation-cli --json scrape https://example.com --format markdown --engine http --webhook-url https://example.com/hook
browser-automation-cli --json sitemap https://example.com --limit 200
browser-automation-cli --json feed https://example.com/feed.xml
browser-automation-cli --json extract --llm --question "What is the title?" https://example.com
browser-automation-cli --category-memory heap summary --path snap.heapsnapshot --json
browser-automation-cli --json mitm start --seconds 30
browser-automation-cli --json mitm capture-url https://example.com --seconds 30
browser-automation-cli --json mitm capture-url https://example.com --seconds 30 --har /tmp/browser-automation-cli-artifacts/cap.har
browser-automation-cli --json mitm har --out /tmp/browser-automation-cli-artifacts/capture.har
browser-automation-cli --json workflow resume --manifest workflow.toml
browser-automation-cli --json print-pdf --url https://example.com --path /tmp/browser-automation-cli-artifacts/page.pdf
browser-automation-cli --json monitor check --url https://example.com --baseline /tmp/browser-automation-cli-artifacts/base.txt --write-baseline
browser-automation-cli --json parse ./doc.pdf --redact-pii
browser-automation-cli --json parse ./doc.ods
browser-automation-cli --json qr encode --text "hello" --path /tmp/browser-automation-cli-artifacts/qr.png
browser-automation-cli --json qr decode --path /tmp/browser-automation-cli-artifacts/qr.png
browser-automation-cli --json find-paths --glob '**/*.rs' '' src
browser-automation-cli --json sheet-write rows.csv --out /tmp/browser-automation-cli-artifacts/out.xlsx
browser-automation-cli --json sg-scan src
browser-automation-cli --json schema run
browser-automation-cli --json schema --cmd wait
browser-automation-cli --json batch-scrape --urls-file /tmp/urls.txt --format text --engine browser --concurrency 2
browser-automation-cli --capture-console --json assert console-empty
browser-automation-cli --json record --url https://example.com --path /tmp/steps.jsonl --seconds 30 --max-events 200--scripttakes a file path, never inline JSON; write the steps file first (NDJSON, one step per line):
{"cmd":"goto","url":"https://example.com"}
{"cmd":"view"}- Then run that file in one process:
browser-automation-cli --json run --script /tmp/steps.jsonl
browser-automation-cli --json --json-steps run --script /tmp/steps.jsonl- Reading an API payload needs the capture and the navigation in the same process, so put the
netstep in the script (/tmp/net.jsonl):
{"cmd":"goto","url":"https://example.com"}
{"cmd":"net","action":"get","id":"0","response_path":"/tmp/browser-automation-cli-artifacts/res.json"}browser-automation-cli --capture-network --json run --script /tmp/net.jsonl- Global flags are listed by
<cmd> --help, for exampleversion --help, and the root--helplists none of them - Persist a durable default with
browser-automation-cli config set <key> <value>in XDG instead of repeating a flag - Output and payload reduction
--jsonemits machine-readable JSON success and error envelopes on stdout--json-stepsstreams one NDJSON object perrunstep on stdout withstep,cmd,okandresult--correlation-id <ID>sets an id echoed on JSON envelopes and NDJSON steps, and it is not a secret--fields <PATHS>projectsdatadown to ONE CSV of dotted paths relative todata, and repeating the flag exits 2--filter-rows <EXPR>keeps rows matchingkey=value,key!=valueorkey~substring, repeatable and ANDed- A missing field never matches a
--filter-rowsexpression, including under!= --dedupe-by <PATH>drops rows whose dotted-path value repeats and keeps the first--sort-rows <PATH>sorts rows by a dotted path and compares numbers numerically--limit-rows <N>emits at most N rows after filter, dedupe and sort--max-items <N>is an accepted alias of--limit-rowsand limits what is EMITTED, while a command's--limitlimits what is FETCHED--count-onlyemits only{"count": N}instead of the rows--truncate-content <CHARS>cuts every string in the payload to N characters and markstruncated--max-output-bytes <BYTES>is a hard ceiling on emitted bytes that sheds rows from the end and markstruncated--expect <EXPR>asserts the emitted payload with the--filter-rowsgrammar, repeatable and ANDed--expectis evaluated AFTER--fieldsand--filter-rows, over the payload the caller actually receives- An unmet
--expectis listed inagent_ops.expectation_unmetand the exit code stays 0 --expect-exit-codeexits 65 when any--expectis unmet--helpprints help and--versionprints the version
- Time and concurrency
--timeout <SECS>sets the global wall-clock timeout in seconds, where 0 means no override and the maximum is 86400--step-timeout <SECS>sets the per-step timeout ofrunscripts, where 0 inherits the global timeout and the maximum is 86400--max-concurrency <N>caps concurrent I/O tasks for batch, crawl and CDP fan-out, where 0 means auto--min-delay-ms <MS>sets a per-invocation floor between same-origin requests in milliseconds- The effective wait of
--min-delay-msis the maximum of the flag, XDGscrape_min_delay_msand the siteCrawl-delay
- Window and display
--browser-mode <MODE>picksauto,headlessorheadedfor this run and wins over XDGbrowser_mode--headedshows the browser window on your own display for debugging--headlessrequires a headless browser for this run and overrides any persisted mode--no-xvfbskips the private virtual display on Linux and uses the current display
- Capture and artifacts
--artifacts-dir <DIR>sets the directory for screenshots, PDFs and other one-shot artifacts--capture-consolecaptures console messages during browser commands--capture-networkcaptures network requests during browser commands--dump-on-failurewrites the captured console and network evidence to the artifacts dir when the command fails
- Robots and roots
--ignore-robotsskips robots.txt policy checks and requires risk acceptance for blocked hosts--i-accept-robots-riskexplicitly accepts the robots.txt override risk together with--ignore-robots--allow-outside-rootspermits local reads and artifact writes outside the allowed roots
- Stealth and input
--no-stealthturns off the anti-detection patches for this run--stealth-profile <PROFILE>picksauto,chrome-linux,chrome-winorchrome-macas the impersonated identity--stealth-seed <SEED>pins the stealth identity across processes--warmupvisits the origin root before the target URL so the session carries cookies--warmup-url <URL>warms this URL instead of the origin root and implies--warmup--input-profile <PROFILE>pickshuman(default) ordirectinput shaping--input-seed <SEED>seeds the input jitter so ahumanrun reproduces exactly
- Proxy
--proxy <URL>sets the egress proxy for Chrome and the HTTP engine withhttp,httpsorsocks5--proxy-bypass <HOSTS>lists the hosts that bypass the proxy in Chrome bypass-list syntax- Proxy credentials belong in XDG through
config set proxy_url, never in argv
- MITM
--mitmenables the one-shot local MITM proxy and routes Chrome through it--mitm-ca-dir <DIR>sets the directory for the MITM CA key and cert PEM, defaulting to XDG data--mitm-har <FILE>writes HAR 1.2 to this path on FINALIZE when--mitmis active--mitm-hosts <HOSTS>lists the comma-separated hosts to decrypt, and empty means all--mitm-wsrestates the default, because WebSocket frames are always captured under--mitm--mitm-max-body-bytes <BYTES>caps the body bytes retained per exchange--mitm-no-media-bodiesdrops image, video and audio bodies from the capture--mitm-redact-secretsrestates the default redaction of Authorization and Cookie secrets--mitm-no-redact-secretskeeps Authorization and Cookie values readable in the capture
- Category gates
--category-memoryenables the deep heap analysis tools--category-extensionsenables the extension management tools--category-third-partyenables the third-party developer tool surface--category-webmcpenables thewebmcptool surface--experimental-screencastenables the experimental screencast, which may require ffmpeg for file export--experimental-visionenables the coordinateclick-atvision tools
- Language and log
--lang <LANG>forces the UI languageenorpt-BR, and machine JSON stays English-q, --quietsuppresses non-error human logs on stderr-v, --verboseraises stderr verbosity to info--debugturns on maximum tracing detail on stderr--plainforces plain stderr with no ANSI colors
Full agent inventory (71 names via commands --json, sorted):
assert— Assertions on url, text or consoleattr— Read one attribute from a targetaudio— Local audio pipeline one-shot without Chrome: info, download, convert, trimback— History backbatch-scrape— Scrape many URLs from a file, HTTP or browser engine, one-shotclick-at— Click at page CSS coordinates, requires--experimental-visioncommands— List available commandscompletions— Generate shell completions, path-level, no Chromeconfig— XDG config and path management, no.envat runtimeconsole— Captured console messages, requires--capture-consolecookie— Cookie jar helpers for the active page through the Network domaincrawl— Crawl from a seed URL, HTTP BFS or browser, one-shotdevtools3p— Third-party developer tools surface, requires--category-third-partydialog— Accept or dismiss dialogsdoctor— Diagnose Chrome install and one-shot readinessdrag— Drag from one target to another with HTML5 drag-and-dropemulate— Emulate device, network, UA, geolocation or CPUeval— Evaluate JavaScript as an expression or a function declarationexec— Single-step inline command with the same surface asrunstepsextension— Chrome extension tools, requires--category-extensionsextract— Extract text or an attribute from a target, or run an LLM extract with--llmfeed— Read an RSS, Atom or JSON Feed document over HTTPfill-form— Fill multiple form fields from a JSON array of target and value pairsfind-paths— Discover filesystem paths with an fd-like UXforward— History forwardgoto— Navigate to a URL, one-shotgrab— Capture a screenshotheap— Heap snapshot tools, deep analysis requires--category-memoryhover— Hover an elementimage— Local image pipeline one-shot without Chrome: info, convert, resize, download, exifkeys— Press a keyboard keylighthouse— Run a Lighthouse audit through the external binarylocale— Show the resolved UI locale and its detection diagnosticsman— Generate a roff man page, path-level, no Chromemap— Map site URLs from a seed over HTTPmitm— MITM capture, CA and HAR, local one-shotmonitor— One-shot change check against a baseline file by hash or textnet— Captured network requests, requires--capture-networkpage— Page info or multi-tab managementparse— Extract text from a local html, md, txt, pdf, docx or xlsx fileperf— Performance trace and metricspick— Pick an option from a custom select, badge popover orrole=optionpress— Click an element by selector or@eNrefprint-pdf— Print the current page to PDF through CDPPage.printToPDF, one-shotqr— QR encode and decode one-shot without Chromerecord— Record page interactions as a replayablerun --scriptNDJSON filereload— Reload the current pageresize— Resize the page viewportrun— Run a multi-step script in one process, NDJSON or JSON array of stepsschema— JSON Schema fragment for a command, acceptingschema runorschema --cmd runscrape— Navigate and return body text or formats, local HTTP or CDPscreencast— Screencast start and stop, experimentalscroll— Scroll the page or an element by delta pixelssearch— Local search over HTTP SERP links or a URL mapselect-option— Pick an option from a custom select, badge popover orrole=optionsg-rewrite— Structural rewrite for known-safe fixes, dry-run by default and--applywritessg-scan— Structural lint scan for forbidden product patterns, one-shotsheet-write— Write a simple XLSX workbook from CSV or JSON, one-shotsitemap— List the URLs declared by a site's sitemap.xml over HTTPstorage— Export or import portable auth state: cookies, localStorage and sessionStoragesubmit— Submit a form, or the form owning a field, and wait for its outcometext— Extract visible text from a targettype— Type text into--targetor into the focused element with--focus-onlyupload— Upload a file to a file inputversion— Print the CLI versionvideo— Local video pipeline one-shot without Chrome: info, download, convert, to-mp3, trim, thumbnail, manifestview— Accessibility snapshot with@eNrefswait— Wait for milliseconds, text, selector or load statewebmcp— Web surface tools, requires--category-webmcpworkflow— Workflow journal DAG backed by SQLitewrite— Fill an input value with smart fill for select, checkbox, radio and text
Grouped for humans:
- Discovery:
doctor,commands,schema,version,locale,man,completions - Navigate:
goto,back,forward,reload - Interact:
press,write,type,keys,wait,hover,drag,fill-form,select-option,pick,submit,upload,click-at - Observe:
view,extract,text,scroll,attr,assert,grab - Scrape:
scrape,batch-scrape,crawl,map,sitemap,feed,search,parse - Capture:
console,net,print-pdf,monitor,screencast - Tabs/Dialogs:
page,dialog,cookie,storage - Utils:
qr,image,video,audio,find-paths,sheet-write,sg-scan,sg-rewrite - Advanced:
eval,emulate,resize,perf,lighthouse,heap,extension,devtools3p,webmcp,mitm,workflow - Config:
config path|init|show|set|get|unset|list-keys - Multi-step:
run,exec,record - Record teaching:
browser-automation-cli --json record --url https://example.com --path /tmp/steps.jsonl --seconds 30 --max-events 200writes page interactions as replayable NDJSON, thenbrowser-automation-cli --json run --script /tmp/steps.jsonlreplays them in one process - Audio teaching:
browser-automation-cli --json audio info|download|convert|trimruns the local audio pipeline without Chrome - Sitemap teaching:
browser-automation-cli --json sitemap https://example.com --limit 200reads the DECLARED sitemap — therobots.txtSitemap:hints, the document itself, and nestedsitemapindexdescent — and never walks the link graph, so there is no--depthto pass - Feed teaching:
browser-automation-cli --json feed https://example.com/feed.xmlparses RSS, Atom and JSON Feed from the RAW body over the HTTP engine; the HTML-shaping flags are absent because a selector would destroy the document, and Chrome is not offered because it would render the browser's XML viewer instead of the feed - Inventory note: 71 agent-facing names via
commands --json(includesselect-option,pick,submit,storage,image+video+audio+record); DevTools e2e covers 53 tools (lighthouse mock SKIP)
- Stealth is ON by default and masks the automation markers a real Chrome never exposes
--no-stealthturns the anti-detection patches off for one run--stealth-profile <PROFILE>picks the impersonated identity:auto,chrome-linux,chrome-win,chrome-mac(listprints the tokens)--stealth-seed <SEED>pinshardwareConcurrency,deviceMemory, GPU vendor/renderer andhistory.length— not UA, platform, languages, timezone, screen, plugins or the Chrome build, which comes from the identity crate with a User-Agent override and from the installed Chrome without onedoctor --fingerprintcompares webdriver, platform vs UA, and screen vs viewport; without--quickit scores the live page and fails if the page contradicts the plan- Launch applies 1920×1080 device metrics so
screenis not the headless 800×600 default;config set screen WxHand run-stepscreenare the explicit knobs autofollows the host and is almost always right--stealth-seed <SEED>pins that identity across processes- With a seed the Chrome major of the last launch is also stored in
state_dir/stealth/host-major-<hash>.txt, so the HTTP engine announces that major; without a seed, or under--no-stealth, nothing about it touches the disk scrapereports where the announced Chrome major came from inuser_agent_major_source:projected,host_binary,host_unprobed, ornullunder--no-stealth- Without a seed every run draws a fresh identity, so a 50-URL crawl of 50 one-shot processes presents 50 different machines
--proxy <URL>sets the egress proxy for Chrome and for the HTTP engine, acceptinghttp,https, andsocks5--proxy-bypass <HOSTS>lists the hosts that skip the proxy, in Chrome's bypass-list syntax--input-profile <PROFILE>ishuman(default) ordirecthumaninterpolates pointer trajectories, dwells between press and release, and paces typing- Measured 2026-09-04 on this tree: the
humanpacing cost grows superlinearly with the typed length, at 2281 ms for 1 character, 14236 ms for 2 and 95781 ms for 4, so a longtypecan exhaust--timeoutand return exit 124 - Pass
--input-profile directwhen the field is long and the pacing does not matter; this is an OPEN defect, tracked ingaps.md, and the workaround is stated here rather than left for the operator to discover through a timeout --input-seed <SEED>seeds the input jitter so ahumanrun reproduces exactly--warmupvisits the origin root before the target URL, so the session already carries cookies and a referrer chain--warmup-url <URL>warms that URL instead of the target's origin root--no-xvfbskips the private virtual display on Linux and uses the current one (only meaningful headed on Linux)--expect <EXPR>asserts the emitted payload matcheskey=value,key!=value, orkey~substring; it repeats and every expression is ANDed--expect-exit-codeexits65when an expectation is unmet, instead of only reporting it- It stays off by default because changing an exit code on data content would silently break callers that already branch on it
- Durable XDG keys:
stealth(true),stealth_profile(auto),stealth_seed,browser_mode(auto),input_profile(human) browser_modeisauto|headed|headless;autoresolves to headed inside a private virtual display on Linux with Xvfb on PATH and without--no-xvfb, and to headless in every other case;doctorreports the effective mode- Proxy XDG keys:
proxy_url,proxy_bypass,proxy_username,proxy_password,cdp_proxy_bypass_loopback(true) - Keep proxy credentials in XDG only, because argv shows up in the process table
cdp_proxy_bypass_loopbackalways bypasses loopback so the CDP control channel survives a proxyrobots_user_agentsets the user-agent token robots.txt rules are matched against- HTTP/2 fingerprint keys:
http2_enabled(true),http2_initial_stream_window_size(6291456),http2_initial_connection_window_size(15663105),http2_max_header_list_size(262144),http2_max_frame_size(16384),http2_adaptive_window(false) http2_adaptive_windowstays off so the fingerprint stays constant- Input kinematics keys:
input_move_steps(24),input_move_gap_ms(12),input_click_dwell_ms(65),input_key_dwell_ms(45),input_type_delay_ms(95),input_scroll_tick_px(100),input_scroll_max_ticks(40),input_target_jitter_px(3),input_scroll_settle_rounds(3) - Input dispersion and rhythm keys:
input_timing_distribution(lognormal),input_move_steps_stddev(6),input_move_gap_stddev_ms(5),input_click_dwell_stddev_ms(26),input_key_dwell_stddev_ms(18),input_type_delay_stddev_ms(40),input_scroll_tick_stddev_px(25),input_word_pause_ms(320),input_word_pause_permille(120),input_typo_permille(0) input_timing_distributionislognormal|normal|uniformand governs the fast rhythm only, because the long-pause tail isinput_word_pause_permilleinput_word_pause_permilleaccepts0as a legitimate value, which removes the long word-boundary pause tail entirelyinput_typo_permillestays at0because a mistyped character corrected with Backspace changes what the page sees mid-worduser_data_dirhas no default and stays absent, and that absence is what upholds the residual-zero disk guarantee- Turning
user_data_diron is opt-in and gives up that guarantee, because the Chrome profile then persists across runs capture_preserved_rings(3) is the number of navigation boundaries kept forconsoleandnet --include-preserved
browser-automation-cli --json --stealth-seed fleet-01 goto https://example.com
browser-automation-cli --json --proxy socks5://127.0.0.1:1080 scrape https://example.com --format text --engine http
browser-automation-cli --json --input-profile human --input-seed 42 goto https://example.com
browser-automation-cli --json --warmup goto https://example.com/deep/page
browser-automation-cli --json --warmup-url https://example.com/login goto https://example.com/app
browser-automation-cli --json --no-stealth goto http://127.0.0.1:8080
browser-automation-cli --json config set stealth_profile chrome-linux
browser-automation-cli --json config set proxy_url http://user:pass@127.0.0.1:8888
browser-automation-cli --json config unset stealth_seed- Prefer CLI flags for one-off agent calls
- Product settings only via flags and XDG
config path|init|show|set|get|unset|list-keys - Discover the full key list (count is not fixed at 16) with
config list-keys --json - Every key with its default and description: XDG Key Reference
- Important keys:
dialog_settle_ms,chrome_path,lighthouse_path,openrouter_api_key,llm_base_url,llm_model,cache_backend,cache_redis_url,lang,log_level - Logging:
--verbose/--debug/-q, or XDGconfig set log_level/log_to_file - Color:
config set color true|false - Chrome binary: shell path or XDG
config set chrome_path - Lighthouse binary: flag
--lighthouse-path, XDGconfig set lighthouse_path, or PATH (envelope reportsbinary_source) - Dialog settle budget: XDG
config set dialog_settle_ms <ms>(agent-visibledialog_settledon dialog accept|dismiss) - Cache:
config set cache_backend sqlite|memory|redisand optionalcache_redis_url(redis://only;rediss://fail-closed) config initcreates XDG layout and default config.tomlconfig unset <KEY>restores one key to its built-in default and is the real inverse ofsetconfig set <key> ""is not an inverse: on a string key it writes an empty value the normal path never produces, and on a numeric key it is a parse error- Unsetting a key that is already absent succeeds, so a script never needs to know the previous state
config pathprints resolved config, data, cache, state, and browsers_dir paths- CLI flags override values stored in config.toml
- Doctor reports browsers_dir, lighthouse source,
cache_redis, andresidual_diskamong readiness checks - Doctor JSON top-level field
residualreports:scanned_roots,cli_marker_dirs,chromium_tmp_singleton_orphans,scavenge_safe_candidates,live_cli_marker_processes(legacy),sibling_live_processes,orphan_marker_dirs,foreign_root_orphans,ghost_marker_processes,process_table_unavailable
- This section lists all 217 XDG keys grouped by family, each with its built-in default and its description
- The source of truth is
browser-automation-cli --json config list-keys, which answers with the same key, default and description - Set a key with
config set <key> <value>, read it withconfig get <key>and restore its default withconfig unset <key> - A default of none means the key stays absent until you set it
- The descriptions mirror docs/CONFIGURATION.md, and the defaults come from the binary
audio_default_bitrate— Default bitrate for lossy audio encode. Default:192kaudio_default_format— Default audio convert formatmp3,m4a,ogg,opus,flac,wavoraac. Default:mp3audio_download_max_bytes— Max HTTP body bytes for audio download. Default:256000000audio_max_input_bytes— Max bytes for audio stdin materialization or path pre-check. Default:256000000
browser_close_wait_secs—Browser.closeand process wait budget during FINALIZE in seconds. Default:5browser_mode— Window mode:autoresolves toheadedinside a private virtual display on Linux with Xvfb on PATH and without--no-xvfb, and toheadlessin every other case;headedputs a real window on your display, and on Linux that window is rendered into a private virtual display when Xvfb is available;headlessis cheapest and most detectable.--headedstill wins. Inverting theautodefault carries a latency bill and is a separate decision;doctorreports whatautoresolves to on this host under thevirtual_displaycheck, so the answer never drifts from the binary. Default:autobrowser_scrape_max_body_bytes— Max body bytes for browser-engine scrape helpers. Default:2000000
cache_backend— Cache backendsqlite,memoryorredis. Default:sqlitecache_max_resp_bulk_bytes— Redis RESP bulk string size ceiling in bytes. Default:16777216cache_max_resp_line_bytes— Redis RESP line size ceiling in bytes. Default:16777216cache_redis_url— Redis URL required when the backend isredis. Default: none
capture_preserved_rings— Navigation boundaries kept for console and net--include-preserved. Default:3
cdp_connection_probe_timeout_secs— CDPBrowser.getVersionliveness probe timeout in seconds. Default:3cdp_discovery_max_body_bytes— Max CDP discovery HTTP body bytes for/json/versionand/json/list. Only the Lightpanda readiness probe reads it, because the self-spawned Chrome uses the DevTools pipe. Default:1048576cdp_discovery_timeout_secs— CDP HTTP discovery timeout for/json/versionprobes in seconds. No launch path reads it: the self-spawned Chrome uses the DevTools pipe and exposes no/json/version, and Lightpanda readiness useslightpanda_discovery_timeout_ms. Default:2cdp_event_broadcast_capacity— Process-local CDP event broadcast channel capacity. Default:4096cdp_event_drain_poll_ms— CDP event drain poll slice during navigation wait in milliseconds. Default:100cdp_network_idle_settle_ms— CDP network-idle settle window in milliseconds. Default:500cdp_proxy_bypass_loopback— Always bypass loopback when Chrome runs behind--proxy. The CDP control channel is loopback, so a proxy that captures it produces a browser that never answers — reported as a Chrome startup timeout, which blames the wrong component. Default:truecdp_target_event_wait_ms— CDP target event short wait in milliseconds. Default:600
chrome_default_timeout_ms— Default per-operation timeout for the Chrome engine in milliseconds. Default:25000chrome_legacy_oxide_launch— Launch Chrome through the legacy path instead of the self-spawn path as a stabilization fallback that loses the residual kill target, reopens an unauthenticated loopback DevTools port and never starts the private Xvfb. Default:falsechrome_path— Absolute Chrome or Chromium path. Default: nonechrome_search_paths— Ordered Chrome or Chromium discovery paths, platform-separated; empty uses the built-in per-OS layout. Default: nonechrome_startup_timeout_secs— Chrome self-spawn CDP readiness wait in seconds, measured on the DevTools pipe bridge; the bridge gives the CDP client twice this budget to connect. Default:20
default_jpeg_quality— JPEG quality in range1..=100whengrabomits--quality. Default:80default_viewport_height— Default headless Chrome window height (--window-size) when launch options omit the viewport. Default:1080default_viewport_width— Default headless Chrome window width (--window-size) when launch options omit the viewport. Default:1920
heap_dominator_max_states— Dominator visited-state ceiling against pathological graphs. Default:50000heap_final_iters— Heap snapshot final drain iterations. Default:20heap_inner_iters— Heap snapshot inner drain iterations after finished. Default:10heap_max_class_nodes— Heapclass_nodeslist cap. Default:500heap_max_edges— Heap node-op max edges returned. Default:200heap_max_path_depth— Heap paths max depth. Default:8heap_max_paths— Heap paths enumeration max paths. Default:32heap_max_retainers— Heap node-op max retainers returned. Default:200heap_outer_iters— Heap snapshot outer poll max iterations. Default:200heap_snapshot_max_bytes— Offline heap snapshot file size ceiling in bytes. Default:536870912
http_connect_timeout_secs— HTTP connect-phase timeout in seconds. Default:10http_pool_max_idle_per_host— HTTP pool max idle connections per host. Default:4http_redirect_max— Max HTTP redirects followed by product clients. Default:10http_ssrf_mode— HTTP SSRF policystrict,allow_loopbackoroff. Default:stricthttp_timeout_secs— Shared HTTP client total timeout in seconds. Default:30
http2_adaptive_window— Let the HTTP/2 stack resize windows dynamically. Off keeps the advertised values fixed, which is what makes the fingerprint reproducible. Default:falsehttp2_enabled— Offerh2in ALPN. ALPN is visible in the clear during the TLS handshake and Chrome always listsh2, so a client that offers onlyhttp/1.1has answered "not a browser" before sending a byte. Default:truehttp2_initial_connection_window_size— Connection-level flow-control window advertised to the peer. Default:15663105http2_initial_stream_window_size—SETTINGS_INITIAL_WINDOW_SIZEadvertised to the peer. Library defaults are three orders of magnitude away from Chrome's. Default:6291456http2_max_frame_size—SETTINGS_MAX_FRAME_SIZEadvertised to the peer. Default:16384http2_max_header_list_size—SETTINGS_MAX_HEADER_LIST_SIZEadvertised to the peer. Default:262144
image_avif_speed— AVIF encoder speed in range1..=10where one is slowest and best, needs theimage-aviffeature. Default:6image_default_format— Default image convert formatpng,jpeg,webporgif. Default:pngimage_default_quality— Default lossy quality in range1..=100for image convert and resize. Default:85image_download_max_bytes— Max HTTP body bytes for image download. Default:32000000image_max_input_bytes— Max bytes for local image decode, convert or resize input. Default:32000000image_max_pixels— Max width times height for image decode as anti-bomb guard. Default:64000000
input_click_dwell_ms— Hold time betweenmousePressedandmouseReleasedin milliseconds. Default:65input_click_dwell_stddev_ms— Standard deviation of the press-to-release hold in milliseconds. Default:26input_key_dwell_ms— Hold time betweenkeyDownandkeyUpin milliseconds. Default:45input_key_dwell_stddev_ms— Standard deviation of thekeyDown-to-keyUphold in milliseconds. Default:18input_move_gap_ms— Delay between synthesized pointer positions in milliseconds. Default:12input_move_gap_stddev_ms— Standard deviation of the delay between synthesized pointer positions in milliseconds. Default:5input_move_steps— Intermediate pointer positions synthesized for one move (human profile). Default:24input_move_steps_stddev— Standard deviation of the per-gesture pointer sample budget, so two moves over the same distance do not carry the same number of intermediate positions. A drag rescales this to its own smaller budget instead of carrying the absolute value across. Default:6input_profile— Default input shaping when--input-profileis absent:humansynthesizes a trajectory, wheel ticks and key events;directkeeps the pre-0.1.8 dispatch. The flag still wins. Default:humaninput_scroll_max_ticks— Ceiling on the number of wheel ticks one scroll gesture synthesizes. Each tick is a CDP round trip, so without a ceiling the cost of a scroll grows linearly with the distance requested and a large--delta-yexhausts the command timeout. Past the ceiling the ticks carry more pixels each; total travel is unchanged and only the granularity degrades. Default:40input_scroll_settle_rounds— Extra rounds allowed to deliver a wheel delta the renderer dropped. Default:3input_scroll_tick_px— Scroll distance carried by one synthesized wheel tick in CSS pixels. Default:100input_scroll_tick_stddev_px— Standard deviation of the distance one synthesized wheel tick carries in CSS pixels. Default:25input_target_jitter_px— Radius of the random offset applied to a click target in CSS pixels. Default:3input_timing_distribution— Shape of the dispersion drawn around every input delay:lognormal,normaloruniform.lognormalis the default because human inter-key intervals are right-skewed, and a symmetric draw reproduces the width of the human distribution without its asymmetry. It governs the fast rhythm only; the long-pause tail isinput_word_pause_permille. Every mean is floored at 5% dispersion and truncated between a quarter and four times itself, so setting a standard deviation to0does not buy the zero variance a detector reads as machine. Default:lognormalinput_type_delay_ms— Delay between characters while typing in milliseconds. Default:95input_type_delay_stddev_ms— Standard deviation of the delay between characters in milliseconds. A caller that asks for its own typing rhythm gets this dispersion rescaled by the same ratio, so halving the mean halves the spread instead of leaving an absolute value that no longer fits. Default:40input_typo_permille— Chance in a thousand that a character is typed wrong, erased withBackspaceand retyped. The field always ends up holding exactly the requested text.0by default, and the only humanisation key that is: every other one disperses TIMING, which a page cannot read as a different value, while this one changes the CHARACTER STREAM, so aninputlistener sees the wrong prefix and may autocomplete or navigate on it. The wrong key is always a physical neighbour on the QWERTY row. Default:0input_word_pause_ms— Mean of the extra pause taken at a word or sentence boundary in milliseconds, itself dispersed by half of its value. This pause is what produces the long right tail of a typing trace, which no amount of jitter around the per-character mean can create. Default:320input_word_pause_permille— Chance in a thousand that a word or sentence boundary earns that long pause.0removes the tail and leaves only the fast rhythm. Default:120
lightpanda_cdp_connect_timeout_secs— Lightpanda CDP connect attempt timeout in seconds. Default:5lightpanda_discovery_timeout_ms— Per-probe CDP discovery timeout while waiting for Lightpanda in milliseconds. Default:500lightpanda_max_log_lines— Bounded Lightpanda launch log ring in lines per stream. Default:40lightpanda_poll_interval_ms— Lightpanda CDP readiness poll interval in milliseconds. Default:100lightpanda_ready_slice_ms— Drain slice after Lightpanda child exit before snapshotting logs in milliseconds. Default:25lightpanda_session_timeout_secs— Lightpanda--timeoutsession max in seconds, range1..=604800. Default:604800lightpanda_startup_timeout_secs— Lightpanda process startup wait in seconds. Default:10lightpanda_target_init_timeout_secs— Lightpanda target init wait after connect in seconds. Default:10
llm_base_url— OpenAI-compatible base URL. Default: nonellm_http_timeout_secs— LLM and webhook blocking HTTP timeout in seconds. Default:60llm_model— Default LLM model id. Default: none
log_level— TracingEnvFilterused when argv flags stay quiet. Default:errorlog_rotation— Rolling policydaily,hourlyornever. Default:dailylog_to_file— Rotated local JSON logs under XDG state, never remote. Default:false
max_cli_json_payload_bytes— Max bytes for CLI flag JSON payloads. Default:4194304max_json_file_bytes— Max bytes for JSON or NDJSON script and manifest files. Default:33554432max_log_files— Retained rotated log files in range1..=90. Default:14max_ndjson_line_bytes— Max bytes for one NDJSON line in run scripts and traces. Default:1048576max_sg_file_bytes— Max bytes for one source file read bysg-scanandsg-rewrite. Default:16777216max_urls_file_bytes— Max bytes for thebatch-scrape --urls-filelist. Default:8388608
mitm_ca_cache_size— MITM dynamic certificate cache size in hosts. Default:1000mitm_capture_wait_max_ms— MITM capture wait ceiling after navigate in milliseconds. Default:8000mitm_capture_wait_min_ms— MITM capture wait floor after navigate in milliseconds. Default:800mitm_chrome_settle_ms— MITM Chrome launch settle before navigation in milliseconds. Default:150mitm_list_limit_max— MITM list and query max items clamp. Default:10000mitm_proxy_seconds_max— MITM proxy one-shot max window in seconds. Default:600mitm_rebind_attempts— MITM proxy bind retries when the port is transiently in use. Default:3mitm_ws_frames_cap— Cap on in-memory WebSocket frames per capture process. Default:500mitm_ws_preview_chars— WebSocket text preview truncation in Unicode chars. Default:256
perf_autostop_settle_ms— Perf auto-stop settle after load or reload in milliseconds. Default:500perf_trace_inner_iters— Perf trace inner drain iterations after complete. Default:5perf_trace_inner_slice_ms— Perf trace poll inner slice in milliseconds. Default:20perf_trace_outer_iters— Perf trace outer poll max iterations. Default:100perf_trace_outer_slice_ms— Perf trace outer poll interval in milliseconds. Default:50
proxy_bypass— Hosts bypassing the proxy, in Chrome's bypass-list syntax. Default: noneproxy_password— Proxy password, sent as basic auth. Never echoed byconfig getorconfig show. Default: noneproxy_url— Egress proxy for both Chrome and the HTTP engine (http,https,socks5,socks5h). Put credentials here rather than in--proxy, where the process table exposes them. Default: noneproxy_username— Proxy account name, sent as basic auth. Kept here rather than in argv, where the process table would expose it. Default: none
redis_allow_remote— Allow non-loopback Redis hosts, false when unset. Default:falseredis_connect_timeout_secs— Redis TCP connect timeout in seconds. Default:2redis_io_timeout_secs— Redis RESP stream I/O timeout in seconds. Default:3
retry_base_delay_ms— Default retry base delay in milliseconds. Default:50retry_budget_secs— Default retry wall budget in seconds. Default:10retry_cdp_base_delay_ms— CDP retry base delay in milliseconds. Default:100retry_cdp_budget_secs— CDP retry wall budget in seconds. Default:15retry_cdp_max_attempts— CDP retry max attempts. Default:4retry_cdp_max_delay_secs— CDP retry max delay in seconds. Default:3retry_default_max_attempts— Default retry max attempts including the first try. Default:3retry_http_base_delay_ms— HTTP scrape retry base delay in milliseconds. Default:75retry_http_budget_secs— HTTP scrape retry wall budget in seconds. Default:12retry_http_max_attempts— HTTP scrape retry max attempts. Default:3retry_http_max_delay_secs— HTTP scrape retry max delay in seconds. Default:2retry_llm_base_delay_ms— LLM HTTP retry base delay in milliseconds. Default:200retry_llm_budget_secs— LLM HTTP retry wall budget in seconds. Default:20retry_llm_max_attempts— LLM HTTP retry max attempts. Default:2retry_llm_max_delay_secs— LLM HTTP retry max delay in seconds. Default:4retry_max_delay_secs— Default retry max delay in seconds. Default:2
robots_loopback_exempt— Loopback hosts skiprobots.txt; set false to enforce against localhost. Default:truerobots_max_body_bytes— Maxrobots.txtbody bytes as anti-OOM guard. Default:524288robots_probe_timeout_secs—robots.txtrequest timeout in seconds. Default:5robots_user_agent— User-agent token thatrobots.txtrules are matched against. Set it when stealth sends a browser User-Agent, so the rules evaluated are the ones that apply to the request actually sent. Default: none
scrape_charset_peek_bytes— Charset sniffing peek window in bytes. Default:4096scrape_crawl_limit_max— Max crawl page budget as anti-DoS clamp for--limit. Default:500scrape_crawl_max_depth— Max BFS depth forcrawlandmap. Default:10scrape_dedup_similar— Collapse near-duplicate pages by content similarity incrawlandbatch-scrape. Default:falsescrape_dedup_similar_distance— SimHash Hamming distance in range0..=64under which pages are near-duplicates. Default:3scrape_default_engine— Default scrape engine when the CLI omits--engine,httporbrowser. Default:httpscrape_delay_jitter_ratio— Politeness delay jitter ratio in range0.0..=1.0, zero disables. Default:0.2scrape_feed_max_entries— Max entries kept by scrape formatfeedfor RSS, Atom and JSON Feed. Default:50scrape_follow_rel_next— Followrel=nextpagination links during crawl. Default:falsescrape_honor_meta_robots— Honor meta robots andX-Robots-Tagnoindex. Default:truescrape_honor_nofollow— Skiprel=nofollowlinks in crawl discovery. Default:truescrape_http_cache_ttl_secs— HTTP scrape response L2 cache TTL in seconds. Default:3600scrape_max_body_bytes— Max HTTP scrape body bytes. Default:5000000scrape_max_parse_bytes— Max local file parse size in bytes before reject. Default:50000000scrape_max_text_chars— Max text or markdown chars in scrape envelopes, zero means no cap. Default:32768scrape_min_delay_ms— Floor delay between same-origin GETs in milliseconds. Default:0scrape_no_cache— Ignore the response cache on READ and always fetch from origin. The fresh response is still written, so a bypassing call refreshes the entry for later callers instead of leaving a stale one.--no-cacheonscrapeoverrides this per invocation. There is no way to express the same thing withscrape_http_cache_ttl_secs: a TTL of0already means "never expires", which is the opposite, and the key rejects it.monitor checkbypasses unconditionally and ignores this key, because a cached body made it compare a stored page with itself and reportchanged: false. Default:falsescrape_search_limit_max— Max search result budget as anti-DoS clamp. Default:50scrape_sitemap_max_bytes— Max sitemap body bytes. Default:2000000scrape_summary_chars— Max chars for scrape formatsummary. Default:400scrape_use_sitemap— Prefersitemap.xmlwhen mapping a site. Default:true
screencast_ffmpeg_framerate— Screencastffmpeginput framerate in frames per second. Default:10screencast_jpeg_quality— Screencast CDP JPEG quality in range1..=100. Default:60screencast_start_pump_iters— Immediate pump iterations afterPage.startScreencast. Default:15screencast_stop_pump_iters— Drain pump iterations beforePage.stopScreencast. Default:40
state_collect_deadline_secs— CDP storage collect outer deadline in seconds. Default:5state_event_recv_secs— CDP storage event recv slice in seconds. Default:2state_load_settle_ms— Settle delay afterload_statenavigation in milliseconds. Default:500
stealth— Anti-detection patches applied before the first navigation.--no-stealthturns them off for one run. Default:truestealth_profile— Impersonated identity:auto,chrome-linux,chrome-win,chrome-mac.autofollows the host, which is the only value that cannot contradict the Canvas and WebGL hashes the real GPU produces. Default:autostealth_seed— Pins the stealth identity so the same fingerprint is reproduced across processes. Absent means a fresh identity each run, which is the default precisely because caching an identity writes it to disk. Default: none
svg_max_bytes— Max SVG source bytes accepted before rasterisation. Default:4000000svg_max_depth— Max XML nesting depth accepted in an SVG source. Default:128svg_max_entities— Max<!ENTITY>declarations tolerated in an SVG DTD, zero rejects any. Default:0
video_default_audio_bitrate— Default bitrate for videoto-mp3. Default:192kvideo_default_container— Default video convert containermp4,webm,mkv,mov,aviorm4v. Default:mp4video_default_crf— Default CRF in range1..=51for lossy video re-encode. Default:23video_download_max_bytes— Max HTTP body bytes for video download. Default:512000000video_max_input_bytes— Max bytes for video stdin materialization or path pre-check. Default:512000000
webhook_max_attempts— Webhook max attempts including the first try. Default:3webhook_post_timeout_secs— Operator webhook POST timeout in seconds. Default:15webhook_retry_base_delay_ms— Webhook retry base delay in milliseconds, doubled each attempt. Default:50
allowed_roots— Extra allowed roots for local reads and artifact writes, platform-separated; defaults cover cwd, XDG dirs and temp. Default: noneartifacts_dir— Artifacts output directory. Default: nonecolor— ANSI colors on human stderr. Default: nonedialog_settle_ms— Max wait after a JS dialog answer forjavascriptDialogClosedin milliseconds. Default:2000dom_stable_window_ms— Quiet window forwait --dom-stable-msin milliseconds. Default:500drag_move_gap_ms— Delay between synthesized drag positions in milliseconds. Default:16drag_move_steps— Intermediate mouse positions synthesized for one HTML5 drag. Default:6encryption_key— Session encryption key material. Default: noneeval_drain_slice_ms— Eval drain slice while waiting forRuntime.evaluateresults in milliseconds. Default:40event_pump_slice_ms— Wait and eval event pump slice in milliseconds. Default:50event_tracker_max_entries— In-memory console and network tracker ring size per page session. Default:1000extension_attach_poll_iters— Extension attach poll iterations; slice x iterations is the total wait. Default:20extension_attach_poll_ms— Extension attach poll slice in milliseconds. Default:150ffmpeg_path— Absoluteffmpegpath for screencast encode and video convert orto-mp3. Default: noneffmpeg_timeout_secs— Wall-clockffmpegencode timeout in seconds, range1..=3600. Default:120file_parse_cache_ttl_secs— Local file-parse L2 cache TTL in seconds. Default:86400gif_max_frames— Max animation frames decoded from a GIF. Default:2000ignore_robots— Default robots ignore, with both CLI risk flags still required. Default:falseinteract_settle_ms— UI settle delay after click, type or extension action in milliseconds. Default:200lang— Message locale override (enorpt-BR; bareptrejected). Default: nonelighthouse_path— AbsolutelighthouseCLI path. Default: nonelighthouse_timeout_secs— Wall-clocklighthouseCLI timeout in seconds, range1..=3600. Default:300manifest_max_bytes— Max bytes accepted for an HLS or DASH manifest body. Default:8000000manifest_max_variants— Max variant or representation entries emitted per manifest envelope. Default:500monitor_diff_max_bytes— Byte ceiling for themonitor check --diff-modepayload. A page rewritten wholesale diffs to the whole page twice, and the caller asked what changed, not for everything.diff_truncatedsays when the ceiling applied, andadded_count/removed_countkeep reporting the real size. Default:65536namespace— Isolated state namespace. Default: nonenav_micro_settle_ms— Navigation micro-settle after page transitions in milliseconds. Default:100network_idle_window_ms— Quiet window forwait --network-idlein milliseconds. Default:500openrouter_api_key— LLM API key stored with permission0600. Default: noneplatform_child_poll_ms— Child-process exit poll interval during FINALIZE in milliseconds. Default:50platform_child_wait_secs— Platform child wait deadline in seconds. Default:5residual_orphan_min_age_secs— Age floor in seconds before a dead-owner marker profile is collectable. Default:60run_max_include_depth— Max nesting depth forrun --scriptinclude chains. Default:16screen— Default page screenWxHforEmulation.setDeviceMetricsOverride(screen.width/screen.height). Absent = mirror the viewport. Argv--screenand arunemulate/resizescreenfield still win. Never smaller than the viewport. Default: nonesearch_base_url— HTML search endpoint base with?q=appended. Default:https://html.duckduckgo.com/html/shutdown_deadline_secs— Shutdown hard deadline waiting for browser exit in seconds. Default:30support_settle_ms— Support-thread settle for sync helpers in milliseconds. Default:80timeout— Global timeout in seconds. Default:0user_data_dir— persistent Chrome profile directory, opt-in. Unset by default, and unset is what keeps residual-zero: the launch gets a throwaway profile and the run leaves nothing on disk. Set it only when a detector attests session across invocations, because a persistent profile is a directory this CLI will never delete for you. Created with mode 0700 on Unix.--profileon argv wins over this key. Default: none
- This crate has no Cargo feature flags
- Optional categories are process flags, not compile-time features
--category-memoryenables deep heap tools--category-extensionsenables extension tools--category-third-partyenables third-party DevTools helpers--category-webmcpenables webmcp tools--experimental-visionenablesclick-at--experimental-screencastenables screencast export with ffmpeg
- Documented for
x86_64-unknown-linux-gnu - Documented for
x86_64-apple-darwin - Documented for
aarch64-apple-darwin - Documented for
x86_64-pc-windows-msvc - Documented for
aarch64-unknown-linux-musl - Not supported on
wasm32-unknown-unknown(Chrome CDP requires a desktop browser) - docs.rs metadata declares these targets explicitly after the 2026-05-01 multi-target change
- Minimum Supported Rust Version is 1.88.0
- Policy: bump MSRV only in minor or major releases with CHANGELOG note
- Local docs:
timeout 180 cargo doc --no-deps
- Claude Code, Codex, Cursor, and shell agents spawn one process per action
- Multi-step agent plans must use
run --script(NDJSON or JSON array) instead of chaining separate processes - Parse stdout with
jaqand ignore stderr unless diagnosing failures - Stream step progress with
--json-stepswhen agents need progressive feedback - Persist durable defaults with
config setunder XDG - See INTEGRATIONS.md and docs/AGENTS.md
- Cold start is dominated by Chrome launch, not Rust binary size
- Prefer
doctor --offline --quickfor install checks without network - Reuse multi-step scripts to avoid repeated Chrome launches
- Prefer
scrape --engine httpwhen CDP is not required - Use
batch-scrapeconcurrency for parallel fetches (--engine httpdefault;--engine browserwhen JS render is required)
- Expect Chrome process memory far above the CLI binary itself
- Heap tools need
--category-memoryand larger snapshots increase RAM use - Screencast export may invoke ffmpeg as an external helper
- Workflow journals and MITM captures land under XDG state/data paths
- Chrome not found: install Chromium or Google Chrome, ensure it is on the shell path, or
config set chrome_path, then re-rundoctor - Config / XDG: run
config initthenconfig pathto inspect layout; useconfig set|getfor values - Product settings only via flags and
config set(XDG) - Exit 69 unavailable: browser binary missing, blocked, or not launchable
- Exit 124 timeout: raise
--timeoutor shorten the script - Exit 2 usage: re-check flags with
browser-automation-cli help <cmd>; with--jsonon argv, clap usage errors emit JSON envelopes @eNrefs invalid across commands: keep steps inside onerunprocess; refs do not span processes- Network empty: pass
--capture-networkon the same process that navigates - API payload read:
net get <IDX>writes bodies with--response-pathand--request-path, butnet listandnet getonly see traffic captured in the same process, so a standalonenet get 0after a separategotorefuses with exit 2; put anetstep next to thegotostep in one script and runbrowser-automation-cli --capture-network --json run --script /tmp/net.jsonl - Wait multi-text: repeat
--textfor OR semantics (any listed text unblocks) - Wait multi-selector / URL: CSS OR
#a, #b; inrunuseurl/url_contains/navigation - View empty blank: empty about:blank refuses silent success unless
--allow-empty/allow_empty:true - MITM bind:
mitm startandmitm capture-urllisten on127.0.0.1only with an ephemeral port - MITM HAR:
mitm har --out <path>(required); or global--mitm-haron FINALIZE; orcapture-url --har - MITM redact:
mitm redactSHOWS the effective policy,mitm redact --secrets true|falsepersists a default, and the global--mitm-redact-secretsoverrides both; CA under XDG data - Workflow resume:
workflow resumeskips steps alreadyokin the journal - Scrape multi-format:
--format markdown,html,links(CSV or repeatable) returns per-format fields; 15 live formats aretext,markdown,html,rawHtml,links,metadata,screenshot,summary,product,branding,images,jsonld,json,feed,attributes(raw-htmlremains an accepted alias ofrawHtml) - Scrape browser formats:
--engine browserapplies--formatvia outerHTML - Batch/crawl browser engine:
batch-scrape --engine browserandcrawl --engine browser(GAP-010) - Scroll aliases: in
runscripts usedy/dxas aliases fordelta_y/delta_x - Schema discovery:
schema runorschema --cmd run; expanded fragments for goto/eval/type/scroll/assert/wait - Lang:
--lang pt-BRorconfig set lang pt-BRlocalizes human suggestions - Fail-fast partial steps: failed
runerror envelopes may include partialdata.steps - JSON steps stream:
--json-stepsemits one NDJSON object per step; final--jsonenvelope still includes fullsteps[] - Lighthouse path: flag,
config set lighthouse_path, or PATH; envelopebinary_sourceisrealormock(mock is e2e-only honesty, not production) - Search redirects:
searchcleansuddg=wrappers to destination URLs - Parse documents:
parsesupports PDF/DOCX/xlsx/ods and--redact-pii - Extract LLM: requires XDG
openrouter_api_key(optionalllm_base_url,llm_model) - Print PDF:
print-pdf --url <url> --path <file>one-shot CDP; also valid insiderun - Monitor baseline:
monitor check --url <url> --baseline <file> [--write-baseline] - Assert console:
assert console-empty/assert console-no-match --pattern …(needs--capture-console) - Assert aliases:
url_contains/text_contains;attruses DOM property fallback when HTML attribute is null - Pick / select-option: agent inventory names; native select dispatches input+change; HIG badge/popover /
role=optionviapick - Submit / storage:
submitfor form submit;storage export|importfor cookies + per-origin state - Inventory size:
commands --jsonlists 71 agent names (includesselect-option,pick,submit,storage,image+video+audio+record) - Locale:
locale --jsondiagnoses resolved language; set with--lang pt-BRorconfig set lang pt-BR file://+scrape --engine http: Usage error — use browser engine orparsefor local filesreload --ignore-cache: CDPPage.reloadwithignoreCache(not a JS no-op)runscript formats:--scriptis always a file path (inline JSON is rejected with exit 66); the file is NDJSON one object per line, or a single JSON array of steps; supportswait_timeout_msand scrapeformat/formats- Grab formats:
png|jpeg|webponly (AVIF removed in 0.1.6) - Redis cache: set
cache_backend redisandcache_redis_url; never userediss:// - Residual /tmp disk hygiene (0.1.5 RES-01…12 still true in 0.1.7):
- BORN auto-GC:
scavenge_stale_singleton_orphansremoves/tmporg.chromium.Chromium.*Singleton-only dirs older than 60s - FINALIZE dual scavenge + re-scan of owned marker dirs (
browser-automation-cli-chrome-prefix) - Never kills host Flatpak Chrome or non-CLI browser processes
- Doctor check
residual_disk+ top-level JSON fieldresidual(scanned_roots,cli_marker_dirs,chromium_tmp_singleton_orphans,scavenge_safe_candidates,live_cli_marker_processes(legacy),sibling_live_processes,orphan_marker_dirs,foreign_root_orphans,ghost_marker_processes,process_table_unavailable) - Local gates:
scripts/residual-check.sh,scripts/residual-stress.sh
- BORN auto-GC:
- Dialog settle:
dialog accept|dismiss→ read.data.dialog_settled; budget via XDGdialog_settle_ms; multi-tab isolation bysession_id(e2e gated) - Lighthouse: unit fixtures include chrome-captured LHR 13.4.1; e2e mock path remains SKIP (contract-only)
- Intentional residual: GAP-022 ~53 transitive multi-version dups; GAP-023/024 PRD divergences registered
- Sheet/lint utils:
sheet-write <input> --out <file>,sg-scan <paths>,sg-rewrite <paths>take positional inputs;find-paths --globfor shell globs find-pathspositional order is[PATTERN] [PATHS]..., so a lone positional is read as the regex PATTERN and the roots silently fall back to the current directory; pass an empty pattern to target a root:find-paths --glob '**/*.rs' '' src- Dialog soft path:
dialog accept --if-present/ runif_present:truesoft-ok when no dialog is showing
0success2usage or clap parse failure6blocked — the origin served a bot check instead of content64capability disabled — a category or experimental gate flag is missing65data error66no input69unavailable70software, browser, or protocol failure74I/O failure75precondition — the page or session does not satisfy the command78config error124timeout130cancelled by SIGINT141broken pipe255unexpected fatal path — plausible panic route, but not mapped by anyerror.kindand not observable through the discovery surface
- docs/HOW_TO_USE.md first command in 60 seconds
- docs/AGENTS.md agent integration contract
- docs/COOKBOOK.md practical recipes
- docs/CONFIGURATION.md every XDG key, its default and its purpose
- docs/CROSS_PLATFORM.md platform matrix
- docs/STEALTH_PARITY.md anti-detection parity against the reference implementations
- docs/MIGRATION.md version migration notes
- docs/TESTING.md test categories
- docs/schemas/README.md JSON schema index
- docs/ARCHITECTURE.md module layout and lifecycle internals
- docs/ROADMAP.md what is planned and what is closed by physical limit
- PRIVACY.md what stays local and what is never uploaded
- skills/browser-automation-cli-en/SKILL.md imperative agent skill
- CHANGELOG.md Keep a Changelog history
- SECURITY.md vulnerability reporting
- CONTRIBUTING.md contributor workflow
- CODE_OF_CONDUCT.md Contributor Covenant 2.1
- llms.txt short LLM discovery map
- Read CONTRIBUTING.md before opening a PR
- Follow the Code of Conduct in CODE_OF_CONDUCT.md
- Report vulnerabilities privately via SECURITY.md
- Maintainer contact: daniloaguiarbr@proton.me
- Version history lives only in CHANGELOG.md
- The Chrome DevTools Protocol team, whose published contract is what makes a one-shot CDP client possible without a daemon
chromiumoxide,hudsucker,clap,tokio,reqwestandfeed-rs, the crates this CLI is built on- The Rust project, for a toolchain where
clippy -D warningsandcargo denyare cheap enough to run on every gate - Reporters of security issues are credited in SECURITY.md after coordinated disclosure; none yet
- No external contributors to credit yet; CONTRIBUTING.md describes how that changes
- Dual licensed under MIT OR Apache-2.0
- See LICENSE, LICENSE-MIT, and LICENSE-APACHE