* feat(browser): unify local Chrome setup across desktop and terminal Co-authored-by: fuller-stack-dev <263060202+fuller-stack-dev@users.noreply.github.com> * feat(browser): unify local Chrome setup across desktop and terminal OpenClaw-Publication: d19e865e-b5a0-4c70-8876-c1662f6e7ef2 Co-authored-by: fuller-stack-dev <263060202+fuller-stack-dev@users.noreply.github.com> * chore(linux): format Chrome setup fixture Co-authored-by: fuller-stack-dev <263060202+fuller-stack-dev@users.noreply.github.com> * feat(browser): keep desktop Chrome setup local and preserve pairing Delegate Windows registration to the shared native management owner, preserve released native bridge compatibility and saved launcher profiles, and integrate serialized desktop setup through isolated local runtimes. Co-authored-by: fuller-stack-dev <263060202+fuller-stack-dev@users.noreply.github.com> Co-authored-by: steipete <58493+steipete@users.noreply.github.com> * fix(browser): repair native setup CI contracts Keep Windows installer dependencies acyclic, validate Unicode within the package library target, and remove unused private exports. Require all eight packaged native-host proof cases and update lazy CLI inventory. Apply native Swift formatter diagnostics without changing behavior. Co-authored-by: fuller-stack-dev <263060202+fuller-stack-dev@users.noreply.github.com> Co-authored-by: steipete <58493+steipete@users.noreply.github.com> * test(cli): account for plugin-owned browser extension catalog Keep the core-only registration invariant aligned with the Browser plugin owner already exercised by its lazy registration tests. Co-authored-by: fuller-stack-dev <263060202+fuller-stack-dev@users.noreply.github.com> Co-authored-by: steipete <58493+steipete@users.noreply.github.com> * test(macos): retain released Chrome bridge request expectation Align the native bridge test with the shipped contract1 request retained by the canonical setup owner, and reject extra legacy payload fields. Co-authored-by: fuller-stack-dev <263060202+fuller-stack-dev@users.noreply.github.com> Co-authored-by: steipete <58493+steipete@users.noreply.github.com> * test(tui): give command handler harness a unique export Rename the shared TUI test helper and both consumers to avoid the Gateway placement harness export collision. No alias or guard waiver. Co-authored-by: fuller-stack-dev <263060202+fuller-stack-dev@users.noreply.github.com> Co-authored-by: steipete <58493+steipete@users.noreply.github.com> * chore(sdk): allow canonical browser config path resolver Apply the approved single public-export and callable allowance for resolveConfigPath. Preserve canonical pre-config path ownership and all other SDK surface checks. Co-authored-by: fuller-stack-dev <263060202+fuller-stack-dev@users.noreply.github.com> Co-authored-by: steipete <58493+steipete@users.noreply.github.com> * fix(browser): preserve desktop setup selection and supported actions Keep native automatic setup selector-free and resolve saved local browser selection through the canonical setup owner before installation. Respect Mac action advertisements and the released legacy install projection in the Apps card, and document the public config-path resolver contract. Co-authored-by: fuller-stack-dev <263060202+fuller-stack-dev@users.noreply.github.com> Co-authored-by: steipete <58493+steipete@users.noreply.github.com> * fix(auth): retry model selection after concurrent credential refresh Adopt upstream PR #152426, commit32298b10f6, without changing its five source files. Co-authored-by: fuller-stack-dev <263060202+fuller-stack-dev@users.noreply.github.com> Co-authored-by: steipete <58493+steipete@users.noreply.github.com> * test: preserve native setup selection and await dashboard document Match the selector-free native CLI arguments exactly and preserve a saved work-profile result. Wait through the existing document-readiness owner only at the quota test browser-proof boundary, after auth assertions. Co-authored-by: fuller-stack-dev <263060202+fuller-stack-dev@users.noreply.github.com> Co-authored-by: steipete <58493+steipete@users.noreply.github.com> * fix(ui): avoid preloading already imported modules Remove exact direct static JavaScript imports from lazy preload tables using the emitted build graph. Preserve HTML, lazy-only JavaScript, CSS, and locale hints. Source-exact CI merge reproduction drops startup gzip from 363283 to 362968 bytes without changing budgets. Add a real emitted-bundle regression. Apply rustfmt layout to the native Chrome selector-free expected arguments. Co-authored-by: fuller-stack-dev <263060202+fuller-stack-dev@users.noreply.github.com> Co-authored-by: steipete <58493+steipete@users.noreply.github.com> * fix: preserve Chrome profiles and attachment follow-up branch binding Let the TUI canonical setup controller retain its saved browser profile and project only a bounded returned name. Align both native first-run fixture expectations with selector-free setup. Join pending chat history before the composer task handoff can expose an admitted attachment to restored-outbox delivery. Preserve idempotency, attachment custody, restored delivery semantics, and all existing assertions and timeouts. Add a deterministic regression reproduced on the exact failed CI merge and its main parent. Co-authored-by: fuller-stack-dev <263060202+fuller-stack-dev@users.noreply.github.com> Co-authored-by: steipete <58493+steipete@users.noreply.github.com> * test(state): adopt canonical worker-custody fixture repair Adopt src/plugin-state/plugin-state-worker.test.ts byte-for-byte from upstreambfec65a2a0(#152456). The former fixture held its late competing owner until after awaiting off-thread acquisition. Preserve that overlap, assert continued host authority checks and noncompletion, release custody, then assert the original result and persisted state. No production locking, guard, deadline or outcome assertion is relaxed. Both prior failures reproduced on the exact CI main parent with independently installed frozen dependencies and Node 24.19.0. All 12 repaired file tests, selected state-logging types, scoped typed lint and fresh P0-P2 review passed. Co-authored-by: fuller-stack-dev <263060202+fuller-stack-dev@users.noreply.github.com> Co-authored-by: steipete <58493+steipete@users.noreply.github.com> * fix(browser): retain saved Windows setup profiles Recover configured extension profiles through bounded serial read-only C# inspection. Select only independently validated current matching descriptors, confirm the selected generation before effects, and leave the single mutation under the existing C# owner. Preserve POSIX behavior, existing manual relay verification and explicit same-profile repair. Missing descriptors, runtime/origin drift and unknown or changing observations fail closed without automatic mutation. Keep raw management facts private and populate the existing browserProfile field only from validated binding metadata. No ABI, schema, SDK, configuration flag or registry/activation owner change. 29 actual CLI/controller/Windows-adapter boundary cases plus sibling coverage: 94 tests pass. Canonical changed checks, full production build and fresh independent P0-P2 review passed. Actual C# native proof remains separately coordinated. Co-authored-by: fuller-stack-dev <263060202+fuller-stack-dev@users.noreply.github.com> Co-authored-by: steipete <58493+steipete@users.noreply.github.com> * fix(browser): preserve saved profiles after POSIX bundle relocation Separate validated native registration ownership from supported origin-migration readiness. Recover the profile only after full private manifest and exact launcher validation; preserve the existing one-slot migration rule and all unsupported-origin, ACL and foreign-host refusals. Fail closed before selector-free installation when the saved selection cannot be proved. Extract the unchanged shared origin helpers into a cohesive sibling to satisfy the existing line-cap guard without waivers. Windows admission, ABI and selector behavior remain unchanged. Actual Linux/Darwin CLI-to-filesystem relocation regressions: 18 failures on original production, all 22 cases repaired. Preserve the private relay key and inode, config, Chrome preferences, work relay19444 and explicit-profile intent. 137 focused tests, eight real POSIX native-host E2E cases, canonical changed checks, full production build and fresh P0-P2 review passed. Co-authored-by: fuller-stack-dev <263060202+fuller-stack-dev@users.noreply.github.com> Co-authored-by: steipete <58493+steipete@users.noreply.github.com> * fix(ui): retain input handoff through the shared outbox owner Remove the superseded pending-history no-yield workaround after main introduced foreground submission custody in the shared outbox owner. Restore chat-submit-guard.ts exactly to pinned main cc7 rather than retaining competing timing policies. Keep passive drains fenced while the input task yields. Preserve the retained history regression with explicit MessageChannel admission, no passive send before resume, and the same terminal leaf, idempotency key, attachment bytes and exactly-once assertions after completion. Original composed source fails all five focused cases; the repair passes 67 handoff/attachment cases and 20 real Chromium cases in the canonical secretless network-none runner. Canonical checks, UI build/performance and fresh P0-P2 review pass. No assertion, timeout, origin or proxy-policy weakening. Browser POSIX/Windows repairs remain byte-identical to accepted255f. The failed e40e CI receipts remain preserved; fresh exact-head CI and parent handoff are still required. Co-authored-by: fuller-stack-dev <263060202+fuller-stack-dev@users.noreply.github.com> Co-authored-by: steipete <58493+steipete@users.noreply.github.com> * fix(tasks): preserve reads across native event finalization Hand joined event publication to its exact native successor after the native flow and observer publication frame completes. Keep worker settlement and cleanup, reversible claim transfer, current-authority and ABA checks, and post-commit delivery in their existing owners without replaying writes. Cover pre-result and readback finalization, native and reentrant successor chains, rollback, failed publication, delivery, and terminal activity cleanup. Co-authored-by: fuller-stack-dev <263060202+fuller-stack-dev@users.noreply.github.com> Co-authored-by: steipete <58493+steipete@users.noreply.github.com> * test(ui): retain rail baseline geometry on readiness failure Keep the exact existing readiness predicate, fixtures, case inventory, assertion and timeout. When the predicate is false, retain synthetic marker identity and numeric geometry so hosted CI can distinguish scroll, visibility and viewport failures. This is diagnostic evidence, not a repair or waiver of the unresolved rail failure. Local rootless browser infrastructure is unavailable; the existing hosted CI lane will verify the reviewed task-publication repair and collect meaningful rail evidence. Canonical changed checks and P0-P2 diagnostic review pass. Co-authored-by: fuller-stack-dev <263060202+fuller-stack-dev@users.noreply.github.com> Co-authored-by: steipete <58493+steipete@users.noreply.github.com> * docs(linux): describe saved-profile Chrome setup selection Match the selector-free adapter argument vector and its regression test. Address the fresh P3 review finding without changing runtime behavior. Markdown syntax and diff checks pass; the generic formatter excludes this subtree. Co-authored-by: fuller-stack-dev <263060202+fuller-stack-dev@users.noreply.github.com> Co-authored-by: steipete <58493+steipete@users.noreply.github.com> * test(transcripts): join configured startup before cleanup faults Observe and await the real startTranscripts promise through a narrow call-through spy while retaining the configured service entry point and real SQLite/provider work. Bind the await to the existing test lifetime instead of charging startup to the subsequent short active-map poll. Gate provider return after persisted utterance to prove readiness does not settle early; retain both missing/unreadable row injections and all cleanup, private-source, lifecycle-token and summary assertions. Cover real startup rejection explicitly. No production change, timeout increase, retries or broad module/storage mocks. The deterministic ordering boundary fails with the old fire-and-forget readiness and passes with the real promise join. Final 39 tests across 3 files, canonical changed checks and full-owner P0-P2 review pass. This does not recover whether the historical CI startup was late or rejected. Co-authored-by: fuller-stack-dev <263060202+fuller-stack-dev@users.noreply.github.com> Co-authored-by: steipete <58493+steipete@users.noreply.github.com> * fix(browser): preserve automatic desktop status inspection Restore read-only Device-page inspection for current and released Mac bridges while keeping installation and verification explicit. Preserve the native filesystem prerequisite proof, split installer repair tests within the existing line cap, and remove the superseded constant export. * fix(browser): preserve registered setup configuration Require canonical setup to match an owned launcher's effective state and config selection before installation or relay access. Preserve equivalent implicit/explicit default selections and the saved launch context. Recheck automatic profile selection before effects and the current manifest before publication through the existing registration owner. Keep manual install and relocation repair contracts unchanged. Cover mismatched configs, legacy selectors, equivalent defaults, selection drift, and actual bootstrap after refused setup. Restore the missing Command import in the existing Unix-only companion CLI test. Focused tests, types, lint, fresh review, clean package build and sealed Mac ARM64 runtime proof pass. The separate historical clock-jump CI failure has bounded replay evidence and remains documented without a speculative fix. Co-authored-by: fuller-stack-dev <263060202+fuller-stack-dev@users.noreply.github.com> * fix(browser): keep setup registration types acyclic Move the private registration status contract beside its context policy and point both consumers at that owner. Remove the publication-module back-edge without keeping an unused compatibility export. The full architecture gate, extension production/test types, typed lint and fresh independent review pass. Node's transformed JavaScript is byte-identical for all three affected modules, so the existing runtime proof remains valid. Co-authored-by: fuller-stack-dev <263060202+fuller-stack-dev@users.noreply.github.com> * test(linux): handle Chrome setup in desktop sharing fixture Recognize the exact automatic Chrome setup invocation and require its native no-respawn flag. Keep unknown-command rejection, selected-auth validation, process-group ownership and joined teardown assertions unchanged. The original fixture reproduces the CI rejection against the real Linux app. The repaired fixture passes all nine checks against that same binary, with five Chrome setup calls and five node starts and joined stops. Fresh review is clean; production app behavior is unchanged. Co-authored-by: fuller-stack-dev <263060202+fuller-stack-dev@users.noreply.github.com> --------- Co-authored-by: fuller-stack-dev <263060202+fuller-stack-dev@users.noreply.github.com> Co-authored-by: steipete <58493+steipete@users.noreply.github.com> Co-authored-by: Peter Steinberger <steipete@gmail.com>
27 KiB
summary, read_when, title
| summary | read_when | title | |||
|---|---|---|---|---|---|
| CLI reference for `openclaw browser` (lifecycle, profiles, tabs, actions, state, and debugging) |
|
Browser |
openclaw browser
Manage OpenClaw's browser control surface and run browser actions: lifecycle, profiles, tabs, snapshots, screenshots, navigation, input, state emulation, and debugging.
Related: Browser tool
Common flags
--url <gatewayWsUrl>: Gateway WebSocket URL (defaults to config).--token <token>: Gateway token (if required).--timeout <ms>: request timeout in ms (default:30000).--expect-final: wait for a final Gateway response.--browser-profile <name>: choose a browser profile (default:openclaw, orbrowser.defaultProfile).--json: machine-readable output (where supported). This is a browser-level option, so place it before the subcommand for an unambiguous form, such asopenclaw browser --json status. Trailing placement such asopenclaw browser status --jsonalso works when the selected child command does not define its own--json.
The CLI reserves 10 additional seconds beyond the request timeout for node and Gateway transport, allowing browser timeout diagnostics to reach the caller.
Quick start (local)
openclaw browser profiles
openclaw browser --browser-profile openclaw start
openclaw browser --browser-profile openclaw open https://example.com
openclaw browser --browser-profile openclaw snapshot
Agents can run the same readiness check with browser({ action: "doctor" }).
Quick troubleshooting
If start fails with not reachable after start, troubleshoot CDP readiness first. If start and tabs succeed but open or navigate fails, the browser control plane is healthy and the failure is usually a navigation SSRF policy block.
Minimal sequence:
openclaw browser --browser-profile openclaw doctor
openclaw browser --browser-profile openclaw start
openclaw browser --browser-profile openclaw tabs
openclaw browser --browser-profile openclaw open https://example.com
Detailed guidance: Browser troubleshooting
Lifecycle
openclaw browser status
openclaw browser doctor
openclaw browser doctor --deep
openclaw browser start
openclaw browser start --headless
openclaw browser stop
openclaw browser --browser-profile openclaw reset-profile
doctor --deepadds a live snapshot probe: useful when basic CDP readiness is green but you want proof the current tab can be inspected.- For a running local managed profile,
statusanddoctorreport cached graphics diagnostics from Chrome: hardware/software classification, renderer, backend, device/driver, feature and disabled-status details, and accelerated video capabilities.openclaw browser --json statusreturns the full structured payload. Passive status never launches Chrome just to collect these facts. stopcloses the active control session and clears temporary emulation overrides. This applies even toattachOnlyand remote CDP profiles, where OpenClaw did not launch the browser process itself. For local managed profiles,stopalso stops the spawned browser process.start --headlessapplies only to that start request, and only when OpenClaw launches a local managed browser. It does not rewritebrowser.headlessor profile config, and is a no-op for an already-running browser.- On Linux hosts without
DISPLAYorWAYLAND_DISPLAY, local managed profiles run headless automatically unlessOPENCLAW_BROWSER_HEADLESS=0,browser.headless=false, orbrowser.profiles.<name>.headless=falseexplicitly requests a visible browser.
If the command is missing
If openclaw browser is an unknown command, check plugins.allow in ~/.openclaw/openclaw.json. When plugins.allow is present, list the bundled browser plugin explicitly unless the config already has a root browser block:
{
plugins: {
allow: ["telegram", "browser"],
},
}
An explicit root browser block (for example browser.enabled=true or browser.profiles.<name>) also activates the bundled browser plugin under a restrictive plugin allowlist.
Related: Browser tool
Profiles
Profiles are named browser routing configs:
openclaw(default): launches or attaches to a dedicated OpenClaw-managed Chrome instance (isolated user data dir).user: controls your existing signed-in Chrome session via Chrome DevTools MCP.- custom CDP profiles: point at a local or remote CDP endpoint.
openclaw browser profiles
openclaw browser system-profiles
openclaw browser system-profiles --browser brave
openclaw browser import-profile --browser chrome --system Default --into imported
openclaw browser import-profile --system "Profile 1" --into work --domains google.com,youtube.com
openclaw browser create-profile --name work --color "#FF5A36"
openclaw browser create-profile --name chrome-live --driver existing-session
openclaw browser create-profile --name remote --cdp-url https://browser-host.example.com
openclaw browser delete-profile --name work
Use a specific profile with --browser-profile <name> on any subcommand, for example openclaw browser --browser-profile work tabs.
On macOS, system-profiles lists real Chrome, Brave, Edge, or Chromium profiles available on the host. import-profile decrypts their cookies after one macOS Keychain/Touch ID consent prompt and injects them into a fresh OpenClaw-managed profile. It imports cookies only. Local storage and IndexedDB are unchanged. Some Google sessions use device-bound session credentials (DBSC) and can still require re-authentication after import.
When the macOS app uses a local Gateway, it can offer this import once and make the isolated imported profile the default for agent browsing. Import always requires an explicit click. Successful import or dismissal suppresses later automatic prompts, and Settings → General → Browser login remains available for re-import.
System-profile import is enabled by default. Set browser.allowSystemProfileImport=false to disable both CLI and agent-triggered imports. Import is host-local and cannot run through the browser node proxy.
Cookie sync to a remote Gateway
import-profile targets a managed profile on the same host. When your OpenClaw Gateway and agent browser run on a separate computer, use cookie-sync instead. It decrypts cookies on this Mac and pushes them into a managed profile on that remote Gateway over the operator connection:
openclaw browser cookie-sync --domains github.com,news.ycombinator.com --into work
openclaw browser --url wss://gateway.example.com cookie-sync --domains github.com --into work --watch
--domainsis required. Cookie sync copies live session cookies, so it never sends an unrestricted cookie jar. A missing or empty allowlist is a hard error.--intoselects the target managed profile on the Gateway (defaultimported).--gateway/--urlselects a remote Gateway (default is the configured or local one).--watchkeeps the command running and re-pushes when the source Cookies database changes. The macOS Keychain secret is read once per watch session, so you approve a single consent prompt rather than one per change.- Decryption is host-local (macOS only) and reuses the same allowlist and Keychain path as
import-profile. Cookies are decrypted on this Mac and shipped over the existing TLS-pinned Gateway connection. No cookie values are printed. - Some Google sessions use device-bound session credentials (DBSC) that stay tied to this Mac and can still require re-authentication after sync. For those sites, prefer driving the browser on the Mac itself through the browser node proxy.
The macOS app exposes the same capability under Dashboard → Settings → This Mac → Browser: an off-by-default toggle, an editable domain allowlist, and a target-profile field. When enabled in remote mode it supervises cookie-sync --watch for you against the connected Gateway and shows a live status row.
Chrome extension relay
openclaw browser extension path
openclaw browser extension setup --action inspect --json
openclaw browser extension setup --action install --json
openclaw browser extension setup --action verify --browser-profile chrome --json
openclaw browser extension install
openclaw browser extension install --no-store
openclaw browser extension install --json --wait-ms 60000
openclaw browser extension status
openclaw browser extension status --json
openclaw browser extension uninstall-host
openclaw browser extension uninstall-store
openclaw browser extension pair
openclaw browser extension pair --gateway-url wss://gateway.example.com
openclaw browser extension cdp
openclaw browser extension cdp --json
extension setupis the shared host-local controller for CLI, TUI, and native desktop adapters.inspectis read-only installation discovery,installprepares native bootstrap, andverifyauthenticates the selected local relay. Its redacted JSON separates preparation, Chrome approval, and connection. Valid pending/blocked states exit 0; execution failures exit nonzero. It never treats a remote dashboard or SSH loopback URL as proof of a local browser host.extension installpre-registers the origin-locked native bootstrap host. Google Chrome on macOS can be prepared before its first launch; other supported browsers need an existing user-data directory. On macOS, setup then requests the official Store installation in Google Chrome for all profiles in that directory. Chrome discovers this at startup. Fully quit and reopen Chrome when convenient, then approve or enable OpenClaw. The command never restarts Chrome or bypasses approval. For other browsers and platforms, add OpenClaw from the Chrome Web Store. Linux supports automatic native pairing. Windows uses the self-containedOpenClaw.BrowserBootstrap.exefrom the packaged CLI or Windows companion. A portable/local installer can pass--native-host-executable <absolute-path>toextension setup --action installorextension install. Setup checks owned context/ACLs and actual framed subprocess responses before user-level registry registration through the shared C# registration service. The CLI explicitly selects native Windows context; the Companion owns its managed-WSL mode. Conflicting contexts and unknown transport outcomes never trigger another writer or mode fallback. No executable or no proof means no automatic bootstrap; it never falls back to a script host or bypasses Chrome approval.extension install --no-storecopies the stable development extension and registers the native host without creating a Store request. Existing requests are unchanged. Use the printed path for Load unpacked.extension statusreportsstoreInstallRequestsstates (requested,missing,foreign,invalid) separately fromstoreDiscoveredapproval fields (enabled,awaitingApproval), approved unpacked IDs and paths, and native-host registration health. Local installation status does not prove a live relay connection. JSON output never includes a pairing string or relay key.extension uninstall-hostremoves only verified OpenClaw-owned native-host manifests and launchers. It does not remove the extension from Chrome. On Windows it delegates to the same registration service;--remove-storeremoves verified owned Store requests first.--native-host-executableand--browser-profileselect the same explicit local context for status/removal.extension uninstall-storeremoves only OpenClaw-owned macOS Chrome Store requests (macOS only). Windows usesuninstall-host --remove-storerather than a separate Store writer. Chrome may remove an externally installed extension at its next startup. Native-host registration and the development copy remain intact.extension pathis read-only. It prints the stable installed copy when present and the bundled source directory otherwise.extension pairremains the advanced manual flow.--gateway-urlcreates a direct remote-Gateway pairing URL. Non-loopback URLs must usewss://.extension pair --local-gateway --jsonlets desktop native helpers obtain the canonical local pairing through the Gateway’s/browser/extensionwake-up route. It requires a local Gateway configuration and cannot be combined with--gateway-url. The JSON contains a credential: consume it privately, never log it.extension cdpprints non-secret Browser Relay Authentication v2 metadata: the loopback browser/CDP endpoints, protocol version, key ID, and fixed challenge/complete binding. It never prints the relay key or an authorization header by default.
Automatic local bootstrap connects through the local Gateway's exact
/browser/extension route so the first authenticated extension connection
starts the lazy browser-control service. Keep openclaw gateway run or the
managed Gateway service running. No separate browser request or prewarm is
needed. Local OpenClaw and mcporter calls still use the profile relay port
reported by extension pair or extension cdp after that wakeup. Browser-node
pairings continue to use the relay on the browser-node host, while explicit
--gateway-url pairings remain direct-remote and manual-only.
The advanced manual extension pair command without --gateway-url or
--local-gateway retains
the host-local /extension relay URL. With the native host installed,
Automatic local setup enabled, and an extension build that supports relay
wake-up, reconnecting can start a standalone relay on the saved pairing's
configured port. This does not start Gateway browser control: authenticated CDP
clients can use the standalone relay without a Gateway, but openclaw browser
actions still require one. For source-checkout testing, load the managed unpacked
copy from the same OpenClaw installation.
extension cdp --legacy-bearer is a temporary migration escape hatch. It
prints the old Bearer header with a warning only while
browser.extensionRelay.allowLegacyAuth=true. Otherwise it exits with an error
without printing a credential. Use --json for machine output. Warnings remain
on stderr so stdout stays valid JSON.
Setup, security model, and recovery steps: Chrome extension.
Run installation on the machine hosting Chrome. In the macOS app, Dashboard → Settings → This Mac → Browser → Set up Chrome on this Mac invokes the local CLI even when connected to a remote Gateway. The browser-based dashboard offers Store and documentation links instead.
If the extension already attempted automatic setup before the native host
existed, Chromium retains that miss for the running browser process. Restart
Chrome once, run extension install, then reopen the Store extension. Popup
retries alone cannot recover that existing process.
Tabs
openclaw browser tabs
openclaw browser tab new --label docs
openclaw browser tab label t1 docs
openclaw browser tab select 2
openclaw browser tab close 2
openclaw browser open https://docs.openclaw.ai --label docs
openclaw browser focus docs
openclaw browser close t1
tabs returns suggestedTargetId first, then the stable tabId (such as t1), the optional label, and the raw targetId. Pass suggestedTargetId back into focus, close, snapshots, and actions. Assign a label with open --label, tab new --label, or tab label. Labels, tab ids, raw target ids, and unique target-id prefixes are all accepted. The request field is still named targetId for compatibility, but it accepts any of these tab references.
Profiles configured with driver: "extension" can additionally return a numeric
webExtensionTabId. It is scoped to the current browser runtime and is intended
only for calls into Chrome's WebExtensions API. It can change after the browser
or extension reconnects and is omitted for other drivers or when extension
metadata is unavailable. Do not pass it to OpenClaw browser commands; keep using
suggestedTargetId or tabId there.
Raw target ids are volatile diagnostic handles, not durable agent memory. Chromium can replace the underlying raw target during a navigation or form submit. OpenClaw then keeps the stable tabId or label attached to the replacement tab, when it can prove the match. Prefer suggestedTargetId.
Snapshot / screenshot / actions
Snapshot:
openclaw browser snapshot
openclaw browser snapshot --urls
Screenshot:
openclaw browser screenshot
openclaw browser screenshot --full-page
openclaw browser screenshot --ref e12
openclaw browser screenshot --labels
--full-pageis for page captures only. It cannot be combined with--refor--element.existing-session/userprofiles support page screenshots and--refscreenshots from snapshot output, but not CSS--elementscreenshots.--labelsoverlays current snapshot refs on the screenshot. On Playwright-backed profiles it works with--full-page(full-page overlay),--ref(element-clip overlay by ARIA ref), and--element(element-clip overlay by CSS selector). In element-clip modes labels are projected relative to the element. The response also includes anannotationsarray, omitted when empty. Each entry carries one ref's bounding box:ref,number,role, optionalname, andbox: {x, y, width, height}. Coordinates use the captured image's space (viewport, fullpage, or element-relative).existing-sessionprofiles render a chrome-mcp overlay on page screenshots but do not use the Playwright projection helper and do not includeannotations. CSS--elementscreenshots are unsupported there. Without Playwright or chrome-mcp, labeled screenshots are not available.snapshot --urlsappends discovered link destinations to AI snapshots so agents can choose direct navigation targets instead of guessing from link text alone.
Navigate/click/type (ref-based UI automation):
openclaw browser navigate https://example.com
openclaw browser click <ref>
openclaw browser click-coords 120 340
openclaw browser type <ref> "hello"
openclaw browser press Enter
openclaw browser hover <ref>
openclaw browser scrollintoview <ref>
openclaw browser drag <startRef> <endRef>
openclaw browser select <ref> OptionA OptionB
openclaw browser fill --fields '[{"ref":"1","value":"Ada"}]'
openclaw browser wait --text "Done"
openclaw browser evaluate --fn '(el) => el.textContent' --ref <ref>
openclaw browser evaluate --fn 'const title = document.title; return title;'
openclaw browser evaluate --timeout-ms 30000 --fn 'async () => { await window.ready; return true; }'
press accepts named keys and shortcuts such as Escape, Control+Shift+T, and Control++. Common Esc, Return, Del, Ctrl, and Cmd aliases are normalized.
For managed browser profiles, select preserves option values exactly. Quote empty or whitespace-sensitive values, such as openclaw browser select <ref> "" or openclaw browser select <ref> " padded ".
evaluate --fn accepts a function source, an expression, or a statement body. Statement bodies are wrapped as async functions, so use return for the value you want back. Use --timeout-ms when the page-side function may need longer than the default evaluate timeout. browser.evaluateEnabled=false (default: true) disables both evaluate and wait --fn.
Action responses return the current raw targetId after action-triggered page replacement when OpenClaw can prove the replacement tab. Scripts should still store and pass suggestedTargetId/labels for long-lived workflows.
File + dialog helpers:
openclaw browser upload /tmp/openclaw/uploads/file.pdf --ref <ref>
openclaw browser upload media://inbound/file.pdf --ref <ref>
openclaw browser waitfordownload
openclaw browser download <ref> report.pdf
openclaw browser dialog --accept
openclaw browser dialog --dismiss --dialog-id d1
Managed Chrome profiles save ordinary click-triggered downloads into the OpenClaw downloads directory (/tmp/openclaw/downloads by default, or the configured temp root). Use waitfordownload or download when the agent needs to wait for a specific file and return its path. Those explicit waiters own the next download. Uploads accept files from the OpenClaw temp uploads root and OpenClaw-managed inbound media, including media://inbound/<id> and sandbox-relative media/inbound/<id> references. Nested media refs, traversal, and arbitrary local paths are rejected.
For remote browser nodes, OpenClaw stages private copies and normalizes filenames for portability, including Windows device names and trailing dots or spaces. File bytes remain unchanged.
If saving a download fails, OpenClaw requests cancellation of the transfer and reports the original save error. Correct the output path or filesystem problem before starting a new download.
When an action opens a modal dialog, text output reports the block and pending dialog IDs. The JSON response returns blockedByDialog with browserState.dialogs.pending. Pass --dialog-id to answer it directly. Dialogs handled outside OpenClaw appear under browserState.dialogs.recent.
Batch actions:
openclaw browser batch --actions '[{"kind":"wait","timeMs":500},{"kind":"click","ref":"12"},{"kind":"type","ref":"23","text":"hello"}]'
openclaw browser batch --actions-file plan.json
openclaw browser batch --actions-file - --continue
openclaw browser batch sends a kind="batch" /act request with nested BrowserActRequest actions (wait, click, type, evaluate, ...) — not open/navigate/snapshot/screenshot, which are CLI subcommands, not /act kinds. --continue sets stopOnError=false (default stops on first error). --target-id scopes the whole batch to one tab. A failed nested action makes the command exit nonzero. Use --json to retain the ordered results response. See Browser batch CLI for the full contract (ref lifecycle, target id conflicts, error summary). batch is not supported on profile="user" / existing-session profiles.
If navigation or a closed page stops the batch, text output reports the action number and skipped count. Take a fresh snapshot before continuing with dependent actions.
--actions-file and --actions-file - stdin input are capped at 1,000,000 bytes. Split larger plans into multiple openclaw browser batch commands.
State and storage
Viewport + emulation:
openclaw browser resize 1280 720
openclaw browser set viewport 1280 720
openclaw browser set offline on
openclaw browser set media dark
openclaw browser set timezone Europe/London
openclaw browser set locale en-GB
openclaw browser set geo 51.5074 -0.1278 --accuracy 25
openclaw browser set device "iPhone 14"
openclaw browser set headers '{"x-test":"1"}'
openclaw browser set credentials myuser mypass
Cookies + storage:
openclaw browser cookies
openclaw browser cookies set session abc123 --url https://example.com
openclaw browser cookies clear
openclaw browser storage local get
openclaw browser storage local set token abc123
openclaw browser storage session clear
Storage keys preserve surrounding whitespace. Quote the key in shell commands,
for example openclaw browser storage local get " account ". Setting that key
does not overwrite the separate account entry. Empty or whitespace-only keys
remain invalid for set; omitting the key in get lists all entries.
Debugging
openclaw browser console --level error
openclaw browser pdf
openclaw browser responsebody "**/api"
openclaw browser highlight <ref>
openclaw browser errors --clear
openclaw browser requests --filter api
openclaw browser trace start
openclaw browser trace stop --out trace.zip
responsebody writes the bounded response prefix to stdout and warns on stderr
when it is truncated. --json includes the response metadata and truncated
flag without a separate warning. Use --max-chars to select the prefix limit.
Existing Chrome via MCP
Use the built-in user profile, or create your own existing-session profile:
openclaw browser --browser-profile user tabs
openclaw browser create-profile --name chrome-live --driver existing-session
openclaw browser create-profile --name brave-live --driver existing-session --user-data-dir "~/Library/Application Support/BraveSoftware/Brave-Browser"
openclaw browser create-profile --name chrome-port --driver existing-session --cdp-url http://127.0.0.1:9222
openclaw browser --browser-profile chrome-live tabs
The default existing-session path is host-only Chrome MCP auto-connect. If the browser is already running with a DevTools endpoint, pass --cdp-url so Chrome MCP attaches to that endpoint instead. For Docker, Browserless, or other remote setups where Chrome MCP semantics are not needed, use a CDP profile instead.
Current existing-session limits:
- Snapshot-driven actions use refs, not CSS selectors.
- Supported
actrequests use a built-in 60000 ms default when callers omittimeoutMs. Accepted per-call overrides set that action budget. clickis left-click only.typedoes not supportslowly=true.pressdoes not supportdelayMs.hover,scrollintoview,drag,select, andfillreject per-call timeout overrides.evaluateaccepts--timeout-ms.selectsupports one value only.wait --load networkidleis not supported (works on managed and raw/remote CDP profiles).- File uploads require
--ref/--input-refand do not support CSS--element. Pass multiple paths when the page's file input accepts multiple files. - Dialog hooks do not support
--timeout. - Screenshots support page captures and
--ref, but not CSS--element. responsebody, download interception, PDF export, and batch actions still require a managed browser or raw CDP profile.
Existing-session action steps share one execution budget: filling and submitting with type do not each receive a fresh timeout. A conditional wait allows its explicit timeMs delay plus the action budget (with a 250 ms minimum) to satisfy the condition. A pure timer wait reserves the larger of timeMs and the action budget.
Navigation verification has a separate shared allowance of the action budget plus 1250 ms for scheduled delays. resize and close skip verification. Browser and tab preparation, execution, and final URL lookup share the overall request deadline. Internal calls and navigation probes do not renew it.
Remote browser control (node host proxy)
If the Gateway runs on a different machine than the browser, run a node host on the machine that has Chrome/Brave/Edge/Chromium. The Gateway proxies browser actions to that node. No separate browser control server is required.
Automatic routing prefers the Gateway host's browser and uses a single connected browser node only when local browser capability is unavailable. Use gateway.nodes.browser.mode to control this fallback and gateway.nodes.browser.node to explicitly select a node, including when the host has a browser. A stopped local managed browser with an installed executable still stays local.
Security + remote setup: Browser tool, Remote access, Tailscale, Security