English · 简体中文
⭐ If it saves you a re-login, a star helps other devs find it.
Point it at a page in your real Chrome → get structured data in one command. (regenerate: vhs assets/demo.tape)
chrome-use drives your real, logged-in Chrome from any AI agent — it shares your existing login sessions and is undetectable by anti-bot systems because it is your real browser. Part of the *-use family (iphone-use drives your real iPhone; bitwarden-use pulls passwords/2FA/passkeys from your Bitwarden vault so an agent can log in with credentials; chrome-use drives your real Chrome).
Originally based on vercel-labs/agent-browser (Apache-2.0); now a standalone project — the stealth/extension-relay architecture, anti-detection, humanize, multi-agent isolation, and CLI have diverged substantially.
📚 Documentation: chrome-use.leeguoo.com — full guides, workflows & command reference (中文 · English).
📖 Deep dive: Letting an agent click into cross-origin iframes — how chrome-use solves the hardest part of browser control · Driving your already-logged-in real Chrome (CreepJS scores it 0% bot) — 中文
No fresh Chrome. No re-login. No "are you a robot?" walls.
chrome-use points any agent — Claude Code, Cursor, Codex, your own scripts — at the Chrome you're already signed into everything on. It clicks in your window, so you watch it work and grab the wheel the moment it hits a 2FA prompt or captcha. And because it's literally your real browser (over a one-click extension, native messaging — no debug port), sites read it as 100% human: CreepJS scores it 0% bot.
Why not just use…
- Playwright / Puppeteer / browser-use? They boot an empty browser — so you redo every login, fight every captcha, and still get flagged as automation. We use the session you already have.
- Claude's Chrome extension? Great, but it only drives Claude. This drives any agent or CLI.
- A raw
--remote-debugging-port(web-access, etc.)? Chrome 136+ pops "Allow remote debugging?" on every connect. This never does — one-click Store extension, native messaging.
Full feature comparison (the receipts)
| Claude in Chrome | web-access / raw CDP port | Playwright · Puppeteer · browser-use | chrome-use | |
|---|---|---|---|---|
| Works with any agent / CLI (not one app) | ❌ Claude only | ✅ | ✅ | ✅ |
| Drives your real, logged-in Chrome | ✅ | ✅ | ❌ fresh empty profile | ✅ |
| No "Allow remote debugging?" popup | ✅ | ❌ every connect | — (own browser) | ✅ native messaging |
| Real-browser fingerprint (CreepJS ~0%)¹ | ✅ | ✅ | ❌ automation markers / headless | ✅ verified 0% |
No Runtime.enable CDP leak (rebrowser)² |
— | ❌ leaks | ❌ leaks | ✅ off by default |
| Many agents on one real Chrome, isolated tab groups³ | ❌ single app | ❌ separate browsers | ✅ | |
| Permissions footprint | 16 incl. <all_urls> |
full CDP | full control | 7, no <all_urls> |
¹ All three real-Chrome tools score ~0% on CreepJS (it's a real browser); we've measured ours. ² rebrowser's runtimeEnableLeak — verified clean on our relay path; Claude in Chrome not independently tested (—). ³ web-access can run parallel sub-agents on one browser, but without per-session isolation; each --session here gets its own colored, command-isolated tab group. See Anti-detection for the measured numbers.
Typical browser automation (Playwright, Puppeteer, or a fresh --launch) opens a brand-new browser with an empty profile. You have to log in again, and websites can tell it's automated.
chrome-use connects to your existing Chrome. Your cookies, sessions, and browser fingerprint are all real — because it IS your real browser.
| chrome-use | chrome-use | |
|---|---|---|
| Browser | Launches new Chrome | Connects to your Chrome |
| Login state | Empty, need to re-login | Your existing sessions |
| Fingerprint | Automation markers present | Your real fingerprint |
| User collaboration | Separate window | Same window, take over anytime |
| CAPTCHA | Agent stuck | You solve it, agent continues |
Your chrome-use CLI talks to a tiny browser extension over Chrome
native messaging — a local inter-process channel, no network socket, no
token, no remote server. The extension uses chrome.debugger to drive the tabs
you target in your own, already-logged-in Chrome, then hands results back to
the CLI. Everything stays on your machine.
Each --session gets its own colored Chrome tab group, so multiple agents
can share one real browser concurrently without stepping on each other — or your
own tabs.
Other local tools drive Chrome over a raw --remote-debugging-port (CDP). Since
Chrome 136, every such connection pops a blocking "Allow remote debugging?"
consent dialog — and the port has to be enabled up front. Our extension uses
native messaging instead: install once, then zero per-use confirmation.
| chrome-use (this extension) | web-access (raw CDP port) | Claude in Chrome (chrome.debugger) | |
|---|---|---|---|
| Connect method | native messaging — no port, no token | --remote-debugging-port |
chrome.debugger |
| "Allow remote debugging?" popup | never ✅ | every connection 🔴 | no |
| Uses your real login | yes | yes | yes |
Runtime.enable (CDP) leak¹ |
off by default → clean ✅ | domain enabled | n/a |
| CreepJS stealth score² | 0% stealth · 0% headless ✅ | real Chrome | real Chrome |
| Per-session tab groups / concurrent agents | yes ✅ | no | no |
| Built for the chrome-use CLI | yes | a separate proxy | a single-app assistant |
¹ Verified against rebrowser-bot-detector: our relay reports
runtimeEnableLeak: 🟢 No leakandnavigatorWebdriver: 🟢. ² Verified against CreepJS on the connected real-Chrome path — see Anti-detection.The consent dialog isn't hypothetical: a raw-port tool pops it on every attach (Chrome 136+ security). The extension path never does.
curl -fsSL https://raw.githubusercontent.com/leeguooooo/chrome-use/main/install.sh | shDownloads the prebuilt binary for your platform from the latest GitHub Release and installs chrome-use (+ the abs alias). No npm, no tokens.
Other ways to install
- Pin a version:
AGENT_BROWSER_VERSION=v0.27.0-fork.12 curl -fsSL https://raw.githubusercontent.com/leeguooooo/chrome-use/main/install.sh | sh - Custom location:
AGENT_BROWSER_BIN_DIR=$HOME/bin curl -fsSL … | sh - Windows: download
chrome-use-win32-x64.tar.gzfrom the Releases page and putchrome-use.exeon your PATH. - npm (legacy):
npm install -g chrome-use— still published, but GitHub Releases is the primary channel now.
Claude Code — plugin marketplace (recommended): installs the skill globally (all projects), auto-updates, and lists the rest of the *-use family:
/plugin marketplace add leeguooooo/plugins
/plugin install chrome-use@leeguooooo-plugins
Other agent runners (Cursor, Codex, custom): pull the SKILL.md with skills.sh. Add -g for a global install (visible to every project); drop it to install only into the current project:
npx skills add leeguooooo/chrome-use -gThe
install.shone-liner above already runs this step for you (opt out withAGENT_BROWSER_NO_SKILL=1). Run it by hand only when you skipped the installer or use a non-default agent runner.
Either way the agent gets the right usage patterns and pre-approved bash permissions for chrome-use and abs; the skill self-heals a missing binary by re-running the install.sh one-liner above. Specialized guides (electron, slack, agentcore, …) are served by the binary itself via chrome-use skills get <name>, so instructions always match the installed version.
Agents that run a shell should use the skill above (it's lighter). For hosts that speak MCP but can't run arbitrary shell commands — Claude Desktop, ChatGPT connectors, n8n/Dify — run chrome-use as an MCP stdio server instead:
chrome-use mcp # stdio Model Context Protocol server (core tool profile)Wire it into Claude Desktop's claude_desktop_config.json:
{
"mcpServers": {
"chrome-use": { "command": "chrome-use", "args": ["mcp"] }
}
}Exposes a core profile of typed tools (chrome_use_open / read / snapshot /
click / fill / type / press / eval / wait / back / forward /
reload); each tool-call delegates to the same binary in --json mode. Use the
absolute path as command if chrome-use isn't on the host's PATH.
chrome-use, chrome-use, and abs are the same binary —
abs is just a short alias. There is no separate "stealth executable"; stealth
is a runtime behavior (see Anti-detection below), applied
automatically based on whether you attach to your real Chrome or --launch a
fresh one.
Recommended — the browser extension (one click, no popups). Install the chrome-use extension from the Chrome Web Store, then register the local bridge once:
chrome-use extension install # register the native-messaging host (one-time)
chrome-use open https://x.com/homechrome-use open then drives your real, logged-in Chrome over native
messaging — no debug port, no token, and no "Allow remote debugging?" dialog,
ever. The extension auto-updates and survives Chrome restarts, so it stays
connected with zero per-use confirmation (ideal for unattended/agent use).
Alternative — raw remote-debugging port (pops a consent dialog)
Without the extension, chrome-use attaches over the Chrome DevTools Protocol,
which Chrome only exposes when launched with a remote-debugging port (a
startup flag — the chrome://inspect toggle alone is not enough):
# macOS
open -a "Google Chrome" --args --remote-debugging-port=9222
# Linux
google-chrome --remote-debugging-port=9222
# Windows: add --remote-debugging-port=9222 to your Chrome shortcut's targetThen chrome-use open <url> auto-discovers the port. On first attach,
Chrome 136+ shows an "Allow remote debugging?" dialog — click Allow once (it
persists for that Chrome session). The extension above avoids this entirely.
No setup / don't want to touch your real Chrome? Use
chrome-use --launch open <url> to spawn a fresh isolated stealth browser
(full anti-detection patches applied; see below). This always works without any
port setup and is what CI uses automatically.
# Connect to your Chrome and navigate
chrome-use open https://example.com
# Everything works through your logged-in browser
chrome-use click "Post"
chrome-use click 449 320 # …or click a raw viewport coordinate
chrome-use fill "Title" "Hello World"
chrome-use screenshot ./page.pngThe agent operates in your Chrome — you'll see tabs opening, pages loading, clicks happening in real time. You can take over at any point (e.g. solve a CAPTCHA), then let the agent continue.
Spawn a separate browser instead of attaching to your running Chrome:
# Throwaway: fresh, EMPTY profile — no cookies, no login (good for CI/testing)
chrome-use --launch open https://example.com
# Keep your login: launch with your real Chrome profile (cookies/sessions intact)
chrome-use --launch --profile auto open https://x.com/home
# or name it explicitly: --profile Default / --profile "Profile 1"
⚠️ Plain--launch(no--profile) uses a temporary empty profile — you will NOT be logged into anything. For logged-in sites use--profile auto(picks the Chrome profile you used most recently) or--profile <name>. chrome-use prints a warning when you--launchwithout a profile.
In CI environments, standalone mode is used automatically.
Most "read GitHub issues" / "search Reddit" / "get my Bilibili feed" tasks don't
need clicking and screenshotting at all — the site already has a JSON API behind
its own login. A site adapter is a tiny JS function that calls that API from
inside your logged-in tab (your cookies, same-origin fetch, the site's own
modules) and returns clean JSON. The site can't tell it apart from you, because it
is you.
chrome-use ships none of these adapters — site update fetches the community
bb-sites pack at runtime (like a package
manager pulling a dependency), then runs them over chrome-use's stealth transport:
chrome-use site update # fetch the adapter pack (~145 commands)
chrome-use site list # github/issues, reddit/search, bilibili/feed, …
chrome-use site info github/issues # see an adapter's args + domain
# Run one — navigates to the site (reusing the tab if you're already there) and returns JSON
chrome-use site github/issues epiral/bb-browser --json
chrome-use site reddit/search "rust async" --json
chrome-use site bilibili/feed --json # works because it's your logged-in sessionPositional args fill the adapter's declared args in order; --key value overrides
by name. Adapters are authored by the bb-sites community and remain their authors'
property — chrome-use just runs them.
Auto-sync + auto-suggest. You rarely type site update yourself: chrome-use
syncs the pack on first use and refreshes it weekly in the background (tune with
AGENT_BROWSER_SITES_TTL_DAYS, disable with AGENT_BROWSER_SITES_NO_AUTO_UPDATE=1).
And when you open/snapshot a page whose domain has adapters, chrome-use surfaces
them right in the output — a 💡 site adapters for <domain> line, plus a
siteAdapters field under --json — so an agent reaches for the structured-data
adapter instead of scraping the DOM:
$ chrome-use open https://github.com
💡 site adapters for github.com — prefer these for structured data:
github/issues, github/me, github/repo, …
e.g. chrome-use site github/issues --json
✓ GitHub
Turn the repetitive "open it, click around, check it's right" work into a re-runnable suite — unit tests for the frontend. Write cases in YAML; steps reuse chrome-use's own commands and assertions compile to a single check:
# smoke.yaml
suite: chatgpt smoke
setup:
- account: chatgpt/huayue # inject a cookie-use login (optional)
cases:
- name: home loads logged in
steps:
- open: https://chatgpt.com/
- wait: { load: networkidle }
assert:
- url: { contains: chatgpt.com }
- visible: "#prompt-textarea"chrome-use test smoke.yaml # launches an isolated browser, runs cases
chrome-use test smoke.yaml --session default # …or against your connected Chromesuite: chatgpt smoke (session cu-test)
✓ home loads logged in 1.2s
✗ composer takes text 0.8s
assert text "#prompt-textarea" contains "hi" → got ""
↳ cu-test-artifacts/composer-takes-text.png
2 cases · 1 passed · 1 failed
Exit code is non-zero if any case fails (drop it into CI), and failed cases save
a screenshot. Assertions: url · visible · hidden · text · count ·
eval. Steps: open · click · fill · type · press · wait · scroll
· eval. Full guide: chrome-use skills get test. Deep-dive writeup (中文):
给前端写「单元测试」:chrome-use test 详解.
Found a regression? Add a case — the suite gets more valuable the more you use it.
Mock a response, rewrite an outgoing request, or block one — right on the Chrome you're driving, over the CDP Fetch domain. No proxy, no CA cert, no JS injection, no extra extension permission.
chrome-use network route "*/api/me" --body '{"vip":true}' --status 200 --content-type application/json # mock response
chrome-use network route "*/api/save" --method POST --set-header Authorization="Bearer test" # rewrite request
chrome-use network route "*/v1/*" --rewrite-url https://staging.example.com/v1/thing # redirect
chrome-use network route "*/api/me" --edit-status 503 --edit-header X-Env=test --replace 'prod=>staging' # edit the real response
chrome-use network route "*/analytics" --abort # blockVerbs/fields mirror Playwright's route/fulfill/continue/abort. Deep-dive
writeup (中文): 改网络请求和响应:chrome-use network route 详解.
When connected to your real Chrome, we inject zero JavaScript patches. Your browser's fingerprint is completely genuine. The guiding rule is native CDP/Chrome overrides over JS lies — a re-defined getter is itself detectable; a native override isn't.
navigator.webdriver = falseviaEmulation.setAutomationOverride(native, undetectable by CreepJS-style lie tests).Runtime.enableis left OFF by default. A liveRuntimedomain is a detectable CDP signal (the patchright/rebrowser "runtime leak") — even when attached to your real Chrome. We only enable it when you opt into console/error capture (see below).click,fill,eval, etc. work without it.
Test results (connected to real Chrome):
| Test site | Result |
|---|---|
| CreepJS | 0% stealth · 0% headless (no override traces at all) |
| bot.incolumitas.com | all checks OK — overflowTest, overrideTest, puppeteerExtraStealthUsed, worker consistency |
| bot.sannysoft.com | all green |
| BrowserScan | Webdriver · User-Agent · CDP all clean |
| Cloudflare Turnstile | passed |
0% stealth on CreepJS is the key number: because the connect path patches nothing, there is no override for a lie-detector to catch. (Dashboards that read navigator.languages order or IP geolocation may show a soft "navigator"/"location" flag — that tracks your real Chrome's language list and network, not an automation tell.)
When using --launch mode (standalone browser), a full suite of stealth patches is applied instead, and it passes the suite above — with one caveat: CreepJS reports ~20% stealth because the srcdoc-iframe contentWindow patch trips its hasIframeProxy probe (the proxy that hides automation is itself a tell). Everything else is clean (0% headless, sannysoft/browserscan green, Cloudflare passed). Set AGENT_BROWSER_DISABLE_IFRAME_PROXY=1 to drop that patch for a clean 0% stealth (trades the niche srcdoc-iframe masking). The extension-connect path (your real Chrome) injects zero JS and is unaffected — it's the genuine 0% path.
Fingerprint stealth isn't the whole story — the strongest anti-bot vendors (Akamai, PerimeterX, DataDome) also score behaviour. A click that teleports the cursor to an element's exact centre with no approach path and zero press delay is a tell, even though our CDP events are isTrusted.
With humanize on, the cursor moves like a hand: clicks follow a curved, decelerating Bézier path and land on a jittered point inside the element (never the dead centre); typing uses variable inter-keystroke timing; scrolling eases in segments; drags follow a curve. It's adaptive — every navigation is probed for known anti-bot vendors (cookies / scripts / globals) and a guarded page auto-escalates to full human motion, while ordinary sites stay instant (zero overhead).
What the page's own mousemove stream sees (this is what a behavioural detector analyses):
| trajectory | |
|---|---|
| off (default) | straight lines · dead-centre · instant |
| human | curved trails · slow-in/slow-out · off-centre landings |
Control with --humanize off\|fast\|human or AGENT_BROWSER_HUMANIZE. Default off; the adaptive detector escalates per page.
Driving your real Chrome should never interrupt your work. The agent operates entirely in the background: new tabs open un-focused (in their own colored per-session tab group), the agent never force-fronts a tab, and Emulation.setFocusEmulationEnabled keeps each agent tab rendering and reporting document.hasFocus() / visibilityState: 'visible'. So screenshots still work, pages aren't render-throttled, and "the tab was hidden the whole session" never becomes its own bot tell. You keep working in your active tab; the agent works alongside you, silently. (Surfacing a tab stays available as an explicit command.)
Don't take our word for it — point your connected Chrome at the toughest public detectors and compare:
- CreepJS — the most thorough fingerprint / lie detector
- bot.incolumitas.com — behavioral + fingerprint scoring with a public methodology
- BrowserScan — Webdriver / User-Agent / CDP / Navigator
- bot.sannysoft.com — the classic automation-marker checklist
- pixelscan.net · iphey.com — consistency & identity
We deliberately don't ship our own bot detector — the strongest, most honest benchmark is the market's best detectors run against your real browser.
| Variable | Default | Effect |
|---|---|---|
AGENT_BROWSER_CAPTURE_CONSOLE |
off | Enable Runtime domain so console / errors capture page output. Off keeps the stealthiest profile. |
AGENT_BROWSER_HUMANIZE |
off | Human-like input motion: off (instant), fast (light eased trajectory), human (full curved trajectory + landing jitter + typing cadence + eased scroll/drag). Also --humanize. Default off; the adaptive detector auto-escalates pages guarded by Akamai/PerimeterX/DataDome to human. |
AGENT_BROWSER_TIMEZONE |
unset | --launch only. An IANA id (e.g. Asia/Tokyo) sets the timezone natively (Intl + Date follow, no JS lie) to match a proxy; auto derives one from the locale. |
AGENT_BROWSER_BLOCK_WEBRTC |
auto | --launch only. Auto-forces WebRTC through the proxy when one is set (no real-IP leak). 1 hides the local IP without a proxy; 0 opts out. |
AGENT_BROWSER_HIDE_CANVAS |
off | --launch only. Adds session-stable canvas/audio fingerprint noise. Off by default (noise is itself a "lie"). |
AGENT_BROWSER_ADAPTIVE_REF |
on | When a saved @ref moves and the role/name re-query fails, relocate it by fingerprint similarity (high score + clear margin required, else it fails loudly). 0 disables. |
AGENT_BROWSER_CLICK_MODE |
(auto) | Click strategy. Default scrolls the target into view, dispatches a coordinate click, and falls back to a DOM .click() if a floating layer occludes the point. dom always uses .click() (best for autocomplete/menu items that close on blur); coord is strict coordinate-only (hard-fail on occlusion). |
- Auto-connect is default —
chrome-use open <url>drives your existing Chrome instead of launching a new one - Extension-relay transport — a one-click Chrome Web Store extension + native messaging, so there's no debug port and no "Allow remote debugging?" dialog
- CDP-native stealth — anti-detection via Chrome/CDP overrides rather than JS patches; zero patches when attached to your real Chrome, full patches only for
--launch - Humanize — human-like cursor trajectories + adaptive anti-bot handling
- Multi-agent isolation — concurrent agents share one real Chrome via per-session tab groups, no cross-talk
- Silent operation — runs in the background; never steals your foreground tab
Originally based on vercel-labs/agent-browser (Apache-2.0); the projects have since diverged substantially.
Thanks to everyone who has contributed to chrome-use!
Built by leeguooooo — field notes on AI agents, reverse engineering & Cloudflare Workers at blog.leeguoo.com · follow on X @leeguooooo




