chrome-devtools-remote
Original:🇺🇸 English
Translated
Drive a remote chrome-devtools-mcp server (typically on a tailnet) over HTTPS using the chrome-devtools CLI. Use this when the user wants to navigate, screenshot, inspect, or evaluate JavaScript on a browser running on another host (e.g. a Tailscale-connected Mac mini or a CI runner) — and you don't have a local Chrome to control. Examples of triggers ("open <url> on the lab mac", "take a screenshot of the browser on host X", "evaluate this on the remote browser").
10installs
Added on
NPX Install
npx skill4agent add dzianisv/chrome-devtools-mcp chrome-devtools-remoteTags
Translated version includes tags in frontmatterSKILL.md Content
View Translation Comparison →chrome-devtools-remote
You are operating the CLI in remote mode against a server that the user has running on another host. The remote server owns the browser; your job is to drive it.
chrome-devtoolschrome-devtools-mcpWhen to use this skill
Trigger on any request that:
- Names a remote machine ("on the lab mac", "on host X", "on my tailnet box") and asks you to do something a browser would do
- Provides a HTTPS URL (typically ending in
chrome-devtools-mcp) and asks for an interactive browser action/mcp - Mentions environment variables or
CHROME_DEVTOOLS_MCP_REMOTE_URLCHROME_DEVTOOLS_MCP_REMOTE_INSECURE
If the user wants to drive a local browser, use the regular CLI (without ) or the MCP tools instead.
chrome-devtools--remotemcp__chrome-devtools__*Install (on the local box, once)
The client CLI ships in the same npm package as the server. Install globally on the machine where the agent runs — not on the remote host:
chrome-devtoolsbash
npm install -g @vibebrowser/chrome-devtools-mcp
chrome-devtools --version # should print 0.26.6 or newerYou do not install anything on the remote host — that host is whoever already serves and is set up out-of-band.
https://.../mcpTroubleshooting:
- — npm's global bin isn't on
command not found: chrome-devtools. AddPATHto$(npm config get prefix)/bin, or on macOS Homebrew addPATHto your shell rc.eval "$(brew shellenv)" - on first run — known bundling gap (issue dzianisv/chrome-devtools-mcp#17). Workaround:
Cannot find package 'pkce-challenge'.cd "$(npm root -g)/@vibebrowser/chrome-devtools-mcp" && npm install pkce-challenge --no-save
Connect
Configure the endpoint once per shell session and verify connectivity before doing anything else.
bash
export CHROME_DEVTOOLS_MCP_REMOTE_URL="https://lab.tailnet.ts.net/mcp"
chrome-devtools status --remote "$CHROME_DEVTOOLS_MCP_REMOTE_URL"A healthy response prints plus a JSON body. Anything else is a hard stop — surface the error to the user instead of retrying.
status=ok http=200If the URL is unset, ask the user once for the endpoint. Conventional shape: (the path is required — the bare host returns a 404).
https://<host>/mcp/mcpConnection-time flags:
| Situation | What to pass |
|---|---|
| Self-signed cert (common on tailnets without Tailscale-issued certs) | |
| Bearer-token gateway | |
Custom static header (e.g. | |
Endpoint behind Tailscale and | |
Once is green, every subsequent call reuses the same server-side tab via a sticky session id cached at .
statuschrome-devtools <tool> ... --remote "$URL"~/.cache/chrome-devtools-mcp/remote/<hash>.sessionSession model — read this before chaining commands
Each CLI invocation reuses a sticky session id stored under . This means:
~/.cache/chrome-devtools-mcp/remote/<hash>.session- →
navigate_page→take_snapshot→clickall hit the same server-side tab. You can chain them as separate CLI calls and assume continuity.take_screenshot - If the server restarts between calls, the next call transparently re-initializes against a fresh session. Tab state on the server is lost — re-navigate before assuming anything.
- To explicitly end the server-side session and free its browser context, run .
chrome-devtools stop --remote "$CHROME_DEVTOOLS_MCP_REMOTE_URL"
Common operations
All commands accept to return structured output you can pipe into .
--output-format jsonjqbash
# Open a page
chrome-devtools navigate_page "https://example.com" --remote "$CHROME_DEVTOOLS_MCP_REMOTE_URL"
# Get a structured a11y snapshot (use for finding clickable uids)
chrome-devtools take_snapshot --remote "$CHROME_DEVTOOLS_MCP_REMOTE_URL" --output-format json
# Click an element by uid from the snapshot
chrome-devtools click "$UID" --remote "$CHROME_DEVTOOLS_MCP_REMOTE_URL"
# Fill an input
chrome-devtools fill "$UID" "value" --remote "$CHROME_DEVTOOLS_MCP_REMOTE_URL"
# Take a screenshot (saved to /tmp/<uuid>.png locally)
chrome-devtools take_screenshot --remote "$CHROME_DEVTOOLS_MCP_REMOTE_URL"
# Evaluate JS in the page — return value must be JSON-serializable
chrome-devtools evaluate_script '() => document.title' --remote "$CHROME_DEVTOOLS_MCP_REMOTE_URL"
# Read console messages from the page
chrome-devtools list_console_messages --remote "$CHROME_DEVTOOLS_MCP_REMOTE_URL"
# List network requests since page load
chrome-devtools list_network_requests --remote "$CHROME_DEVTOOLS_MCP_REMOTE_URL"Recipes
Smoke-check a deployed web app
bash
URL="$CHROME_DEVTOOLS_MCP_REMOTE_URL"
chrome-devtools navigate_page "https://app.example.com" --remote "$URL"
chrome-devtools evaluate_script '() => ({title: document.title, ready: document.readyState})' --remote "$URL"
chrome-devtools list_console_messages --remote "$URL" --output-format json
chrome-devtools take_screenshot --remote "$URL"If contains any entries, surface them — they are usually the root cause of "the page looks broken" reports.
console_messageslevel: "error"Drive a login form
bash
chrome-devtools navigate_page "https://app.example.com/login" --remote "$URL"
chrome-devtools take_snapshot --remote "$URL" --output-format json > /tmp/snap.json
# Find the uid of the email input + password input + submit button from /tmp/snap.json
chrome-devtools fill "<email-uid>" "$LOGIN_EMAIL" --remote "$URL"
chrome-devtools fill "<password-uid>" "$LOGIN_PASSWORD" --remote "$URL"
chrome-devtools click "<submit-uid>" --remote "$URL"Capture a CrUX-style trace
bash
chrome-devtools performance_start_trace --remote "$URL"
chrome-devtools navigate_page "https://app.example.com" --remote "$URL"
chrome-devtools performance_stop_trace --remote "$URL" --output-format jsonOutput discipline
- Always print the URL of the page you navigated to so the user knows which tab they're looking at.
- For screenshots, print the path of the saved file () — the CLI already writes that line on stdout.
Saved to /tmp/<uuid>.png. - For , prefer
evaluate_scriptand forward only the relevant field instead of dumping the whole structuredContent envelope.--output-format json - If the user asks "what's on the page", prefer over
take_snapshot— the snapshot is text and cheaper to reason over.take_screenshot
Failure modes
| Symptom | Cause | Fix |
|---|---|---|
| DNS, Tailscale offline, or wrong URL | |
| Server restarted; sticky id was stale. Retried once internally — if you see this it means the retry also 404'd | |
TLS verify error ( | Server uses a self-signed cert (no Tailscale-issued cert) | Add |
| Local cache directory was wiped mid-session | First call after the wipe will mint a fresh session; just retry |
| Hangs on first call after a long idle | Server idle reaper closed the session | Same fix as the 404 row — |
Don'ts
- Don't loop to "wait for the page to load" — use
navigate_pagewith a text selector instead.wait_for - Don't for every step in a chain — the user almost always wants one final screenshot, not five intermediate ones.
take_screenshot - Don't pass for a hosted endpoint with a real cert. It silently disables TLS for the whole CLI process.
--insecure - Don't try to a server with
start— that subcommand only manages local daemons.--remote