Sessions & Auth

Stealth & Anti-detection

Many sites actively block browser automation—at best a challenge or CAPTCHA, at worst an outright account ban. Tools like Playwright or Puppeteer with a stealth plugin patch a blank browser into impersonating a human, and every patch is a crack for the anti-bot systems to find. chrome-use's answer is different: it doesn't simulate a human—it IS your real, already-logged-in browser.

Why anti-detection is a core capability

For any agent running against real sites, the first hurdle isn't "can it click a button," it's can it avoid being flagged as a bot. Anti-bot vendors like Akamai, PerimeterX, DataDome, and Cloudflare look at both the fingerprint (does the browser show automation traces) and the behavior (how the mouse moves, how text is typed). Once triggered, the cost is often more than a single failed request—it's this account getting flagged and banned.

So chrome-use treats anti-detection as a first-class capability, not an afterthought patch. The core idea in one line: prefer driving your real, already-logged-in Chrome—what the site sees is a genuine human browser. Only for the cases that truly need an isolated browser do we fall back to the "native overrides > JS lies" approach to keep the traces clean.


Core philosophy: 0% stealth = change nothing

When connected to your real Chrome (via the extension relay), the number of JavaScript patches chrome-use injects is zero. Your browser's fingerprint is completely real. The guiding principle is "native CDP/Chrome overrides over JS lies"—a redefined getter is itself detectable, while a native override is not.

✅ Why 0% is the strongest score
On CreepJS, 0% stealth is the key number: because the connection path changes nothing, the lie-detector has no "override" to catch at all. It isn't "the patches are well made," it's there are no patches at all—this is the real browser's own score.

Measured results

chrome-use deliberately ships no bot detector of its own—the most honest benchmark is to point the strongest detection sites on the market straight at your real browser. Here are the measured results when connected to a real Chrome:

measured results · connected to real Chrome
# CreepJS —— the strictest fingerprint / lie detector
CreepJS            0% stealth · 0% headless   # zero override traces at all

# bot.incolumitas —— combined behavior + fingerprint score (public methodology)
bot.incolumitas    all checks OK          # overflowTest / overrideTest /
                                          # puppeteerExtraStealthUsed / worker consistency

# classic automation-flag checklist
bot.sannysoft      all green
BrowserScan        Webdriver · User-Agent · CDP all clean
Cloudflare Turnstile (nowsecure.nl)  passed
ℹ️ About "soft flags"
When some dashboards read navigator.languages order or IP geolocation, they may raise a soft navigator / location flag—that reflects your real Chrome's language list and network, not an automation trace.
⚠️ A caveat for --launch isolated browsers
With --launch (a standalone browser), a full set of stealth patches is applied instead, which also passes the detections above— but CreepJS will report ~20% stealth, because the srcdoc-iframe contentWindow patch trips its hasIframeProxy probe (the very proxy used to hide automation becomes the crack). Everything else is clean (0% headless, sannysoft/browserscan all green, Cloudflare passes). Set AGENT_BROWSER_DISABLE_IFRAME_PROXY=1 to drop that patch and get a clean 0% stealth. The extension connection path (your real Chrome) injects zero JS and is unaffected—it is the true 0% path.

Three lines of defense

In chrome-use, anti-detection is three layers stacked: from "which browser to use" to "what the fingerprint looks like" to "how human the behavior is."

① Real session > headed > headless (disabled)

Anti-detection ranking: real, already-logged-in Chrome (extension connection) > headed launched browser > headless (disabled). A genuine human browser has no headless / automation cracks at all, so any anti-bot-sensitive task should prefer it. Headless is disabled by default—it is itself a bot crack (--headed is the stealth default and always on).

bash · headed by default
# --headed is the stealth default, always on —— headless is disabled
# (it's a bot crack: creepjs reports ~33% for headless, 0% for headed)
# only unlock it on a headless server with no display:
$ AGENT_BROWSER_ALLOW_HEADLESS=1 chrome-use --launch open "https://example.com"

② Native fingerprint overrides

For isolated / launched browsers, use native overrides to align key fingerprints to the identity you want—none of them are JS lies, so lie-detectors can't catch them. These switches only apply to --launch:

bash · fingerprint overrides (--launch)
# native timezone override (IANA id, or "auto" to derive from locale), Intl+Date follow, no JS lies
$ AGENT_BROWSER_TIMEZONE="Asia/Tokyo" chrome-use --launch open "https://example.com"

# hide the local IP via WebRTC (when a proxy is set, force through it so the real IP never leaks)
$ AGENT_BROWSER_BLOCK_WEBRTC=1 chrome-use --launch open "https://example.com"

# session-stable canvas/audio fingerprint noise (off by default, because noise is itself a kind of "lie")
$ AGENT_BROWSER_HIDE_CANVAS=1 chrome-use --launch open "https://example.com"
ℹ️ webdriver is a native override too
navigator.webdriver = false goes through Emulation.setAutomationOverride—a native implementation, not a redefined getter, so lie-detectors like CreepJS can't catch it.

③ Behavior layer: --humanize beats Akamai/PerimeterX/DataDome

A clean fingerprint isn't everything—the strongest anti-bot vendors also score behavior. A click that teleports the cursor to the dead center of an element with zero press delay is a crack, even though our CDP events are isTrusted. With humanize on, the cursor moves like a hand: a click lands along a curved, decelerating Bézier trajectory on a jittered point inside the element (never dead center); typing uses variable keystroke intervals; scrolling eases in segments; drags follow a curve.

It's adaptive—each navigation probes for known anti-bot vendors (cookies / scripts / globals), and guarded pages auto-upgrade to full human motion, while ordinary sites stay instant (zero overhead).

bash · humanize
# off (default, instant) | fast (lightweight eased trajectory) | human (full curve + landing jitter + typing rhythm + eased scroll/drag)
$ chrome-use --humanize human click "@ref=e42"

# or set the default for the whole session via an env var
$ AGENT_BROWSER_HUMANIZE=human chrome-use type "hello"
✅ Leave it on auto
The default is off, and the adaptive detector auto-upgrades pages guarded by Akamai/PerimeterX/DataDome to human. Only force human manually when you already know for sure the target scores behavior.

Cloudflare: pass once, reuse the clearance

Passing a Cloudflare challenge once mints a cf_clearance cookie (HttpOnly—invisible to eval/document.cookie, read it with chrome-use cookies). It's bound to your IP + User-Agent: reuse the same egress IP and UA to skip the challenge until it expires. Driving the user's real Chrome (relay) persists it natively; for an isolated session, use --session-name <name> to save / restore.

Before spending effort on solving it, run chrome-use cf-status (aliases cf, clearance) as a preflight— to avoid re-solving a challenge that's already passed.

bash · cf-status
# preflight: is the page currently a Cloudflare challenge? is there already a valid cf_clearance?
$ chrome-use cf-status

# read the HttpOnly cf_clearance cookie
$ chrome-use cookies
ℹ️ The three recommendations cf-status gives
proceed (already through, don't re-solve), solve (challenge present, no clearance), reissue (has clearance but the page is still blocked → IP/UA drifted, re-solve). Treat it as a preflight, don't re-solve a challenge that's already passed.

Self-check: chrome-use stealth status

You can inspect the current stealth state at any time: chrome-use stealth status reports the current mode plus a set of live probes (webdriver / chrome / plugins / UA), along with the overrides in effect. Add --json for machine-readable output.

bash · stealth status
# stealth self-check: mode + live probes (webdriver / chrome / plugins / UA) + overrides in effect
$ chrome-use stealth status
$ chrome-use stealth status --json

Related pages