chrome-use — Real Chrome (Extension)
Drive the user's live, already-open, logged-in Chrome window through the extension-connect relay instead of a freshly launched browser.
Driving the user's real, already-open Chrome (extension)
When the task needs the user's live logged-in window (their real session, the window they're looking at — not a fresh browser), use the extension connect flow. One-time setup:
chrome-use extension install— registers the native-messaging host.- Install the chrome-use extension. Easiest (and restart-stable):
the Chrome Web Store, one-click Add to Chrome:
https://chromewebstore.google.com/detail/chrome-use/knfcmbamhjmaonkfnjhldjedeobeafmk
(Dev fallback:
chrome://extensions→ Developer mode → Load unpacked →extensions/ab-connect. Load-unpacked can be disabled on Chrome restart, so prefer the Store build for unattended setups.)
macOS: the "silent, all profiles" policy makes Chrome managed. Approving the configuration profile
extension installoffers puts Chrome in "managed by your organization" mode — which locks the "Use secure DNS" (DoH) setting (#187) and strips the extension's manual update/remove buttons (#186). Usechrome-use extension install --no-profileto never write it, orprofiles remove -identifier com.leeguoo.chrome-use.connectto undo it (Chrome then uninstalls the policy-installed extension — re-add it from the Store).
Site rules and profile selection
On macOS, open / goto / navigate can consult existing ChooseBrowser site rules when no explicit connection or browser is selected. The rule must resolve to a connected relay profile. --browser <id|email> takes precedence; --no-choosebrowser skips rule lookup. Reads are local and do not modify the rules.
To write one back, add --remember alongside an explicit --browser: after the navigation succeeds it asks ChooseBrowser to route that domain to that profile from now on. It is a request, not a save — ChooseBrowser shows its own dialog and reports no result back, so never tell the user a rule was saved. If --remember cannot produce a valid request it refuses before navigating and says why. It needs ChooseBrowser ≥ 0.2.1 (the version that registers the choosebrowser:// scheme; chrome-use doctor reports what is installed); on an older one nothing handles the url and chrome-use says so — no rule is proposed.
If the rule target is unavailable, normal profile selection applies. This fallback does not verify the website account. Check browsers and the site's identity, or pin --browser, when the task requires a specific account. click and snapshot do not consult routing rules to move an existing session.
Once installed, plain chrome-use open <url> auto-connects through the
extension relay — auto_connect_cdp prefers the live relay over a raw
--remote-debugging-port, so Chrome 136+'s "Allow remote debugging?" consent
popup never fires. chrome-use extension connect is the explicit form of the
same path. Zero-confirmation, zero-token. Use --launch instead when a fresh,
isolated browser is fine.
Many Chrome profiles? See which one — and pick it. The relay binds to whichever profile's extension worker is talking to the native host. If a site comes back logged out, confirm it's the right profile before assuming the login is gone:
chrome-use browsers— lists every connected profile (email if the ext has the optionalidentitypermission, else a stable id; marks the default).chrome-use --browser <id|email> <cmd>— pins THIS session to that profile. It's sticky per session (the session's daemon binds on first connect), and each session can pick a different profile, so concurrent agents don't fight.chrome-use extension status/doctoralso report the current driving profile.A logged-out result on the wrong profile is not a missing login — run
browsers, then re-run with--browser <the right one>.Many ACCOUNTS on one site? Verify identity, don't assume it. Profile selection picks the browser;
whoami/--aspick the account (backed by the cookie-use vault, hash-compare only — no stored cookie values are read):
chrome-use whoami [site]— which vault account each site's live session is.chrome-use --as <site/acct> <cmd>— verifies BEFORE acting; on mismatch auto-applies that account's stored session and re-verifies.--as-strictfails (exit 1) instead of switching. Re-verified on every invocation — sessions drift (logouts, other agents, account choosers).
--launch opens an isolated, empty test profile — no cookies, no login, no
extensions (so the extension-relay path is off). Its window is labelled
chrome-use (<session>) in Chrome's profile menu so a human watching the
desktop knows which session owns it. If a launched session needs more:
- Real cookies / login / extensions → drop
--launch, use--profile auto(reuses the user's real Chrome profile), or setAGENT_BROWSER_PROFILE=autoonce so every call does it by default. - A specific unpacked extension in the test profile →
--launch --args "--load-extension=<dir>".
If you DO hit the "Allow remote debugging?" dialog, don't keep retrying (every attempt re-pops it). One of two things is true:
- You're on a stale build. The relay-preference that avoids this dialog has
shipped for many releases — if you still hit it, your
chrome-useis old. Upgrade and retry:
Ifcurl -fsSL https://raw.githubusercontent.com/leeguooooo/chrome-use/main/install.sh | shwhich -a chrome-useshows more than one install, an old npm/pnpm copy (the npm registry lags behind — GitHub Releases are the source of truth) may be shadowing the upgraded one; remove the stale copy (npm rm -g chrome-use/pnpm rm -g chrome-use) so theinstall.shbuild wins. A tool that bundles its own pinned copy needs that copy upgraded too. - The extension/relay isn't live. Tell the user to install the Store extension (one click, above); after that the relay stays up and the dialog never returns.
If the relay drops mid-session (a command suddenly errors with "couldn't reach your Chrome" / "relay … failed" — usually the MV3 service worker got suspended, or two agents are sharing one relay): the CLI now self-heals — it waits for the worker's keepalive to revive the relay (~25s) and retries once, so most drops you never even see. If a command does surface the error:
- Just retry the command — the relay has usually reconnected by then.
- If it persists:
chrome-use status(check), thenchrome-use extension connect(re-attach), then retry. The CLI auto-registers the native host and opens the Web Store page itself if the extension was never set up — you don't runextension installby hand.statusis daemon-free and reports CLI, live/expected extension, driving profile, and current session state even when that session worker is stuck. - Never tell the user to quit/restart Chrome with
--remote-debugging-portto recover a dropped relay — that throws away their tabs and defeats the extension path. (The old error text said this; it no longer does.) chrome-use reconnectis a friendly alias forextension connect— re-binds the session to the running Chrome without any reinstall.
Don't serialize agents to dodge fragility. Relay drops are transient and self-heal; they are not a sign that the shared browser can't be driven concurrently. Concurrent multi-agent is supported — each
--sessiongets its own tab group and drives only its own tabs (see Strict multi-agent isolation below). Give each agent a distinct--sessionand let them run in parallel; you don't need to run them one at a time.
- Can't restore the browser at all? Don't stall waiting for a screenshot — fall back to non-visual verification:
get text/eval/ read the deployed page overcurl/WebFetch. Confirming a change via the DOM/HTML or the live URL is a correct result, not a failure. Reserve screenshots for a genuine visual check you report to the user.
OAuth/SSO popups and redirects now just work. A login handoff (GitHub/Google OAuth, SSO) navigates the tab across processes, which used to orphan the old session and make the next read fail "stale sessionId". The relay now auto-reattaches the opener across that cross-process nav and retries a read briefly while the new process settles, so reads (
snapshot/screenshot/eval/get) keep working through the handoff and "Sign in with Google" / OAuth-popup logins complete end-to-end. (The cross-origin Google GSI iframe — the "Continue as " button — is pierced only on Chrome 125+; on older Chrome that one button may stay unreachable.)
Each --session that connects gets its own colored Chrome tab group (named
after the session) and drives only its own tabs — multiple agents share the one
real browser without cross-talk, and the user's own tabs are never grouped. CDP
drives the page without moving the user's mouse/keyboard, so it doesn't fight
them for control.
Per-agent isolation is automatic. The session name is the isolation key: it maps to a dedicated tab group and a dedicated daemon (the port is derived from the name). With no
--session/AGENT_BROWSER_SESSION, the name is derived per agent — the derivation rules live in the core skill (chrome-use skills get core, "Per-agent isolation"), so there is one description of them rather than two that drift apart. What matters here: when each agent has a per-agent id in its environment (the usual case under an agent harness), two agents in the same repo get different tab groups and no longer stomp each other's active tab, and the name is stable across one agent's commands. That prerequisite is real: with neither a per-agent nor a per-terminal id — two plain shells, or two agents sharing one terminal tab — the derivation falls back to the shareddefaultsession and they do share a tab group. When separation has to be guaranteed rather than derived, pass--session <name>/AGENT_BROWSER_SESSIONexplicitly; setting them to the same value across agents makes them deliberately share one tab group.
Strict multi-agent isolation. A session over the relay drives only the tabs
it created or explicitly adopted. A pop-up that your own action
opened — e.g. the OAuth account-chooser window from a "Sign in with Google"
click — is followed and drivable as part of your session (switch to it and drive
the chooser). But it does not adopt the user's existing tabs, other agents'
tabs, or unrelated pop-ups (a login window the user opened on their own is
theirs), so several agents (and other tools opening tabs) can work in the same
real Chrome concurrently without ever dropping or stealing each other's tabs —
another agent's tab churn can't make your bound tab vanish or drift your commands
onto the wrong page. tab list may surface other tabs for recovery, but marks
them foreign; they cannot be selected or closed. Use adopt as the explicit
opt-in before driving one. Adopted tabs remain user-owned and cannot be closed by
the session. Created ownership persists across daemon restarts for the same named
session and connected browser endpoint, so interrupted cleanup can resume safely.
No debugger banner on the user's pages. The extension attaches Chrome's debugger only to tabs the agent owns (ones it created, or that you
adopt), never to the user's own tabs — so Chrome's "chrome-use started debugging this browser" bar never covers a page they're working in (it only appears on attached tabs, and the agent's are background tabs).adopt <url>attaches that one tab on demand (the bar then shows on that tab — it's the one you asked to drive). No Chrome restart, fully seamless. Since extension 0.5.19 the bar also goes away by itself: after 30 s without agent activity on a tab the extension releases the debugger from it, the tab stays known to the relay, and the next command re-attaches transparently (enabled domains are replayed). The delay is configurable on the extension options page ("Release idle tabs after", 0 = never). Clicking Cancel on the bar is honoured until the agent's next command. Trade-off: passive captures (network/console logging) miss events during a released interval.
Need to read a tab the user already has open? Use
chrome-use adopt <url-substring|targetId>— it finds that pre-existing tab (the user's own, or another session's) across groups and drives it without opening a new tab. e.g.adopt "claude.ai/design"thensnapshot/eval/get texton it. On no match it errors and lists the tabs it can see. This is the explicit, opt-in way through the isolation above (it tags the adopted tab into your group). Great for "read/extract from the page I'm looking at" without disturbing it.
Anti-detection ranking: this real logged-in Chrome (extension connect) > a headed launched browser > headless (forbidden). A genuine human browser has no headless/automation tells at all, so prefer it for anything anti-bot-sensitive.
Silent by default. When driving the user's real Chrome the agent works entirely in the background — new tabs open un-focused and the agent never force-fronts a tab. Focus is emulated, so the page keeps rendering and keeps running timers instead of being throttled. You don't need to do anything; just don't expect the user's view to follow you.
But a background tab really is hidden. document.visibilityState stays
'hidden' — focus emulation does not change it, and no CDP override does
either (issue #215). Almost nothing cares. The exception is a page that
deliberately gates its UI on visibility (a device lease that must not be kept
alive by a background tab, a video player, a game that pauses): it renders its
background branch, so snapshot can come back empty and the controls you
expect may be missing or unavailable. snapshot now says so when the tree is near-empty and the
tab is hidden. When you hit that, surface the tab on purpose with
chrome-use bringToFront and read it again — that is also the only thing that
makes the user's view follow you, so use it deliberately, not by habit.
Human-like input for behavioural anti-bot. Beyond fingerprint stealth,
--humanize off|fast|human (or AGENT_BROWSER_HUMANIZE) makes clicks follow a
curved, decelerating path with in-element landing jitter, typing use variable
cadence, and scroll/drag ease. Default off; a per-navigation detector
auto-escalates pages guarded by Akamai/PerimeterX/DataDome to human. Leave it
on auto; force human only when you already know the target scores behaviour.
Cloudflare clearance — solve once, reuse. Passing a Cloudflare challenge
mints a cf_clearance cookie (HttpOnly — invisible to eval/document.cookie;
read it via chrome-use cookies). It's bound to your IP + User-Agent: reuse
the same exit IP and UA and you skip the challenge until it expires. Driving the
user's real Chrome (relay) persists it natively; for isolated sessions,
--session-name <name> save/restores it. Before spending effort solving, run
chrome-use cf-status (aliases cf, clearance): it reports whether the page
is currently a Cloudflare challenge and whether a still-valid cf_clearance
exists, with a recommendation — proceed (already cleared, don't re-solve),
solve (challenge up, no clearance), or reissue (clearance present but page
still blocks → IP/UA drifted, re-solve). Use it as a preflight to avoid
re-solving what you already cleared.