chrome-use
chrome-use
English · 简体中文

chrome-use drives your real, logged-in Chrome from any AI agent. It shares your existing login sessions and uses your existing browser profile; public detector results are documented, not a guarantee for every website. 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), 中文
Advertisement · Available
Advertise here
Showcase your product here and support ongoing maintenance.
Ask about advertising · leeguoooo@gmail.com
Paid setup and project sponsorship
Need help connecting your agent to your signed-in Chrome or setting up a browser workflow? Email us with your environment, the workflow and expected result, and where you are stuck. We review feasibility and agree on scope, acceptance criteria and a quote before work starts.
Ask about paid setup · Discuss sponsorship · leeguoooo@gmail.com
Want to support ongoing maintenance? Email us to discuss a one-time or recurring contribution.
Community bug reports and feature requests remain welcome on GitHub. Please keep credentials and private account data out of inquiries.
Related MCP server: byob
Give your AI agent the browser you already live in
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), the documented CreepJS test reported: CreepJS scores it 0% bot.
A new browser context starts without your existing login sessions. Playwright and Puppeteer also support persistent profiles and existing-browser connections; compare the actual configuration. chrome-use connects to your existing Chrome. Your cookies, sessions, and browser fingerprint are all real, because it IS your real browser. Chrome 136 restricts remote debugging of the default profile; prompts and requirements depend on Chrome version and connection mode. Our extension uses native messaging instead: install once, then zero per-use confirmation.
Typical automation (Playwright · Puppeteer · browser-use) | web-access / raw CDP port | chrome-use | ||
Works with any agent / CLI (not one app) | ✅ | ✅ | ❌ Claude only | ✅ |
Drives your real, logged-in Chrome | Configurable; fresh contexts start empty | ✅ | ✅ | ✅ |
Connect method / "Allow remote debugging?" popup | — (own browser) |
|
| native messaging · never ✅⁴ |
Real-browser fingerprint (CreepJS ~0%)¹ | ❌ automation markers / headless | ✅ | ✅ | ✅ verified 0% |
No | ❌ leaks | ❌ leaks | — | ✅ off by default |
Many agents on one real Chrome, isolated tab groups³ | ❌ separate browsers | ⚠️ shared tabs, no isolation | ❌ single app | ✅ |
Permissions footprint | full control | full CDP | 16 incl. | 12, no |
¹ 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. ⁴ No consent dialog, but the extension still uses chrome.debugger, so Chrome shows its "started debugging this browser" bar while an agent tab is attached. See Setup for removing it. See Anti-detection for the measured numbers.
How it works

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. When --session is omitted, chrome-use derives a stable per-agent
session from supported runner IDs, including Codex's CODEX_THREAD_ID.
Explicit --session / AGENT_BROWSER_SESSION always win. Session naming,
session list / stop / prune, ownership handoff, and daemon recovery are
covered in the sessions guide.
Install
macOS / Linux
curl -fsSL https://raw.githubusercontent.com/leeguooooo/chrome-use/main/install.sh | shWindows (PowerShell)
irm https://raw.githubusercontent.com/leeguooooo/chrome-use/main/install.ps1 | iexDownloads the prebuilt binary for your platform from the latest GitHub Release and installs chrome-use. No npm, no tokens.
Pin a version:
curl -fsSL https://raw.githubusercontent.com/leeguooooo/chrome-use/main/install.sh | AGENT_BROWSER_VERSION=v1.5.188 shCustom location:
curl -fsSL … | AGENT_BROWSER_BIN_DIR=$HOME/bin shmacOS app bundle: on a Mac the installer puts
ChromeUse.app(signed and notarized) in<prefix>/share/chrome-use/next to the bin directory,~/.local/share/chrome-use/by default, andchrome-useis a symlink into it. That way System Settings → Privacy & Security → Files and Folders lists chrome-use once, as "ChromeUse" with its icon, when an agent you run from the side panel works in a project under Documents, Desktop or Downloads.AGENT_BROWSER_NO_APP_BUNDLE=1installs the bare binary instead.Windows, pin a version or location:
$env:AGENT_BROWSER_VERSION = 'v1.5.139'or$env:AGENT_BROWSER_BIN_DIR = 'D:\tools'before theirm … | iexline. It installs to%LOCALAPPDATA%\Programs\chrome-useby default and adds that to your user PATH, keeping the existing entries exactly as they were (opt out with$env:AGENT_BROWSER_NO_PATH = 1). No admin rights needed.Windows, by hand: download
chrome-use-win32-x64.tar.gzand its.sha256from the Releases page, check that(Get-FileHash chrome-use-win32-x64.tar.gz -Algorithm SHA256).Hashmatches the.sha256file, extract withtar -xzf chrome-use-win32-x64.tar.gz, and putchrome-use.exeon your PATH. Check the hash before running it: an interrupted download still extracts into an.exe, which then fails at launch with an access violation (exit code-1073741819,0xC0000005) rather than anything that says the download was incomplete.
Install with Nix
Run it once, no install: nix run github:leeguooooo/chrome-use -- --help.
The flake also ships a home-manager module and a NixOS module (programs.chrome-use.enable = true); on NixOS the native-messaging host is registered per-user, so run chrome-use extension connect once after switching (it registers the host the same way extension install does, then attaches to the extension relay).
Dev shell: nix develop (rust toolchain + node 24 + pnpm + chromium + vhs).
Full snippets: install guide.
Install the AI agent skill
With a current CLI, the installers install and verify its bundled discovery skill without Node, npx, Git or another download. To install or refresh it manually:
chrome-use skills install
chrome-use skills install --projectGlobal installation covers ~/.agents/skills, Claude Code, Codex and Cursor, plus existing Pi, OpenCode, Windsurf, CodeBuddy and Trae configurations. It respects CLAUDE_CONFIG_DIR and XDG_CONFIG_HOME. Project installation uses .agents/skills and .claude/skills, plus existing .pi, .windsurf, .codebuddy and .trae configurations. Restart your agent or reload its skills afterward. A failed write is an error, even if other destinations succeeded. See installation details.
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-pluginsAdditional runners: skills.sh remains available for runners outside the built-in mappings. This alternative requires Node and its own dependencies:
npx skills add leeguooooo/chrome-use -gThe install one-liners already install the bundled skill (opt out with
AGENT_BROWSER_NO_SKILL=1). PowerShell also extracts it from older pinned CLI releases, bypassing their npx installer. Installation errors stop completion; the final message does not claim that the Chrome extension is connected.
Codex users: Codex ships its own browser plugin and picks it for browser tasks. Measured on a machine with many skills installed, Codex also trims every skill description to a few characters (or none), so the skill's description cannot win the routing, and naming
chrome-usein the prompt was not enough either. What worked was one line in the project'sAGENTS.md:Use the `chrome-use` CLI from the shell for every browser task; start with `chrome-use skills get core`. Do not use the built-in Chrome plugin for browser work here.
Either way the agent gets the right usage patterns and pre-approved bash permissions for chrome-use; the skill self-heals a missing binary by re-running the install one-liner above for its platform. Specialized guides (electron, slack, agentcore, …) are served by the binary itself via chrome-use skills get <name>, so instructions always match the installed version.
The installed discovery skill should direct the agent to chrome-use skills get core; it should not carry a second command manual. If an older installed copy contains its own workflow without that handoff, refresh it before comparing core-guide changes.
Upgrading the binary does not move a SKILL.md already copied into a runner; that copy lives outside the binary. chrome-use upgrade handles both: it installs the latest GitHub Release, then refreshes each installed copy of the skill it finds (Claude Code plugin, a git checkout, or the folders its installer writes; for an npx skills add copy it prints npx skills update chrome-use). chrome-use upgrade --check (or --json) changes nothing and reports current vs latest plus where the skill is installed; exit code 2 means the check failed. Other commands, and the native host whenever Chrome starts it, check for a newer release at most once a day in the background; when one exists they install it in place in the background (it takes effect on the next run) and refresh the skill copies. CHROME_USE_AUTO_UPGRADE=0 turns off the automatic install and leaves a one-line stderr notice instead; CHROME_USE_NO_UPDATE_CHECK=1 or the family-wide USE_NO_UPDATE_CHECK=1 turns off the check altogether. A CLI installed where it cannot write (a package manager's path) is never replaced; it gets the notice and the command to run. The extension shows the same state in its popup and side panel, with an Update CLI button, and reports its own pending update there too. To refresh only the skill, run chrome-use skills update (refresh and install are the same command; add --project to install into ./ instead of globally).
Use from an MCP client (Claude Desktop, etc.)
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 by wiring it into Claude Desktop's claude_desktop_config.json:
{
"mcpServers": {
"chrome-use": { "command": "chrome-use", "args": ["mcp"] }
}
}Local agent side panel
Full guide: Agent chat.
Click the extension toolbar icon to open the side panel; Settings opens connection options. On macOS, Linux or Windows, choose Codex, Claude Code, OpenCode or Pi and use the installed CLI's existing login and provider configuration. The agent menu follows the connected host's capabilities; older hosts need an upgrade to offer newer adapters. Windows offers the same conversations, configuration preview/apply/restore, skills, images, options and schedules. Older Windows hosts need a CLI upgrade; no administrator access is needed. Agent processes run in owned Windows jobs, and private panel files use protected user/SYSTEM ACLs.
Codex uses its app-server protocol, Claude Code uses stream-json, OpenCode uses ACP, and Pi uses JSONL RPC. Each conversation has its own browser session. The current webpage appears as a tag above the composer and is attached to the next message so the agent can target that tab. Click × to leave it out of that message.
The model menu comes from the selected CLI's catalog. Default model keeps the CLI's configured model; a Custom model ID in the + menu overrides the menu choice. Reload models from CLI refreshes the catalog. CLI version, account state and model listings do not prove execution access. Agents & models discovers programs and supports configuration previews, verified writes and restore that preserves later edits. Saving a default does not change a conversation already running.
The permission switch applies to one conversation. New conversations start with Full access enabled unless you have saved a different choice:
Codex / Claude Code: turn it off for Ask first and review approval requests. Full access runs without those permission prompts and automatically answers supported approvals; agent questions still need your response.
OpenCode: turning it off selects CLI permissions. OpenCode's own rules may allow tools without asking. Requests it does send appear in the panel; full access answers them with Allow once and does not change its stored permission rules.
Pi: there is no per-tool approval mechanism. Turning full access off selects Browser only, exposing only the
chrome_useMCP tools, without shell or file tools. Turning it on enables the CLI's full tool set.
History streams replies, expandable tool rows and requests. Tool output does not prove the browser task succeeded. Messages sent during a reply enter a queue; edit or remove them before they start, using Load full text for truncated previews. Failure or interruption pauses the queue until Resume queue. After a failed or interrupted turn, a new message starts immediately in the same conversation and model; older queued messages stay paused until you resume them explicitly. Stop & send or Ctrl/Cmd+Enter waits for confirmed interruption or process exit before sending ahead of the ordinary queue, which remains paused. Reconnect reads existing history without resending. An unconfirmed send can be retried explicitly with its original message ID; clearing its warning does not cancel a task that may already have arrived.
Panel replies preserve fenced code literally. To show an example containing triple backticks, wrap it in a longer fence. A closing fence must use the same character, be at least as long as the opening fence, and have only whitespace after it.
To delete a conversation, stop its response, click the header's delete button and confirm. Deletion removes panel history and that conversation's browser session, plus Codex rollout files, Claude session files/directories, OpenCode history through session/delete, or Pi session files inside the conversation folder. Codex's SQLite cache is left untouched. The panel reports cleanup failures or unconfirmed tab closure.
In the /resume picker, changing the agent or search clears the previous selection immediately. Enter only selects a currently listed session; it does nothing while results are loading, unavailable or empty. Changing the agent/search or closing the picker also dismisses old confirmations and prevents earlier resume responses from opening the old conversation. Requests already sent to the host may still finish; fresh results remain selectable while they are pending.
/resume continues a Claude Code, Codex, OpenCode or Pi session you started in a terminal, and a new conversation can work in a project folder that a site can remember. See Continue a terminal session and Project folder.
Each conversation row offers Initial page, Final page, and Delete conversation. Initial page opens the first recorded HTTP(S) URL; Final page opens the most recently recorded URL, including while a task is running. A matching recorded tab is focused, otherwise the saved URL opens in a new tab. Opening the initial page preserves the final address. Older conversations without an initial address report it as unavailable. The title switches chats; opening a page does not send messages, rerun tasks or restore unsaved input. Addresses stay in local extension storage. Deletion requires confirmation and reports cleanup failures; stop a running reply before deleting.
If Chrome replaces a saved Initial page tab, the conversation follows its replacement instead of opening a duplicate. The saved initial and final addresses remain separate.
Panel history is stored locally under ~/.chrome-use/agent-panel, scoped to the Chrome profile. The selected CLI may send tasks and page content to its configured model service, whose privacy policy applies. The side panel adds no webpage content script; opening it can change the page viewport. Inspect & Ask (below) injects into a page only when you press its shortcut or button. Custom programs require an absolute path.
Clicking a task notification activates the conversation tab and focuses the window containing that tab, even when another Chrome window was last active or the current window is not yet known. A bound conversation tab takes precedence over the last-window fallback.
The panel also supports:
Skills: type
/to choose a bundled, user or profile-library skill. Agents & models → Skill library edits library entries, enables/disables them, and imports an absolute local folder, ZIP/.skill archive or HTTPS Git repository. User and CLI skill folders are read-only here. A selected skill and its assets are snapshotted before delivery, so queued messages and explicit retries retain the selected revision. Panel-bound agents can usechrome_use_skillsto list/read skills, read selected relative text assets and save library instructions when asked.Images: paste, drop or choose up to five PNG/JPEG/WebP/HEIC files with Attach images. Chrome cannot decode HEIC, so the local CLI converts it to JPEG with the system codec (macOS
sips; Windows needs the HEIF Image Extensions and HEVC Video Extensions from the Microsoft Store; Linux needsheif-convertor ImageMagick with HEIF support), applies the photo's rotation and drops its EXIF metadata, including GPS. Images are reduced to a 2000-pixel long edge and at most 512 KiB each before native transport. They stay with the conversation, including queued-message edits and retries, and are removed with it. ACP agents must advertise image input; unsupported input fails instead of dropping the images. The model service receives the attachments.Conversation options: choose allowed tools and, for Codex/Claude, reasoning effort; Codex also supports a service-tier override. Save while idle. Overrides take effect on the next response and do not edit CLI defaults. Codex can restrict writes but cannot remove its file-reading shell. OpenCode ACP does not enforce built-in tool restrictions; its own permission rules still apply. The approval switch controls automatic answers within the selected tool set; Pi has no per-call approvals.
Scheduled prompts: Agents & models → Scheduled prompts saves intervals, daily/weekday local times or five-field cron, with agent, model, options, skill and explicit tool scope. Run now does not move the next scheduled time. Runs use independent background browser sessions and remain in history; completion notifications link to their conversations. The host-local service must be running; closing the panel does not stop it. On restart or wake, missed periods coalesce into one run. An active or unconfirmed run is never overlapped or replayed; inspect the history before acknowledging an unknown outcome. A chat cannot schedule more tools or automatic approval than it has, and scheduled conversations cannot mutate or trigger schedules or rewrite library skills for future runs. Native acceptance and agent completion remain separate from verifying the requested page effect.
Finish notifications: when a panel task finishes, fails, stops, needs recovery or waits for your approval, Chrome shows a notification (outcome plus at most the first line of the redacted answer) and the toolbar icon counts the unseen ones. Clicking it opens the side panel on that conversation. Nothing is shown for the conversation the panel already has open in the focused window. Turn it off with Settings → Notify when a task finishes. Scheduled runs keep their own notification.
If Chrome rejects a panel turn notification, a later check in the same extension-worker session retries it. Disabled notifications and turns already being viewed remain suppressed. Viewing a turn while its notification is being created also consumes that turn if creation later fails, including across worker restarts.
Inspect & Ask: click an element, let your agent change it
Press Alt+Shift+C (or Inspect element in the toolbar popup), click an element, write what should change and press Enter. chrome-use sends your words, the element's source file:line, a cropped screenshot and its styles through ocs to the Claude Code, Codex or Pi session already running in that project. It works on local dev servers and on test-environment domains in your logged-in Chrome.
Source locations come from code-inspector-plugin's
data-insp-pathmarks (Vite, webpack, Rspack, esbuild, Turbopack; React, Vue and more). React 18 and Vue dev builds work without it; otherwise the message says "no source location" and carries selector and text. When marks are missing, the panel lists the exact changes and asks before your agent adds the plugin. Test builds need an explicit flag, never production.Multi-select and markup: Shift+click or drag to select up to 8 elements, ↑/↓ for parent/child, P to pause animations, a note per element, and a pen on each screenshot. Copy gives the same content as Markdown without ocs; Open in editor opens the file in VS Code, Cursor, Windsurf or WebStorm.
Project and session come from one confirmation card per site (or per path), preselected only from local evidence: a committed
.chrome-use/inspect.jsonnaming the site's domains (single-label wildcards allowed), or the local dev server's folder, with exactly one session in that project. A session can also claim a site withchrome-use inspect link <url>; a claim on a site that belongs to another session waits for your OK in the panel. Choose Only this tab for a one-off target. Different worktrees stay separate; page data only ranks candidates.Delivery is never replayed. Each batch has an id; ocs's stored and wake results are shown separately, and an unconfirmed outcome is queried, not resent. Full context lives in
~/.chrome-use/inspect/ctx/<id>/(owner-only, removed after 7 days); only a tombstone with the batch id and outcome stays, so an id is never sent twice.Boundaries: off by default; nothing stays injected in pages and no debugger bar appears. The input box runs in the extension's own frame, authenticated with a one-time secret, so page scripts cannot read or change what you type; each send re-checks that the box is fully visible. Page content is labelled as untrusted data, and delivery never raises the receiving session's permissions.
Details: Inspect & Ask docs.
Setup: connect to your Chrome
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/home
chrome-use status # relay, profile, extension, and session healthOn macOS/Linux, chrome-use extension install also registers the native host in existing custom data directories of running Chromium-family browsers started with --user-data-dir=<path>. For a browser that is not running or cannot be discovered, use chrome-use extension install --user-data-dir "/path/Chrome Data"; --user-data-dir=<path> is also accepted and the option may be repeated. Every explicit directory must already exist. The command lists written manifests and reads back their name and launcher path. This confirms registration only: reopen the side panel in that Chrome or wait for automatic reconnection. Windows uses HKCU registration and rejects this option. Discovery scans only the current user’s processes. Failures in discovered directories warn and skip that registration; default and explicit directory failures remain errors (retry with --user-data-dir). Successful custom registrations are recorded in ~/.chrome-use/custom-host-dirs.json for status and uninstall even when the browser is stopped. Recording failures warn that uninstall may leave manifests behind.
chrome-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 raw remote-debugging-port alternative (which pops a consent dialog) is described in the real Chrome guide.
extension install is the one-time setup. chrome-use extension connect (alias chrome-use reconnect) re-attaches to an already-installed extension's relay without reinstalling anything. Chrome still shows its "chrome-use started debugging this browser" bar on attached agent tabs; chrome-use extension connect --silent removes it by restarting Chrome once with --silent-debugger-extension-api (tabs and logins are restored; it refuses when several Chrome instances are running). --keep-banner leaves Chrome alone, and without either flag it asks first in an interactive terminal.
All AI sessions in a Chrome profile share one background agent window, with one tab group per session; your own window stays separate. Existing windows with verified agent ownership are reused, including fullscreen windows. Unknown ownership or failed placeholder cleanup refuses instead of creating more windows. User tabs are never moved or deleted to reclaim a window. If you open or drag your own tabs into the agent window, that window becomes yours: agent tabs already there keep working, and new agent tabs go to one fresh agent window that later sessions share.
Your Chrome profile must already have a window open before automation: with no window it stops with profile not open (code profile_not_open), so open a window in that profile first and rerun. If it cannot tell whether a window is open, it stops with profile window unavailable (code profile_window_unavailable); unknown means nothing is created. See Troubleshooting for the first-tab cleanup codes.
A relay timeout means a command missed its deadline. Tab metadata cannot prove
blocked JavaScript or a healthy command channel; screenshots can remain pending
while JavaScript answers. Preserve the tab, inspect status and tab inspect <ref>,
avoid overlapping capture retries, and verify an action's effect before repeating
it. If the probe also fails, inspect its reason before treating the tab as closed.
Multi-profile Chrome: ChooseBrowser rules
If you keep several Chrome profiles (work, personal, a client's), you already know which account each site belongs to, and you tell us with --browser every time. ChooseBrowser is a macOS link router that stores that mapping. When it is installed, chrome-use open <url> without an explicit --browser follows the rule you already wrote for that site, and says so:
$ chrome-use open https://github.com/my-org/repo
· using Chrome profile Profile 14 — a ChooseBrowser rule routes this site there
(github.com|/my-org*). Override with --browser <id|email>, or skip with
--no-choosebrowser.Read-only, and invisible if you do not use it: no rules file means no behaviour change and no message. A rule is binding: chrome-use never opens the site in a different profile. If the rule's profile is not connected, the command fails and names chrome-use connect --browser <profile>. If the session is already bound to another profile, it fails and suggests a new --session or --no-choosebrowser. --browser and config routes still win. The check covers batch steps, MCP tool calls and script steps as well as direct commands. A rule whose profile no longer exists only warns. chrome-use doctor lists each rule and whether its profile is connected. Add --remember to an explicit --browser and chrome-use asks ChooseBrowser to write the rule back, behind its own confirmation dialog.
ChooseBrowser is a macOS link router by the chrome-use author. Set it as your default browser once, and every link you click asks which browser, or which Chrome profile, it should open in.
A row for every profile in Chrome, Edge, Brave, Vivaldi or Chromium; work, personal and client accounts stay apart.
Rules that match a path, not just a domain, so one site can route to two browsers.
⌘1–⌘9opens instantly,⌥↵teaches it once, and it learns which browser you prefer per site.No accounts, no tracking, no analytics. Optional sync through your own iCloud.
Free for 7 days, then US$4.99 one-time for up to 3 Macs. Notarized .dmg; macOS 26 or later. Download · Full guide. chrome-use does not depend on it.
Usage
After cross-site navigation or reconnecting, page reads use the current document. If the page keeps changing while its private reading context is being recreated, the read fails explicitly; observe the page again before acting.
chrome-use mobile serve --bind IP:17345 waits with exponential backoff (1–60 seconds) when that IP is unavailable. It keeps the exact address and reports readiness only after listening succeeds. Update --bind and the phone endpoint after changing networks; it never switches to all interfaces automatically. Other bind errors fail immediately.
Custom comboboxes are scrolled into view instantly and opened with trusted pointer input. pick reports verified: false with a warning when the choice is unconfirmed. Page/container scrolling uses instant movement even with CSS smooth scrolling; an unchanged position returns scrolled: false with a warning.
A wait-condition timeout alone does not diagnose a browser connection failure. wait --text matches a case-sensitive substring: use the actual page wording, and do not wait again after the requested receipt is already visible.
chrome-use skills get core includes the everyday action loop and ordinary form commands. Load core/reading, core/connection, or core/site-adapters only when that task needs the detail; an ordinary click does not require another reference. Use the cheapest state check that answers the next question, and stop once an authoritative page signal confirms the goal.
The core loop: open, read, act, re-read only what changed.
chrome-use open https://example.com # connect to your Chrome and navigate
chrome-use snapshot -i # the start of every interaction: interactive elements with @refs
chrome-use click @e3 --observe # act, and watch for the page's reaction
chrome-use snapshot -i --diff # only what changed since the last snapshotFor scoped, depth-limited, regex-filtered or budgeted snapshots, JSON refs contains only references rendered in the returned excerpt. The session keeps its complete live ref map; narrowing output does not invalidate a previously captured ref. Sparse-page detection still uses the complete map. Valid incremental snapshots return JSON refs only for nodes in the delta. A no-change delta has empty refs; the complete live session map and previously captured refs remain available. A full-tree fallback keeps the normal full-snapshot behavior.
Interactive snapshots add context only to repeated controls with the same role and name when named parent lines do not already distinguish them. Context omits the control’s own name and punctuation, stays within about 100 characters (60 for unnamed controls), and must differ between controls. Unique controls have no context; use a scoped or full snapshot for missing details such as a unique product’s price.
Prefer snapshot -i -c for compact controls, scoped reads for a known region, and --diff only when the last observation leaves a question. Use batch for known action sequences (a step takes its own --observe: batch "fill @e1 Ada" "click @e2 --observe"; pick and hover observe like click), script for bounded observe/decide/act/verify flows, and form fill --map for several fields. Verify the requested result at the end: observed.status: complete means the capture is complete, not the task, so wait for the page's own final signal (wait --text). On a small page (tree at most 4 KB and 60 lines) an observation carries the whole current tree as observed.snapshot plus observed.changes (+/- lines only); larger pages keep delta. observed.text lists visible text lines that changed in any frame (receipts, logs, page counters), never input, textarea, select or editable content, and nothing at all while any password field holds a value (textStatus: redacted); a frame it could not read is listed in textFrames and makes the observation partial. observed.target names the tab and target on every JSON reply. observed.announced holds the text of toasts and alert/status/aria-live regions that appeared while the action ran and the page settled, even ones gone before the reply ("video under review, not saved"). An element screenshot is screenshot <selector> <path> or screenshot <path> --selector <selector>. Add --with-screenshot <path> only when pixels answer a question the tree cannot.
After a successful trusted insertion, contenteditable fill keeps focus on the editor without synthetic change or focusout events. If read-back fails, it reports the failure instead of overwriting the editor DOM. Use the page's own save or commit action when needed.
dblclick uses two trusted pointer clicks and verifies delivery to the target. Covered, disabled, transformed-frame and unmappable cross-origin targets are refused; no synthetic fallback is used. If the target changes after the first click, the second is stopped. JSON includes dispatch: "pointer" and verified; an unverified delivery carries a warning. Inspect the page before retrying an interrupted or unverified action. AGENT_BROWSER_CLICK_MODE=dom is not supported for double-clicks.
When a hidden Monaco module API can be matched to the requested editor, fill uses native input and verifies that exact live model (engine: monaco-native); get value reads the same model without copy or paste. This path does not use the system clipboard. A changed model, lost focus or mismatched readback is an error, with no clipboard retry after input. If no usable API is found before input, the clipboard fallback below remains necessary; this does not make that fallback atomic. Monaco clipboard fallback keeps transaction state in a private closure and removes temporary listeners on completion, setup errors, or a 60-second lease expiry while the document survives. The backup uses independent Blob-backed items because browser-backed ClipboardItems may expire after a write. An empty or unreadable backup is refused before staging. Contents are compared before further input and before restoration; changes or uncertain ownership stop the operation. Restoration is read back and verified. Only formats exposed by the Web Clipboard API can be backed up; native application metadata is not preserved. A restore failure is an error, even if the editor changed. Context loss can prevent restoration, and clipboard comparison/write is not atomic; avoid concurrent clipboard use.
screenshot --annotate draws numbered labels into the captured image in the CLI, without inserting page nodes or styles. JSON annotation boxes remain capture-relative CSS pixels; labels scale to the image resolution. Explicit clips take precedence over full-page and selector captures. Frame references use their owning renderer and top-viewport geometry. Nested out-of-process frames support rotation, skew, reflection and perspective through protocol quads and isolated-world viewport measurements, including scrollbar space. Annotation boxes enclose the projected corners. Collapsed or ill-conditioned transforms, perspective-horizon crossings and missing frame geometry report errors instead of guessed positions. Cropping also happens in the CLI; an off-viewport region is cropped from a full-page capture. Regions outside the page are refused.
The extension relay allows up to 25 seconds for each screenshot capture, below the CLI's 30-second CDP deadline. Native captures after viewport or DPR changes can take longer than ordinary commands. This waits for the same capture; it does not replay it or activate the tab. A timeout still fails and does not cancel Chrome's pending capture, so avoid overlapping capture retries.
The extension relay attaches to nested out-of-process iframe targets recursively, so snapshots can resolve their contents up to the existing three-level expansion limit. Chrome must allow debugger access to each target. If a frame or ref is missing, inspect frames and take a fresh snapshot; do not guess another target.
For Ant Design / rc-picker date ranges, fill the start bound and then the end bound. fill confirms each bound through the component's trusted keyboard or visible confirmation control and reads it back, instead of blurring and refocusing a draft. Focus follows the picker. Invalid, read-only or disabled controls fail without a synthetic overwrite; an unverified popup requires explicit picker interaction. Verify the final range before running the query.
If only the post-action capture fails, observed.refs says what became of the refs: kept-unverified keeps the previous snapshot's refs, but each is confirmed live (same tab, frame, document and element) before a later command uses it and refused otherwise, never re-anchored by role or name (DOM-walk refs are always refused then); dropped means the document may have changed. Either way, run snapshot -i and do not repeat the action.
Semantic find role/text/label/placeholder/alt/title/testid requires exactly one visible match, including locate-only queries. Ambiguity returns up to eight candidates with visible state and selector/context hints; no action is dispatched and input values are omitted. Narrow --name/--exact, or use --within <CSS|@ref> to restrict the query to exactly one container. A scope must belong to the active tab's main document; cross-frame refs and an explicitly selected iframe are refused; use direct frame refs or frame main. find first/last/nth explicitly selects an order and keeps its existing behavior. A plain CSS selector or XPath given to an action (click, fill, type, hover, check, select, drag …) must match exactly one element too: one that matches several is refused with code selector_ambiguous, listing the first five matches with their text and position, and nothing is done. Narrow it, use a @ref, or choose by index with find nth <index> <selector> <action>; AGENT_BROWSER_STRICT_SELECTORS=0 (read when the session's daemon starts) restores first-match for old scripts. Roles and label names use Chrome accessibility data, including aria-labelledby; a semantic query re-resolves on each call. A detached target before dispatch fails safely; uncertain actions are never replayed.
Semantic clicks report the covering element with a bounded tag, id/class and text description. If the hit-test cannot confirm the target, the click fails without guessing a blocker or dispatching input.
The existing chrome_use_find tool in mcp --tools all accepts within with the same unique-scope rules; tool count is unchanged. text for fill/type is passed literally, including --name --observe, rather than parsed as CLI options.
Semantic find retains the existing --observe unsupported warning; use one batch containing the scoped find action and a task-specific get text receipt when both are known. The MCP find tool does not advertise an observe field.
Discover a scope from the page first: find query "Beta account" returns candidate selector anchors; choose the article/container corresponding to that heading, then use find role button click --name Save --exact --within "<returned-selector>". Inspect an ambiguous scope with snapshot -s "<selector>" and narrow it rather than accepting the first container. Unknown semantic-find options and duplicate --within are refused; use find label Email fill -- --name to enter literal flag-looking text. --exact false requests substring matching.
After three identical observed click, dblclick, or press attempts on the same target and screen, with no gap over 60 seconds, observed.noProgress advises checking state or waiting for a task-specific condition. It requires complete, settled evidence with no detected tree, request, resource, or frame activity. The hint does not change action success, prove a write failed, or retry it.
Ordinary CLI/MCP connection preparation preserves this streak only on successful reuse of the same browser connection, target and session, without loading storage state. A new browser, rebind, failed preparation or storage-state load still clears the count.
Scripts retain these hints in advisories (top-level in CLI script --json; data.advisories in the daemon envelope) (at most 20), including nested scripts and runs that later fail. JSON op-list scripts also keep noProgress on the relevant steps entry; text output prints the aggregate advisories once. A failed JS script retains ok:false, return:null, error, logs, and advisories. Nested script daemon-envelope data.ok:false fails the parent script even when transport success is true; dispatch success does not establish program success.
Ordinary CLI --json replies use a success/data/timing envelope; --no-timing (or AGENT_BROWSER_TIMING=0) leaves timing out for a compact reply, and timing.jsonl is still written. batch --json prints an array of {command,success,result,error} entries; script --json prints the bare program result (ok, return, logs, error, advisories, and other program fields). Batch and script CLI output have no top-level timing.
MCP chrome_use_snapshot accepts diff: true for a reread of the same page with the same snapshot options, including the filter. It maps to CLI snapshot --diff. Without a valid baseline it returns the full tree and diffNote; omit diff or set it to false when a complete current tree is required. A diff is an excerpt, so keep its baseline and do not interpret a removed line as a current control.
A click refused by the hit-test guard reports element_occluded with retryable: false, even when the covering element says "timeout" or "connection". No click was dispatched. Read a fresh snapshot and resolve the blocker before trying again; repeating the same command does not resolve an overlay.
JSON command timing includes cdpMs (sum of completed foreground CDP request durations), cdpBusyMs (their interval union within command wall time), and nonCdpMs (wall time minus that union). Concurrent requests can make cdpMs exceed wall time; these are elapsed durations, not CPU measurements. Background tasks do not inherit the recorder; nonCdpMs is not pure daemon processing time. Tool/HTTP calls are not model round trips; only caller traces establish those. See task measurement for task measurement.
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.
For an authorized task, the bundled skill tells the agent to inspect and attempt ordinary CAPTCHAs before handing off: solve-slider for ordinary and rotating Yidun puzzles, screenshot-guided ordered clicks for readable icon challenges, then verify the site's result and continue. Load chrome-use skills get core/captcha. Attempts are bounded; unavailable or ambiguous challenges still need a handoff. This workflow does not guarantee every provider or challenge can be solved. Activate the target before capturing coordinates; a provider success or frozen resend countdown does not establish site acceptance.
Command | Purpose |
| macOS/Linux: register an existing custom Chrome data directory (repeatable; equals form accepted). Running custom directories are also discovered automatically. Windows uses HKCU and rejects this option. |
| Extension relay: AI tabs open in your current window, each session in its own tab group starting with ✦; |
| Connect to your Chrome and navigate. If |
| Read the page; the start of every interaction ( |
| The page as text, plus a bounded |
| Click by text, by snapshot ref, or on a raw viewport coordinate |
|
|
| Structured rows in one call; |
| Move the real pointer onto the element (trusted input); ✓ only when a trusted pointer event landed on the element, and a covered target is refused instead of hovered |
| Read the recorded response body from its originating renderer, including cross-origin frames; unavailable bodies carry |
| Save visual evidence; use it for image challenges and canvas targets, and refs for ordinary controls |
| Attempt a Yidun puzzle (nonzero exit if unsolved); load ordered clicks and verification |
| Ranked, non-acting candidates from a natural-language description |
| What this element supports right now, and perform one of exactly those |
| A tab the click opened ( |
| List tabs; select a created or adopted tab; attach an already-open tab through the extension or direct CDP without navigating it |
| Raise the target before initialization or the liveness probe; |
| Every tab in the connected Chrome profile, across windows, the user's own and other sessions' included: handle, window, active, title, url, owner (this session / |
| Act on (or close) a tab the session does not own, such as the user's own, in place and in the background; only when the user asked. Results carry |
| Handle a native |
| Download with the same cookies as the logged-in browser, without navigating the current tab |
| Mock a response, rewrite an outgoing request, or block one |
| Run a site adapter and get clean JSON from the site's own API |
| Show one adapter's args and domain, or every adapter in a pack with its args and a usage line |
| Close a tab, or end the session and close every tab it created. Both read the tabs back before reporting them closed ( |
| Manage session workers |
| Fill the current login page from Bitwarden; handles TOTP and supported passkey second factors |
| Sign in with a vault passkey in |
| Relay transport, recent debugger timeouts, duplicate installs, extension version skew, and session health. With ab-connect 0.5.50+, host disconnect schedules a first retry after 1s, with repeated failures backing off to 30s. Dead-socket command/event waits fail; old replies are not replayed. Failed sends/lost replies report action_outcome_unknown with retryable: false. Check the page before repeating an interrupted write |
| Explicit recovery for stale ownership records with no tab identity. Requires two valid registry absence reads; reports ownershipDropped and does not claim those Chrome tabs were closed. Cannot be combined with a tab or --all |
Upgrading installed files does not replace an already-running native host. With Chrome open during an upgrade, reload the chrome-use extension at chrome://extensions when agent sessions are idle. Reconnecting a session daemon does not replace the host. Status reports health.nativeHostVersion from the live handshake (null when unavailable), separately from the installed CLI and hostLauncherHealthy; unavailable or mismatched runtime versions produce warnings.
After a refused first open, tab list --all can still inspect the session's bound profile or configured CDP endpoint passively. It creates no driving connection and does not bypass mixed-window guards.
status, extension status, and doctor's relay check read ABExt.state over one diagnostic connection with a total 10-second budget. An error reply falls back to ABExt.inspectTab on that same connection. They send no debugger commands. The debugger summary passively counts answered commands (including non-timeout errors) and timeouts with “in the last 10 min” for a full reporting window, otherwise “since the extension worker started ago” (whole seconds below 120 seconds, such as “45s”; whole minutes otherwise, such as “3 min”). No samples means “not exercised”; an older extension without health data reports that explicitly. Counts use bounded one-second buckets and reset when the service worker restarts. If commands keep failing, reload the chrome-use extension at chrome://extensions or restart Chrome.
Extension 0.5.48 adds a guarded native-tab-group operation used by Thermo. It accepts only an explicitly reviewed list, rechecks every tab, preserves existing/current/pinned/audible/private/agent tabs, keeps windows and profiles separate, journals before mutation, verifies the result, and supports one-shot undo without replaying an uncertain action. Ordinary chrome-use sessions still cannot mutate tabs they do not own.
New native hosts acknowledge diagnostic connections and skip attachAll. A still-running older host performs its usual attachAll once; the diagnostic notice recommends reloading the extension after upgrading to start the new host. Possible duplicate extensions are identified from sidecar identities and concurrent TCP liveness checks with a one-second limit and no WebSocket handshake. Matching account/browser with distinct extension ids does not prove a shared Chrome profile: disable one only if both are installed in the same profile.
Concurrent requests attaching the same tab share one complete attachment. Replies from an old native-host connection are never replayed onto its replacement; reconnect re-announces the current tab state. Automatic detach recovery skips tabs discarded by Chrome. Optional idle debugger release (ab_idle_detach_secs, disabled by default) preserves active tabs in every window and rechecks command activity before releasing a background tab.
JSON health contains transportResponsive, hostDiagnostic, nativeHostVersion, debugger, and extensionHealth (windowMs, workerAgeMs, answered, timedOut, lastTimeout, or null). connectedProfiles and warnings remain available. extension status --json retains relayUp as endpoint presence; status --json uses an extension transport reply. Update an older extension when a newer version is published; if the live extension is newer than this CLI expects, run chrome-use upgrade. Only installType: development identifies a development install. On macOS/Linux, doctor shows one-minute system load and CPU count; load above twice the CPU count warns and adds a hint to relay/CDP timeout errors.
A field that shows your text is not proof the page saved it. fill warns
when the form's Save/Submit was disabled before the edit and still is,
click refuses a disabled control and reports dispatch: dom when it had to
fall back to an untrusted element.click(), and snapshot marks a button
that wraps a checkbox as [toggles=checkbox(checked=true)], because clicking
it flips a setting (in LinkedIn's profile-language dialog, it deletes that
language's profile).
Tab creation, selection, and adoption stay in the background by default, and
no default command raises Chrome or changes the tab you are looking at.
--activate (alias --front) and bringToFront are the explicit exceptions:
they change the visible tab, focus that Chrome window and leave the tab in the
foreground, so agents are told to use them only when you ask. If new-tab initialization
fails, chrome-use retains the target and reports its ID. Use
chrome-use tab select <targetId> --activate, then chrome-use snapshot -i
to verify recovery, keeping the same session and connection endpoint. Do not
repeat tab new or automatically replay an action whose outcome is unknown.
Tab ids and labels survive a reconnect (a relay restart, for example): each
stays bound to the same Chrome tab, and one whose tab is gone is refused rather
than given to another tab. If the tab the agent was driving is gone, commands
on the current tab are refused until it picks one with tab select <ref>,
tab new or --tab <ref>, so nothing runs in a tab it never chose.
Bitwarden login
Open the site's login page, then run chrome-use auth login --bwu. Among
several matching accounts it uses the one that signed in to that host last time,
else the one named exactly the site's host or its sign-in frame's host (App
Store Connect signs in through an idmsa.apple.com iframe); otherwise select
one with --item <id|name>. Add --passkey to use only a
vault passkey in a --launch browser (bitwarden-use 0.9.0+); passwords, TOTP
and custom fields are not read in that mode. On the extension relay, passkeys
are unsupported: passkey-only login fails immediately, while ordinary login
keeps the password/TOTP flow.
Only synced passkeys with signature counter 0 are supported; nonzero counters
need vault write-back and are refused. The temporary WebAuthn authenticator is
removed after the attempt. A temporary page guard blocks ordinary passkey
registration calls; retained native references can bypass it. Unexpected
credential creation or unconfirmed cleanup aborts the command. If WebAuthn
is unavailable, ordinary login keeps the password flow; passkey-only login fails.
A login is reported only when the site took it: after submitting, auth login --bwu waits until the sign-in form is gone from the page and returns
signedIn: true with the evidence, or fails with the sign-in was not confirmed: … and what the page shows instead. It checks that its Enter reached
the page; one that did not is replaced by a click on the form's sign-in button.
Login option | Effect |
| Use the vault account for the current page (bwu 0.7.0+) |
| Select one matching account |
| Sign in with a vault passkey in |
| Fill only; skips TOTP and passkey authenticators; incompatible with |
chrome-use open https://github.com/login
chrome-use auth login --bwu --item github.com
chrome-use --session passkey-demo --launch open https://github.com/login
chrome-use --session passkey-demo --launch auth login --bwu --item github.com --passkey
chrome-use --session passkey-demo --launch snapshot -iCheck the authenticated destination after login. A passkey assertion means Chrome signed the request; it does not establish that the site accepted it.
A command that lands on a sign-in page, or a site adapter that finds the site
signed out (loginRequired: true, or a failed run after HTTP 401), prints
login wall: … and returns loginWall in --json. The first time for a site
it asks whether to sign in from the vault: this time, always for that site, or
never (a prompt in a terminal; loginWall.ask with one command per answer for
an agent, which relays the question to you). chrome-use auth autologin status
shows the decisions and auth autologin off <host> forgets one.
A QR sign-in that stops at a second, security-verification scan (Xiaohongshu
shows a "Security Verification" dialog with a new QR code over the sign-in box,
which still says to confirm on the phone) is reported on every command as
login verification: … (loginVerification in --json, with the QR code as
qrSrc): give that code to the user and do not reload or navigate until they
have scanned it. Auto-login and site login walls wait for it too.
See Login & Credentials.
Agent loop (experimental)
jev run drives a goal end to end: TypeSafe's Jev picks each step's operation
and target from an indexed element table, and a small model writes text only
when a field needs typing. It needs TYPESAFE_API_KEY (or
~/.config/typesafe/key).
chrome-use jev run --goal "find a flight from Zurich to London" --url https://www.google.com/travel/flightsA run reports where its time went — jev_ms (model), act_ms, observe_ms,
fresh_ms — because the answer is usually "the model", not the browser: one
measured run was 64% model round trips, 29% real page load, 6% our own commands.
--terminal-shadow adds one question to the same request, asking whether the
chosen action ends the goal, and records that claim against what the closing
decision then decided (terminal_predicted, terminal_condition_observed,
terminal_confirmed_done). It does not change the completion control flow: the
closing decision is still made and still decides. It exists to measure whether
skipping that decision could ever be safe — on its own, a cheap local check is
not a completion test, since a checkout bounced to /login changes the page
exactly as a success would.
JEV_TRACE=<file> appends one JSON line per decision: the request that was sent,
the candidates the model was shown (id, kind, label, current value, checked
state), its choice, and Jev's raw answers with probabilities. It is off unless
set. It records the goal, the page text and field values, which includes
anything already typed into the form, so treat the file as sensitive. The run report also splits act_ms into
act_read_ms, cmd_click_ms, cmd_press_ms and cmd_insert_ms.
Anti-detection
Session-scoped internal DOM reads require an isolated execution context. If creation, recreation or node resolution cannot keep that context, the command returns isolation_unavailable rather than retrying in the page world. Wait for navigation to settle and observe again; some same-process frame operations may remain unsupported. User-requested evaluation, site adapters, deliberate editor-model access and explicitly supplied contexts keep their existing semantics. The existing AGENT_BROWSER_MAIN_WORLD=1 compatibility override disables this default isolation requirement; it is not a stealth-preserving workaround. This policy is independent of the extension cursor setting.
In extension settings, enabling Stealth mode or disabling Agent cursor removes existing cursor overlays and their page global through current debugger connections. Detached or unreachable tabs show an unconfirmed-cleanup warning in settings; reload affected pages before relying on stealth. Cleanup retries when the agent normally reattaches, without forcing a new connection.
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.click,fill,eval, etc. work without it.
Test results (connected to real Chrome):
Test site | Result |
0% stealth · 0% headless (no override traces at all) | |
all checks OK: | |
all green | |
Webdriver · User-Agent · CDP all clean | |
passed, no interaction |
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.)
Chrome may reduce navigator.languages to its first preferred language for privacy. With AGENT_BROWSER_LOCALE=ja-JP, the stealth benchmark accepts matching page/worker lists of ja-JP or ja-JP,ja; wrong locales, disagreement and missing results still fail. It does not disable Chrome's language reduction. Native GPU availability and site challenge outcomes must be measured on the actual host; other detector failures still make the benchmark fail.
Headed --launch now preserves Chrome's native fingerprint by default, including CPU, GPU, UA Client Hints, screen metrics and iframe functions. Pages, Web Workers and Service Workers see the same underlying browser. Canvas/audio noise and disable-devtool compatibility wrapping remain explicit opt-ins; they can be detected. The extension-connect path also keeps the native fingerprint.
On a display-less Linux server, prefer headed Chrome on a virtual display such as Xvfb. AGENT_BROWSER_ALLOW_HEADLESS=1 is an explicit compatibility fallback: headless Chrome can still be detected, including through workers. stealth status reports the actual launch mode and warns about that limitation; its page probes are not an external bot-detection verdict. Detector results depend on the browser, host, graphics support and network. A passing result does not guarantee Cloudflare clearance or account safety.
The CDP IME path generates composition events, but Chrome may mark compositionend untrusted. Do not interpret a detector's pass as proof that every event is trusted.
Verify it yourself
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
Use independent detectors to evaluate fingerprints. Botcheck complements them with page-artifact and input-sequence checks; its pass does not replace Worker consistency or real-site acceptance.
More in the docs
Site adapters: turn a website into a structured-data CLI (
chrome-use site)Automated testing: re-runnable YAML suites with
chrome-use testAccessibility audits: axe-core via
chrome-use a11yReading a page for fewer bytes:
snapshot -i --diff,--max-bytes,--fromWaiting before a read: settle detection,
--settle-ms,--with-screenshot; a capture that hit the ceiling names the requests still in flight (settle.pendingRequests)Editing inside a field, and pasting with a MIME type:
select-text,paste --format htmlActions beyond a click:
actions,do expand|showMenu|incrementFinding elements and stable refs:
find, XPath, shadow-DOM refsDownloads:
download,download-url,downloadsLocal HTTP API: the versioned
/api/v1surface on each session's stream portNetwork interception:
network routeto mock, rewrite, or blockHuman-like input (humanize):
--humanize off|fast|human, adaptive anti-bot escalationSilent operation: background tabs, never steals your foreground tab
Tuning knobs:
AGENT_BROWSER_*environment variablesStandalone mode (
--launch): a fresh isolated browser,--profile autoto keep your loginTabs, dialogs, and sessions:
tab duplicate|select|adopt|inspect,dialog,session handoffMCP server:
chrome-use mcp,--tools all
The *-use family
Small, composable CLIs that give an AI agent hands on one real thing. Same shape
everywhere: curl … install.sh | sh to install, npx skills add leeguooooo/<name>
to teach your agent, JSON on stdout.
Repo | Gives your agent |
Email: read, search, send, triage across Gmail / QQ / 163 / any IMAP | |
A real iPhone: tap, type, screenshot, pull on-device data | |
WeChat on macOS: send messages, query contacts and history | |
Discord: messages, channels, forums, webhooks (REST-only, Rust) | |
Many logged-in accounts per site: capture, switch, apply sessions | |
Your personal profile, safely: fill signup / KYC / checkout forms | |
Bitwarden / Vaultwarden: headless passkey (FIDO2) login | |
Your ChatGPT subscription as a coding-agent backend, no API key | |
The macOS desktop itself | |
Read-only PixCake probing: snapshot / diff / SQLite inspection |
Remote developer checks
Configure an SSH build host once with git config --local chromeuse.remoteHost <ssh-alias>.
pnpm build:190 and pnpm test:190 run Cargo remotely; pnpm build:native also builds remotely and retrieves a checksum-verified native binary. These commands do not fall back to compiling on your workstation.
The runner snapshots Git-listed working-tree files, including uncommitted edits. Use git add -N <path> for a new source file before running it. Receipts under cli/target/remote-build-receipts/ record the input hash, remote toolchain, command, exit status and artifact checksum. See remote build instructions.
Contributing
AGENTS.md carries the conventions for this codebase: where docs live, how to
build and test, and two hard-won rules about never shipping a silent success and
about measuring performance honestly. Open work is tracked in
issues.
The Git pre-push hook does not sync to ClawHub by default and does not require
pnpm or ClawHub for ordinary pushes. Maintainers can opt in for a single push
with CHROME_USE_CLAWHUB_SYNC=1 git push. Only the value 1 enables the sync;
SKIP_CLAWHUB_SYNC=1 always overrides it. Sync failures warn without blocking
the Git push. Explicit publishing with pnpm run clawhub:sync is unchanged.
These variables control the source checkout's hook, not the installed CLI.
Test the hook with sh scripts/test-pre-push-sandbox.sh on Linux with Docker
and an already available node:24-bookworm image. The runner never pulls an
image or installs packages. It copies only the hook and tests into an
unprivileged container with no network or host mounts, a read-only root,
temporary storage and resource limits. Tests use a fake publisher and verify
actual pushes between temporary local repositories, after checking isolation.
Thanks to everyone who has contributed to chrome-use!
License
Apache-2.0
Built by leeguooooo. Field notes on AI agents, reverse engineering & Cloudflare Workers at blog.leeguoo.com · follow on X @leeguooooo
read --filter uses literal, ASCII-case-insensitive text matching, not a regex. It prefers matching page headings with their descendants, then matching sections. Use read --outline to find a heading. snapshot --filter separately accepts a regex. read --help lists the reading options.
debugger_access_denied lists browser-wide candidate extension names and IDs when available. Verify which extension injects a frame into the blocked tab before disabling it; the list does not prove the cause.
A refused dynamic-form ref now reports code: "stale_ref" with retryable: false. Refresh snapshot -i, then use the current dialog's ref or a unique stable CSS/semantic locator; no input is sent by the refusal. Keep verification enabled and do not replace trusted input with a DOM click. For debugger_access_denied, close a visible autofill menu or save-login bar first; hiding a tab may not dismiss a save-login bar. Candidate-extension lookup is best effort and never replaces the original access denial.
Video publisher sources and cover review: wechat-channels/publish still comes from bundled OpenCLI; it was not removed. OpenCLI 1.8.8 also provides Xiaohongshu image-note publishing, not a video publisher, and its TikTok manifest has no upload/publish command. Use site info to check the installed command and source. The bundled WeChat and Douyin video publishers now default to a chrome-use --cover-mode review preflight that refuses an implicit platform cover before invoking the adapter (code: "cover_selection_required", retryable: false). WeChat --manual true or --draft true prepares the form without automatic publication; --cover-mode keep explicitly accepts the upstream platform-selected cover, without claiming to preserve a cover chosen in a previous form. Douyin's existing --cover <image> remains supported; --cover-mode upload requires it. Unsupported cover arguments and AI/frame modes are refused rather than silently ignored. Added OpenCLI sources keep their own schemas. Local frame extraction is available only on opted-in native adapters; existing-work cover updates remain unimplemented.
Adapter file arguments passed to file.setOn(element) use the same native/relay upload path as ordinary upload. Chrome's explicit Not allowed refusal falls back to relay byte streaming without adding input markers; non-file targets are refused before delivery. Other native errors return action_outcome_unknown rather than replaying an unconfirmed upload. The result reports the live attached count and preserves an empty/cleared-input warning; a delivered file still needs the adapter's preview or application-state verification.
File objects advertise elementRelayUpload: true when element targets share the relay-safe path. Adapters can require this capability before input instead of guessing from the CLI version.
Native adapters with coverFrame metadata support --cover-mode frame:1.5 --cover-video ./clip.mp4 --cover-output ./cover-1.5.png. FFmpeg extracts the explicitly requested local frame before browser interaction, retains a new PNG without overwriting, and hands it to the adapter's normal verified image-upload path. Missing frames fail. Near-black/nearly uniform frames return cover_frame_review_required; review the saved file and choose another timestamp, or explicitly use --allow-dark-cover true with a new output path. This pixel heuristic does not assess cover quality. The adapter must still verify both requested crop previews and the final selection. Douyin applies the extracted image to both ratios. No platform AI or timeline interaction is used; OpenCLI publishers keep their own preflight and do not gain frame support. Custom adapters must explicitly opt in; existing schemas stay unchanged. Existing-work cover updates remain separate and unverified.
Available Tools
12 toolschrome_use_backB
Go back in browser history.
| Name | Required | Description | Default |
|---|---|---|---|
| observe | No | Observe the action's effect (--observe): a page snapshot before and after, the change, and whether the page now waits for a person. Use it when the action should submit, save, pay or send, then confirm the effect with chrome_use_expect. | |
| session | No | Isolated session name (chrome-use --session <name>). Each session gets its own tab group, browser tab and element refs. Omit it unless several agents share ONE MCP server — the session is otherwise derived per agent automatically. When you do share a server with sibling agents, pass a name unique to you on every call, or you will drive their tabs and invalidate their refs. | |
| timeoutMs | No | Kill the underlying chrome-use process if it hasn't responded after this many ms (default 30000). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full disclosure burden, yet it says nothing about whether navigation waits for load, what occurs if there is no prior history entry, or how the result is surfaced. 'Back' implies direction but not side effects or failure modes.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single short sentence, front-loaded with the verb and resource, with zero filler. Nothing in it is wasted or buried.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple no-required-parameter navigation tool with fully documented schema params and no output schema, the description is barely sufficient. It omits edge-case behavior (no history available) and whether the call blocks until navigation completes, which an agent would want to know.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, with observe, session, and timeoutMs each fully documented in the schema including their semantics and warnings. The description adds no parameter meaning beyond that, so the baseline of 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Go back in browser history'), which is unambiguous and inherently distinct from chrome_use_forward. It doesn't explicitly name or contrast with siblings, but the action itself is self-differentiating.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
No guidance on when to use this versus chrome_use_forward, chrome_use_reload, or navigating directly with chrome_use_open. There is also no mention of what happens at the start of history or how this interacts with the observe/expect workflow.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
chrome_use_clickB
Click an element (by CSS selector or @ref) or a raw viewport coordinate. Provide either selector or both x and y.
| Name | Required | Description | Default |
|---|---|---|---|
| x | No | Viewport x coordinate (use with y instead of selector). | |
| y | No | Viewport y coordinate (use with x instead of selector). | |
| force | No | With tabId: act on a tab this session does not own (the user's own, or another session's), in place and in the background (--tab <handle> --force). Only when the user asked you to act on that tab; the result has forced: true and the tab's title and url. | |
| tabId | No | Target tab id (e.g. t2), label, or targetId (--tab). | |
| follow | No | If the click opens a new tab, switch the active tab to it. | |
| newTab | No | Report a tab opened by this click without switching to it. | |
| observe | No | Observe the action's effect (--observe): a page snapshot before and after, the change, and whether the page now waits for a person. Use it when the action should submit, save, pay or send, then confirm the effect with chrome_use_expect. | |
| session | No | Isolated session name (chrome-use --session <name>). Each session gets its own tab group, browser tab and element refs. Omit it unless several agents share ONE MCP server — the session is otherwise derived per agent automatically. When you do share a server with sibling agents, pass a name unique to you on every call, or you will drive their tabs and invalidate their refs. | |
| selector | No | CSS selector or @ref to click. | |
| timeoutMs | No | Kill the underlying chrome-use process if it hasn't responded after this many ms (default 30000). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description must carry the full behavioral burden, and it only says 'click' — nothing about what happens if the selector misses, whether the call blocks or waits, or that refs can go stale. Some behavioral detail (observe, force, follow/newTab, timeout) lives in schema property descriptions, but the description itself discloses almost none of it for a mutation tool.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short sentences with the primary mode of targeting front-loaded and no filler. It is efficient, though the brevity leaves behavior undisclosed rather than being a model of well-structured guidance.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 10-parameter interactive tool with no annotations and no output schema, the description is thin: it never says what a click returns (e.g. whether the page navigated, whether a new tab opened) or how failures surface. The rich schema descriptions compensate for most parameter-level gaps, keeping this at a minimum-viable 3.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already explains every one of the 10 parameters. The description restates the selector vs. x/y split without adding format, precedence rules, or defaults beyond what the schema says. Baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (click) and target types (element via CSS selector or @ref, or raw viewport coordinate), which cleanly separates it from siblings like chrome_use_fill, chrome_use_type and chrome_use_press. It does not explicitly name those siblings, so it stops short of a 5.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The only guidance is the mutual-exclusion rule: 'Provide either `selector` or both `x` and `y`.' That is a call-shape instruction rather than a when-to-use-this-vs-alternatives statement; there is no note about when to prefer @ref over a coordinate, or when to escalate to chrome_use_expect.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
chrome_use_evalA
Run JavaScript in the page's main world (state persists, page handlers fire) and return its result.
| Name | Required | Description | Default |
|---|---|---|---|
| force | No | With tabId: act on a tab this session does not own (the user's own, or another session's), in place and in the background (--tab <handle> --force). Only when the user asked you to act on that tab; the result has forced: true and the tab's title and url. | |
| frame | No | Run in this frame's context instead of the main frame (CSS selector, @ref, URL substring, or frame index). | |
| tabId | No | Target tab id (e.g. t2), label, or targetId (--tab). | |
| script | Yes | JavaScript to evaluate. | |
| session | No | Isolated session name (chrome-use --session <name>). Each session gets its own tab group, browser tab and element refs. Omit it unless several agents share ONE MCP server — the session is otherwise derived per agent automatically. When you do share a server with sibling agents, pass a name unique to you on every call, or you will drive their tabs and invalidate their refs. | |
| timeoutMs | No | Kill the underlying chrome-use process if it hasn't responded after this many ms (default 30000). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the burden and does disclose meaningful behavior: main-world execution, persistent state, and that page handlers will fire. However, it does not disclose that arbitrary JS can mutate page state, how script exceptions are surfaced, or how non-serializable return values are handled.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single front-loaded sentence that states the action, context, key behavioral caveat, and return value with zero filler. Nothing redundant.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 6-parameter tool whose parameters are fully documented in the schema and which has no output schema, the description covers the core action and its main-world semantics. The remaining gap is what 'return its result' means for complex or non-serializable values and errors.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so every parameter including force, frame, tabId, and session is fully documented in structured data. The description adds no parameter-level detail beyond the schema, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Run JavaScript in the page's main world') and adds the execution context and return behavior. The 'main world' qualifier plus 'state persists, page handlers fire' makes it distinguishable from sibling tools like chrome_use_read or chrome_use_snapshot.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The mention that state persists and page handlers fire implicitly signals when to use this over an isolated-world read, but there's no explicit when/when-not guidance or named alternative from the sibling list. An agent must infer the routing decision.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
chrome_use_fillA
Clear and fill a form field (handles CodeMirror/Monaco/ProseMirror/contenteditable in addition to plain inputs).
| Name | Required | Description | Default |
|---|---|---|---|
| force | No | With tabId: act on a tab this session does not own (the user's own, or another session's), in place and in the background (--tab <handle> --force). Only when the user asked you to act on that tab; the result has forced: true and the tab's title and url. | |
| tabId | No | Target tab id (e.g. t2), label, or targetId (--tab). | |
| value | Yes | Text to fill in. | |
| observe | No | Observe the action's effect (--observe): a page snapshot before and after, the change, and whether the page now waits for a person. Use it when the action should submit, save, pay or send, then confirm the effect with chrome_use_expect. | |
| session | No | Isolated session name (chrome-use --session <name>). Each session gets its own tab group, browser tab and element refs. Omit it unless several agents share ONE MCP server — the session is otherwise derived per agent automatically. When you do share a server with sibling agents, pass a name unique to you on every call, or you will drive their tabs and invalidate their refs. | |
| selector | Yes | CSS selector or @ref of the field. | |
| timeoutMs | No | Kill the underlying chrome-use process if it hasn't responded after this many ms (default 30000). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations exist, so the description carries the full burden. It does disclose a meaningful behavioral trait — that it clears existing content before filling — and that it works beyond plain inputs. But it says nothing about failure behavior, whether it triggers submit/change events, or what happens on selector mismatch, which are important for a mutation-on-page tool.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single well-formed sentence that front-loads the core action and appends the differentiator in parentheses. No wasted text.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 7-parameter browser-automation mutation with no annotations and no output schema, the description covers the 'what' but not the 'when/when-not' relative to `chrome_use_type`, nor error/return behavior. The rich schema compensates for parameter documentation, but usage routing is a gap.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so every parameter including `force`, `tabId`, `observe`, and `session` is already well documented. The description adds no additional parameter meaning beyond the schema, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description pairs a specific verb ('Clear and fill') with a specific resource ('form field') and enumerates the editor types it supports (CodeMirror, Monaco, ProseMirror, contenteditable). It is clear what the tool does, though it never explicitly contrasts itself with the sibling `chrome_use_type`, so the fill-vs-type distinction is left to inference.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The mention of rich editors implies the tool should be preferred for CodeMirror/Monaco/ProseMirror fields, which is a useful usage signal. However, there is no explicit statement of when to use this versus `chrome_use_type`, and no guidance on prerequisites or exclusions beyond `force` (documented in the schema, not the description).
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
chrome_use_forwardB
Go forward in browser history.
| Name | Required | Description | Default |
|---|---|---|---|
| observe | No | Observe the action's effect (--observe): a page snapshot before and after, the change, and whether the page now waits for a person. Use it when the action should submit, save, pay or send, then confirm the effect with chrome_use_expect. | |
| session | No | Isolated session name (chrome-use --session <name>). Each session gets its own tab group, browser tab and element refs. Omit it unless several agents share ONE MCP server — the session is otherwise derived per agent automatically. When you do share a server with sibling agents, pass a name unique to you on every call, or you will drive their tabs and invalidate their refs. | |
| timeoutMs | No | Kill the underlying chrome-use process if it hasn't responded after this many ms (default 30000). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full behavioral burden, but it does not disclose what happens if there is no forward history, whether element refs are invalidated, or what state changes occur in the tab. It only restates the basic action.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single front-loaded sentence with no wasted words. It immediately states the action and resource.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple, zero-required-parameter navigation tool with fully documented parameters and no output schema, the description is minimally adequate. However, it omits failure behavior and post-navigation context that would help an agent invoke it correctly without annotations.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the parameters are already fully documented in the schema. The description adds no parameter meaning beyond what the schema provides, which is acceptable given complete schema coverage.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource: 'Go forward in browser history.' This clearly identifies browser-history navigation and is distinguishable from chrome_use_back, though it does not explicitly name the sibling it mirrors.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is implied by the action: use it to move forward in history. There is no explicit guidance on when to use this instead of chrome_use_back, chrome_use_reload, or chrome_use_open, but for a simple navigation tool the implied use case is reasonably clear.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
chrome_use_openA
Navigate to a URL. Omitting url just launches the browser and stays on about:blank (useful before setting up cookies/routes).
| Name | Required | Description | Default |
|---|---|---|---|
| url | No | URL to open. https:// is assumed if no scheme is given. | |
| label | No | Assign a memorable label to the tab (--label). | |
| newTab | No | Open the URL in a new tab instead of navigating the current tab. | |
| observe | No | Observe the action's effect (--observe): a page snapshot before and after, the change, and whether the page now waits for a person. Use it when the action should submit, save, pay or send, then confirm the effect with chrome_use_expect. | |
| session | No | Isolated session name (chrome-use --session <name>). Each session gets its own tab group, browser tab and element refs. Omit it unless several agents share ONE MCP server — the session is otherwise derived per agent automatically. When you do share a server with sibling agents, pass a name unique to you on every call, or you will drive their tabs and invalidate their refs. | |
| reuseTab | No | Adopt an existing tab already on this URL instead of opening a new one. | |
| timeoutMs | No | Kill the underlying chrome-use process if it hasn't responded after this many ms (default 30000). | |
| waitUntil | No | Navigation readiness to wait for (default: load). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations exist, so the description carries the full burden. It does disclose a non-obvious behavior beyond the schema: omitting `url` launches the browser and leaves it on about:blank. It does not state what happens to the current tab versus new tabs, whether navigation failures throw, or that this is a side-effecting action on live browser state.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences, front-loaded with the primary action and followed by the one non-obvious edge case. No filler and nothing buried.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For an 8-parameter, side-effecting browser tool with no annotations and no output schema, the definition is thin. The rich schema compensates for parameter detail, but the agent gets no statement about side effects on existing tabs, failure behavior, or what a successful call yields (page refs, snapshot), which matters before the subsequent click/fill calls.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the description adds real meaning not in the schema: the schema marks `url` as optional without explaining the consequence, and the description fills that gap with the about:blank launch behavior. The remaining seven parameters are left entirely to their schema descriptions.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource: "Navigate to a URL." That is enough to separate it from the interaction siblings (click, fill, type), though it does not explicitly differentiate from navigation-adjacent siblings like chrome_use_reload, chrome_use_forward, or chrome_use_back.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives one concrete usage case (omit `url` to sit on about:blank before setting up cookies/routes), which is genuinely useful routing guidance. It says nothing about when to prefer this over chrome_use_reload or chrome_use_forward for reaching a page, so the alternative-selection guidance is only partial.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
chrome_use_pressC
Press a keyboard key (e.g. Enter, Tab, Control+a).
| Name | Required | Description | Default |
|---|---|---|---|
| key | Yes | Key or chord to press, e.g. "Enter" or "Control+a". | |
| force | No | With tabId: act on a tab this session does not own (the user's own, or another session's), in place and in the background (--tab <handle> --force). Only when the user asked you to act on that tab; the result has forced: true and the tab's title and url. | |
| tabId | No | Target tab id (e.g. t2), label, or targetId (--tab). | |
| holdMs | No | Hold the key down this long (ms) before releasing. | |
| observe | No | Observe the action's effect (--observe): a page snapshot before and after, the change, and whether the page now waits for a person. Use it when the action should submit, save, pay or send, then confirm the effect with chrome_use_expect. | |
| session | No | Isolated session name (chrome-use --session <name>). Each session gets its own tab group, browser tab and element refs. Omit it unless several agents share ONE MCP server — the session is otherwise derived per agent automatically. When you do share a server with sibling agents, pass a name unique to you on every call, or you will drive their tabs and invalidate their refs. | |
| timeoutMs | No | Kill the underlying chrome-use process if it hasn't responded after this many ms (default 30000). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full behavioral burden, but it only says to press a key. It does not disclose whether the active page or focused element receives the key, whether this can submit forms or trigger navigation, what permissions are needed, or how errors manifest. The schema descriptions cover some parameter-specific behavior, but the core action's side effects and preconditions are not explained.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single front-loaded sentence with no wasted words and useful examples. It is appropriately sized for a simple action, though its brevity means some important context is absent rather than redundant.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
This is a browser automation tool with seven parameters, no annotations, and no output schema. The description does not explain focus requirements, whether a prior snapshot is needed, what the result contains, or how observe/force interact with the action. The rich schema helps with parameters, but the description is too thin to fully prepare an agent for correct invocation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already documents all seven parameters in detail, including force, observe, session, and timeoutMs. The description only adds the key example, which duplicates the schema's key description. With the schema doing the heavy lifting, a baseline 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource: 'Press a keyboard key,' with examples such as Enter, Tab, and Control+a. It is clear what the tool does, but it does not differentiate itself from sibling tools like chrome_use_type or chrome_use_fill, which also involve keyboard input.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives examples of keys but does not explain when to use this tool instead of chrome_use_type, chrome_use_fill, or chrome_use_click. It also omits prerequisites such as whether an element must be focused first. Usage is only implied by the tool name and examples.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
chrome_use_readB
Fetch a URL (or the active tab, if url is omitted) as agent-readable text/markdown.
| Name | Required | Description | Default |
|---|---|---|---|
| raw | No | Return raw HTML instead of cleaned markdown. | |
| url | No | URL to read; omit to read the active tab. | |
| llms | No | Read from the site's llms.txt instead of the page itself. | |
| force | No | With tabId: act on a tab this session does not own (the user's own, or another session's), in place and in the background (--tab <handle> --force). Only when the user asked you to act on that tab; the result has forced: true and the tab's title and url. | |
| links | No | Append the page's links as absolute URLs (a `## Links` section; at most 100 unless maxLinks). | |
| tabId | No | Target tab id (e.g. t2), label, or targetId (--tab). | |
| filter | No | Literal, ASCII-case-insensitive filter for page sections, llms links/sections or outline headings. Not a regex; page reads prefer matching headings and their descendants. | |
| outline | No | Return only the heading outline instead of full content. | |
| session | No | Isolated session name (chrome-use --session <name>). Each session gets its own tab group, browser tab and element refs. Omit it unless several agents share ONE MCP server — the session is otherwise derived per agent automatically. When you do share a server with sibling agents, pass a name unique to you on every call, or you will drive their tabs and invalidate their refs. | |
| maxLinks | No | Cap for links (1-1000); implies links. | |
| requireMd | No | Fail instead of falling back to raw text if markdown conversion is unavailable. | |
| timeoutMs | No | Kill the underlying chrome-use process if it hasn't responded after this many ms (default 30000). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full behavioral burden, yet it only says the result is text/markdown. It does not mention read-only semantics, whether fetching a URL navigates or mutates the browser, the markdown-to-raw fallback (only visible in the requireMd schema), session ownership rules, or timeout behavior.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single front-loaded sentence with no filler; the default behavior is stated immediately after the primary action. There is no wasted text to trim.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The schema is rich and fully described, which covers most parameter-level needs, and the description states the return format. But for a 12-parameter tool with no annotations, the description does too little to route the agent among sibling tools or to flag browser-state implications, leaving real gaps.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already documents all 12 parameters in detail, including llms, force, session, and requireMd. The description only restates the url-omitted behavior and adds no parameter meaning beyond the schema, which makes the baseline 3 appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (fetch) and resource (a URL or the active tab) with the output form (agent-readable text/markdown). It is clear what the tool does, but it does not distinguish itself from siblings like chrome_use_open or chrome_use_snapshot, which an agent could easily confuse with this.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The parenthetical 'or the active tab, if url is omitted' gives one usage condition, but there is no guidance on when to prefer this over chrome_use_open, chrome_use_snapshot, or chrome_use_eval, and no exclusions or prerequisites are stated.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
chrome_use_reloadC
Reload the current page.
| Name | Required | Description | Default |
|---|---|---|---|
| observe | No | Observe the action's effect (--observe): a page snapshot before and after, the change, and whether the page now waits for a person. Use it when the action should submit, save, pay or send, then confirm the effect with chrome_use_expect. | |
| session | No | Isolated session name (chrome-use --session <name>). Each session gets its own tab group, browser tab and element refs. Omit it unless several agents share ONE MCP server — the session is otherwise derived per agent automatically. When you do share a server with sibling agents, pass a name unique to you on every call, or you will drive their tabs and invalidate their refs. | |
| timeoutMs | No | Kill the underlying chrome-use process if it hasn't responded after this many ms (default 30000). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full behavioral burden, yet it says nothing about what a reload destroys (unsaved form input, element refs), whether it re-issues network requests, or whether it waits for the load to complete before returning. For a state-mutating navigation tool in this family, that is a significant disclosure gap.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single front-loaded sentence with zero filler. It is efficient, though the terseness contributes to the gaps in usage and behavioral coverage rather than reflecting deliberate restraint.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The tool has no annotations and no output schema, so the description must supply all behavioral context; instead it omits waiting behavior, effect on element refs, and page-state loss. Even for a simple reload action, an agent driving a browser needs to know whether the call returns before or after load completes.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, and the parameters (observe, session, timeoutMs) are documented in detail in the schema, including the chrome-use CLI flags they map to. The description adds nothing beyond that, so the baseline 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (reload) and resource (the current page), which is unambiguous on its own. It does not distinguish itself from navigation siblings such as chrome_use_back or chrome_use_forward, though the verb 'reload' is distinctive enough that confusion is unlikely.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
No guidance is given on when to reload versus using chrome_use_back/forward/open, nor on prerequisites such as a page being open. The agent must infer all usage conditions from the one-line purpose statement.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
chrome_use_snapshotB
Accessibility tree of the current page with @ref handles, for locating elements to click/fill/type.
| Name | Required | Description | Default |
|---|---|---|---|
| diff | No | Only changes since this session last read the same page with the same options (--diff). Without a valid baseline returns the full tree and a diffNote. Omit or false for a full snapshot. Valid deltas include only excerpt refs; unchanged deltas have empty refs while the live session map is kept. | |
| urls | No | Include link/image URLs (-u). | |
| depth | No | Limit tree depth (-d). | |
| force | No | With tabId: act on a tab this session does not own (the user's own, or another session's), in place and in the background (--tab <handle> --force). Only when the user asked you to act on that tab; the result has forced: true and the tab's title and url. | |
| tabId | No | Target tab id (e.g. t2), label, or targetId (--tab). | |
| cursor | No | Include the current cursor position marker (-C). | |
| filter | No | Regex: keep only matching lines + ancestor context (-f). | |
| compact | No | Remove empty structural elements (-c). | |
| session | No | Isolated session name (chrome-use --session <name>). Each session gets its own tab group, browser tab and element refs. Omit it unless several agents share ONE MCP server — the session is otherwise derived per agent automatically. When you do share a server with sibling agents, pass a name unique to you on every call, or you will drive their tabs and invalidate their refs. | |
| selector | No | Scope the snapshot to a CSS selector (-s). | |
| timeoutMs | No | Kill the underlying chrome-use process if it hasn't responded after this many ms (default 30000). | |
| interactive | No | Only interactive elements (-i). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full behavioral burden but only states what the tool returns. It does not disclose read-only behavior, ref lifecycle/staleness, session isolation risks, or side effects around force/tab targeting, leaving significant behavioral traits undocumented in the description.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single front-loaded sentence with no filler. It immediately states the resource, the useful output artifact, and the primary purpose.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 12-parameter browser automation tool with no annotations and no output schema, the description is too sparse. It does not explain the snapshot-to-action workflow, session ownership, diff baseline behavior, or ref validity, even though some of that detail appears only in parameter schemas.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already explains all 12 parameters in detail. The description adds no parameter-level meaning beyond the schema, which is acceptable for high coverage but not value-adding.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names a specific resource (accessibility tree of the current page) and its output element (@ref handles), and ties it to locating elements for click/fill/type. It is clear but does not explicitly distinguish itself from sibling chrome_use_read, which may also retrieve page content.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The phrase 'for locating elements to click/fill/type' implies when to use the tool, but there is no explicit guidance on when not to use it, when to use chrome_use_read instead, or how to choose between full snapshots and diff mode. Usage is implied rather than stated.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
chrome_use_typeC
Type text into an element (or, with no selector, whatever currently has focus).
| Name | Required | Description | Default |
|---|---|---|---|
| text | Yes | Text to type. | |
| clear | No | Clear the field before typing. | |
| enter | No | Press Enter after typing (implies keyEvents) to commit an autocomplete candidate. | |
| force | No | With tabId: act on a tab this session does not own (the user's own, or another session's), in place and in the background (--tab <handle> --force). Only when the user asked you to act on that tab; the result has forced: true and the tab's title and url. | |
| tabId | No | Target tab id (e.g. t2), label, or targetId (--tab). | |
| delayMs | No | Per-key delay in ms. | |
| observe | No | Observe the action's effect (--observe): a page snapshot before and after, the change, and whether the page now waits for a person. Use it when the action should submit, save, pay or send, then confirm the effect with chrome_use_expect. | |
| session | No | Isolated session name (chrome-use --session <name>). Each session gets its own tab group, browser tab and element refs. Omit it unless several agents share ONE MCP server — the session is otherwise derived per agent automatically. When you do share a server with sibling agents, pass a name unique to you on every call, or you will drive their tabs and invalidate their refs. | |
| selector | No | CSS selector or @ref to type into; omit to type into the focused element. | |
| keyEvents | No | Send real per-character keystrokes instead of a bulk insertText (needed for autocomplete widgets). | |
| timeoutMs | No | Kill the underlying chrome-use process if it hasn't responded after this many ms (default 30000). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the entire burden and it does very little: it says nothing about focus requirements, whether existing content is replaced or appended (the `clear` flag exists in the schema but is unaddressed here), what happens if the selector doesn't match, or what the call returns. For a write-like interaction tool with eleven parameters, that is a substantial disclosure gap.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single compact sentence with the primary behavior front-loaded and the edge case tucked into a parenthetical. Nothing is wasted, though the brevity is partly the source of the gaps elsewhere.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Eleven parameters and no output schema mean the description should do more than one sentence of work, especially about what a successful type returns and whether refs are invalidated. The rich per-parameter schema descriptions cover the mechanics, which keeps this at minimum-viable rather than inadequate.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the baseline is 3. The description only adds the omit-selector-equals-focused-element semantics, which is genuinely useful but is also restated in the selector parameter's own description. It adds nothing about `observe`, `session`, or `keyEvents` beyond what the schema already states.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb ('type text') and target ('an element'), and the parenthetical clarifies the fallback to the focused element when no selector is supplied. It is clear on its own, but does not differentiate itself from chrome_use_fill or chrome_use_press, which sit in the same sibling set and could plausibly overlap.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
There is no explicit when-to-use, when-not-to-use, or alternative named. The closest thing is the parenthetical about typing into the focused element, which is a behavioral note rather than routing guidance. An agent must infer for itself whether to reach for this over chrome_use_fill.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
chrome_use_waitA
Wait for an element, a fixed duration, a URL, a load state, a JS condition, text, or a download. Provide exactly one of: selector, ms, url, loadState, expression, text, download.
| Name | Required | Description | Default |
|---|---|---|---|
| ms | No | Wait this many milliseconds. | |
| url | No | Wait for the page URL to match this glob pattern. | |
| gone | No | With selector: wait for it to leave the DOM instead of appearing. | |
| text | No | Wait for this text to appear on the page. | |
| force | No | With tabId: act on a tab this session does not own (the user's own, or another session's), in place and in the background (--tab <handle> --force). Only when the user asked you to act on that tab; the result has forced: true and the tab's title and url. | |
| tabId | No | Target tab id (e.g. t2), label, or targetId (--tab). | |
| hidden | No | With selector: wait for it to become invisible instead of appearing. | |
| session | No | Isolated session name (chrome-use --session <name>). Each session gets its own tab group, browser tab and element refs. Omit it unless several agents share ONE MCP server — the session is otherwise derived per agent automatically. When you do share a server with sibling agents, pass a name unique to you on every call, or you will drive their tabs and invalidate their refs. | |
| download | No | Wait for a download to complete. | |
| selector | No | Wait for this CSS selector/@ref to appear (or disappear, with gone/hidden). | |
| loadState | No | Wait for this load state. | |
| timeoutMs | No | Kill the underlying chrome-use process if it hasn't responded after this many ms (default 30000). | |
| expression | No | Wait for this JS expression to become truthy. | |
| downloadPath | No | With download: save it to this path. | |
| waitTimeoutMs | No | How long to wait before giving up (distinct from the top-level timeoutMs). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations present, the description carries the full disclosure burden and largely doesn't. It does not say whether the call blocks, what it returns on success (element? boolean?), or what happens when the wait times out — throw, return falsy, or partial result. The one-of constraint is the only real behavioral content added.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences, zero filler, and the capability list is front-loaded before the constraint. The constraint sentence is a direct, actionable restatement that an agent needs before calling.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 15-parameter tool with no annotations and no output schema, the description plus the fully documented schema cover the mutually-exclusive mode selection well. What's missing is the return contract — an agent doesn't know if a successful wait yields the element handle, a ref, or a plain boolean, and there is no output schema to fill that gap.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline would be 3; the description earns above that by imposing a mutual-exclusion rule ("exactly one of") that the schema does not encode. It is slightly imprecise, since selector legitimately combines with gone/hidden and download with downloadPath, but the mode-selection semantics are a genuine addition.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names a specific verb (wait) plus the full set of resources it can wait on: element, duration, URL, load state, JS condition, text, download. That enumeration is exhaustive enough that an agent can tell this is the synchronization primitive and is not a duplicate of chrome_use_read, chrome_use_snapshot or chrome_use_eval.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
"Provide exactly one of: selector, ms, url, loadState, expression, text, download" is explicit routing guidance for choosing a wait mode, which is the main ambiguity an agent faces here. It stops short of stating when to prefer this over alternatives like chrome_use_snapshot (e.g. "use snapshot for immediate state, wait for eventual state").
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
12 tool updates
v0.1.0- First observed
chrome_use_back - First observed
chrome_use_click - First observed
chrome_use_eval - First observed
chrome_use_fill - First observed
chrome_use_forward - First observed
chrome_use_open - First observed
chrome_use_press - First observed
chrome_use_read - First observed
chrome_use_reload - First observed
chrome_use_snapshot - First observed
chrome_use_type - First observed
chrome_use_wait
TDQS
Scored across 12 tools
Most tools are clearly distinct: open/read/snapshot/back/forward/reload each have a unique role, and click/fill/type/press target different interaction primitives. The only mild overlap is chrome_use_fill vs chrome_use_type (both insert text; fill clears first and handles rich editors), which descriptions clarify but an agent could still misselect in edge cases.
Every tool uses the identical chrome_use_<verb> pattern with short, action-oriented verbs (back, open, read, click, fill, type, press, eval, wait, forward, reload). No mixing of camelCase, casing, or verb styles across the set.
12 tools is squarely within the well-scoped range and each tool maps to a real browser-automation need (navigation, reading, element location, input, waiting). There is no obvious filler; the surface is compact yet covers the core loop of navigate-snapshot-act-wait.
The core automation lifecycle is covered: navigation, content reading, accessibility snapshotting, clicking/filling/typing/pressing, JS eval, and rich wait conditions. Gaps remain for tab/window management (list/new/close tabs), scrolling, dropdown selection, and screenshots, though most can be worked around via chrome_use_eval.
Maintenance
Related MCP Connectors
Browser MCP for logged-in tasks. Uses your Chrome — credentials stay local. Zero-token replay.
Use your Mac, Windows or Linux computer from ChatGPT, Claude or Codex: files, commands, documents.
Agent social posting via your logged-in Chrome. Remote MCP + OAuth. Not clawpost.dev.
Connect AI agents to your own Chrome with scoped access, approvals, and verified task results.
Related MCP Servers
- FlicenseNot gradedqualityCmaintenanceA Chrome browser automation MCP server. Connect Claude (or any MCP client) to a real Chrome session — using your existing profiles with their cookies, saved passwords, and history.3-
- AlicenseNot gradedqualityAmaintenanceA local MCP server that lets AI coding assistants drive the user's own already-signed-in Chrome, so agents can read logged-in pages, click, fill forms, navigate, screenshot, inspect network traffic and storage, and run multi-step browser workflows without a separate headless browser or remote debugging port. All communication stays on the user's machine and agent-opened tabs are grouped so they never steal focus.1 npmISC
- AlicenseNot gradedqualityAmaintenanceA local MCP server that lets AI coding tools drive the user's actual, already-logged-in Chrome browser — snapshotting pages, clicking, typing, navigating, reading content, taking screenshots, and inspecting cookies, network traffic, and console output. Browser automation happens through a Chrome extension using Native Messaging, so no remote-debugging port is exposed and all communication stays on the local machine.1 npmISC
- AlicenseNot gradedqualityAmaintenanceA local MCP server that lets AI coding tools drive the real Chrome browser you already have open, so agents can read logged-in pages, click, fill forms, take screenshots, and inspect tabs, cookies, and network traffic. All communication stays on your machine, with no debugging port or manual cookie copying required.1 npmISC