Real-world dogfooding surfaced clicks that resolve a valid @ref but still miss: - Scroll the target into view before computing click coordinates (scrollIntoViewIfNeeded). Without it, an element below the fold — or revealed after a scroll/popup — yields off-viewport coordinates and the click lands on whatever occupies that screen point. - Fall back to a DOM-dispatched `.click()` when the coordinate path fails (a persistent floating layer failing the occlusion guard, or coordinates that won't resolve). The DOM dispatch targets the intended element directly instead of a screen point, so an overlay or portal can't divert it. - AGENT_BROWSER_CLICK_MODE: "" (default: scroll + coordinate + DOM fallback), "coord" (strict coordinate, hard-fail on occlusion), "dom" (always element.click() — best for autocomplete/menu <li> that close on input blur). Fallback is limited to left single-clicks (DOM .click() can't express right/middle/double). Non-left/multi and "coord" mode keep the original error. Docs: README knob table + skill commands.md gain CLICK_MODE, a click-reliability note, and a "debug forms/hidden inputs with eval" section (snapshot doesn't show hidden inputs — the fast path to bugs like a hidden point_choice=none). 6 click/interaction e2e green; full suite 760 passed.
agent-browser-stealth
Stealth fork of agent-browser — connects to your real Chrome, shares your login sessions, and is undetectable by anti-bot systems.
For basic usage, commands, and API reference, see the upstream documentation.
Why this fork?
agent-browser launches a fresh browser with an empty profile. You need to log in again, and websites can detect it's automated.
agent-browser-stealth connects to your existing Chrome. Your cookies, sessions, and browser fingerprint are all real — because it IS your real browser.
| agent-browser | agent-browser-stealth | |
|---|---|---|
| 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 |
Install
curl -fsSL https://raw.githubusercontent.com/leeguooooo/agent-browser-stealth/main/install.sh | sh
Downloads the prebuilt binary for your platform from the latest GitHub Release and installs agent-browser (+ 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/agent-browser-stealth/main/install.sh | sh - Custom location:
AGENT_BROWSER_BIN_DIR=$HOME/bin curl -fsSL … | sh - Windows: download
agent-browser-win32-x64.tar.gzfrom the Releases page and putagent-browser.exeon your PATH. - npm (legacy):
npm install -g agent-browser-stealth— still published, but GitHub Releases is the primary channel now.
Install the AI agent skills
The repo ships SKILL.md files for Claude Code, Cursor, etc. Pull them into the current project with skills.sh:
npx skills add leeguooooo/agent-browser-stealth
This drops skills/agent-browser (and the specialized skill-data/{core,electron,slack,dogfood,agentcore,vercel-sandbox}) into your project so your AI agent gets the right usage patterns and pre-approved bash permissions for agent-browser, agent-browser-stealth, and abs.
Command names
agent-browser, agent-browser-stealth, 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.
Setup: connect to your Chrome
Attaching uses the Chrome DevTools Protocol, which Chrome only exposes when it is
launched with a remote-debugging port. This is a startup flag, not a setting
— the chrome://inspect toggle alone is not enough (it only enables target
discovery, not the CDP attach).
Recommended — fully quit Chrome, then relaunch with the port:
# 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 target
Then run agent-browser open <url> — it auto-discovers the port and attaches.
On first attach, Chrome 136+ shows an "Allow remote debugging?" dialog — click
Allow once (it persists for that Chrome session).
No setup / don't want to touch your real Chrome? Use
agent-browser --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.
Usage
# Connect to your Chrome and navigate
agent-browser open https://example.com
# Everything works through your logged-in browser
agent-browser click "Post"
agent-browser fill "Title" "Hello World"
agent-browser screenshot ./page.png
The 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.
Standalone mode (--launch)
Spawn a separate browser instead of attaching to your running Chrome:
# Throwaway: fresh, EMPTY profile — no cookies, no login (good for CI/testing)
agent-browser --launch open https://example.com
# Keep your login: launch with your real Chrome profile (cookies/sessions intact)
agent-browser --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>. agent-browser prints a warning when you--launchwithout a profile.
In CI environments, standalone mode is used automatically.
Anti-detection
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 |
| bot.sannysoft.com | All green |
| Cloudflare Turnstile | Passed |
When using --launch mode (standalone browser), a full suite of 32 stealth patches is applied for headless Chrome.
Tuning knobs (environment variables)
| Variable | Default | Effect |
|---|---|---|
AGENT_BROWSER_CAPTURE_CONSOLE |
off | Enable Runtime domain so console / errors capture page output. Off keeps the stealthiest profile. |
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). |
Differences from upstream
Based on agent-browser v0.27.0. Changes:
- Auto-connect is default —
agent-browser open <url>connects to your Chrome instead of launching a new one - CDP-native stealth —
Emulation.setAutomationOverrideinstead of JS patches - Dual stealth mode — zero patches for real Chrome, full patches for
--launchmode --launch/--newflag — explicitly start a standalone browser- CI auto-detection — standalone mode when
CIenv var is set
All upstream features (commands, snapshots, screenshots, recordings, tabs, sessions, etc.) work the same. See the upstream repo for full documentation.
License
Apache-2.0 (same as upstream)