Control the Chrome the user already has open and logged in through the Browser Relay CLI, without launching a separate automation browser or taking over the foreground tab. Use when an agent needs to work with existing sessions, cookies, extensions, SSO or intranet pages, or a browser on another machine. Prefer the CLI; use HTTP only for code, tests, or integrations. Skip static pages and pure REST APIs.
npx skills add https://github.com/reliefeai/browser-relay --skill browser-relay
Work alongside the user in the Chrome they already use. Browser Relay lets the
agent operate existing tabs through a Skill + CLI, including background tabs,
without launching a blank browser profile or repeatedly pulling Chrome to the
foreground. Remote Relay can reach the user's explicitly enabled browser on
another machine.
Use Browser Relay when you need to:
[link], [button], [input] markersWhen NOT to use:
Check setup before the first browser action:
browser-relay doctor
If browser-relay is not installed, tell the user to install the open-source
CLI, then rerun the check:
npm install -g @linsoai/browser-relay
browser-relay path
The user must load the directory printed by browser-relay path from
chrome://extensions and explicitly enable the extension. Do not install it,
enable Remote Relay, or invent a Remote Device ID without the user. A ready
setup has the relay server running, the extension connected, and at least one
regular Chrome tab attached.
Relay URL: http://127.0.0.1:18795
WebSocket: ws://127.0.0.1:18795/extension
No authentication needed — the relay only accepts connections from localhost.
Remote mode ("Remote Relay") lets an agent drive a browser on another machine.
The user opens the extension Options, turns on Remote Relay, and copies the
generated remote-device-id — a secret capability like br-xxx. Only then use
remote flags (the hosted hub relay.linso.ai is the default host):
browser-relay tabs --remote-device-id br-xxx
browser-relay remote add mymac br-xxx # or save an alias once…
browser-relay tabs --remote mymac # …and use the short name (remote ls / rm to manage)
Never invent or guess a remote-device-id; it is a secret generated by the
extension. The local relay stays bound to localhost — remote mode connects the
browser out to the hub and does not need it.
When shell access is available, use the browser-relay CLI for browser
interaction. Do not hand-write curl for normal agent browsing tasks. The CLI
avoids JSON escaping, keeps commands short, and prints compact output by
default.
Use the HTTP API directly only when you are writing code, tests, scripts, or an
integration against Browser Relay, or when the CLI is unavailable. Use --json
only when you need the full API response.
browser-relay tabs
browser-relay console --tab <tabId> --limit 50
browser-relay network --tab <tabId> --type response --status 500 --limit 20
browser-relay snapshot --tab <tabId> --max-length 20000
browser-relay wait 'button[type=submit]' --state visible --timeout 10000 --tab <tabId>
browser-relay click 'button[type=submit]' --tab <tabId>
browser-relay type 'hello world' --selector 'input[name=q]' --clear --submit --tab <tabId>
browser-relay key Control+L --tab <tabId>
browser-relay scroll down --amount 1000 --tab <tabId>
browser-relay download-start https://example.com/file.pdf --filename files/file.pdf
browser-relay downloads --limit 20
browser-relay screenshot /tmp/page.png --full-page --tab <tabId>
browser-relay eval 'document.title' --tab <tabId>
For maintenance, upgrade Browser Relay with:
browser-relay update
Then refresh this Skill for the active agent (for example, codex or
claude-code) and let Browser Relay verify the installed copy:
browser-relay skill install --agent codex
For long text or JavaScript, avoid shell escaping with stdin:
printf '%s' "$TEXT" | browser-relay type --selector textarea --stdin --tab <tabId>
browser-relay eval --stdin --tab <tabId> < script.js
The HTTP API below is for code, tests, custom tools, and low-level debugging.
For interactive agent work, prefer the CLI workflow above.
Errors are structured across HTTP, CLI --json, and MCP tool errors:
{ "ok": false, "code": "invalid_request", "error": "url is required", "message": "url is required", "status": 400, "retryable": false }
Agents should branch on code rather than matching localized/free-form error
text. retryable: true means a reconnect/retry is reasonable.
List all attached browser tabs.
GET http://127.0.0.1:18795/api/tabs
Returns: { ok: true, tabs: [{ id, title, url }] }
Navigate a tab to a URL.
POST http://127.0.0.1:18795/api/navigate
Header: Content-Type: application/json
Body: { "url": "https://example.com", "tabId?": "optional-tab-id" }
Read captured console, page error, and browser log entries.
GET http://127.0.0.1:18795/api/console?tabId=<id>&limit=100&level=error&clear=false
POST http://127.0.0.1:18795/api/console/clear
Body: { "tabId?": "...", "level?": "error" }
Use this after actions that may trigger frontend errors or warnings.
Read captured request/response/finished/failed network events. Sensitive
headers such as Authorization, Cookie, Proxy-Authorization, and
Set-Cookie are redacted; request bodies are not captured.
GET http://127.0.0.1:18795/api/network?tabId=<id>&type=response&status=500&limit=100&clear=false
POST http://127.0.0.1:18795/api/network/clear
Body: { "tabId?": "...", "type?": "request|response|finished|failed", "method?": "GET", "status?": 500, "requestId?": "...", "url?": "substring" }
Use this after actions that fail silently, after form submits, or when console
errors imply an API request failed.
Get a text representation of the current page (interactive elements annotated).
GET http://127.0.0.1:18795/api/snapshot?tabId=<id>&format=text&maxLength=100000
Format can be "text" (annotated DOM) or "html" (raw HTML).
Wait for a CSS selector to be attached to the DOM or become visible. Prefer
this over fixed sleeps after navigation or actions.
POST http://127.0.0.1:18795/api/wait
Body: {
"selector": "button.submit",
"state?": "attached|visible",
"timeoutMs?": 5000,
"pollMs?": 100,
"tabId?": "..."
}
state defaults to visible. timeoutMs accepts 1–20000 and pollMs
accepts 50–1000. A timeout returns code: "wait_timeout" with
retryable: true; a tab closing or the extension disconnecting fails
immediately instead of waiting for the timeout.
Click an element by CSS selector. Scrolls into view first, uses real mouse events.
POST http://127.0.0.1:18795/api/click
Body: { "selector": "button.submit", "tabId?": "...", "doubleClick?": false }
Type text into an input field. Optionally clear and submit.
POST http://127.0.0.1:18795/api/type
Body: {
"text": "hello world",
"selector?": "input[name='q']",
"clear?": true,
"submit?": true,
"tabId?": "..."
}
Scroll the page.
POST http://127.0.0.1:18795/api/scroll
Body: { "direction": "down|up|top|bottom", "amount?": 800, "tabId?": "..." }
Press a key or keyboard shortcut using real keyboard events.
POST http://127.0.0.1:18795/api/key
Body: { "key?": "Enter", "combo?": "Control+L", "tabId?": "..." }
Use combo for shortcuts (Control+L, Meta+K, Shift+Tab) and key
for single keys (Enter, Escape, ArrowDown, a).
Capture a PNG screenshot (base64).
POST/GET http://127.0.0.1:18795/api/screenshot?tabId=<id>&fullPage=true
Full-page captures use layout metrics plus a clipped screenshot when possible,
then fall back to Chrome's captureBeyondViewport path. Returns:
{ ok: true, data: "base64...", format: "png", fullPage, strategy, width?, height?, bytes }
Evaluate arbitrary JavaScript in the page. The escape hatch.
POST http://127.0.0.1:18795/api/eval
Body: { "expression": "document.querySelector('h1').innerText", "tabId?": "..." }
Get the URL of an image/media/link element.
POST http://127.0.0.1:18795/api/download
Body: { "selector": "img.profile-pic", "tabId?": "..." }
Start a real Chrome download from a URL using the user's browser profile.
POST http://127.0.0.1:18795/api/download/start
Body: {
"url": "https://example.com/file.pdf",
"filename?": "files/file.pdf",
"saveAs?": false,
"conflictAction?": "uniquify|overwrite|prompt"
}
Returns: { ok: true, downloadId, id, options }
List Chrome downloads plus recent Browser Relay download events.
GET http://127.0.0.1:18795/api/downloads?limit=20&state=complete
POST http://127.0.0.1:18795/api/downloads/clear
Use this after browser_download_start to verify completion or diagnose interruptions.
Real downloads require the extension's downloads permission. If Browser Relay
was already loaded in Chrome before this capability was installed, reload the
unpacked extension in chrome://extensions.
When asked to do something with a web page:
browser-relay tabs first — discover available tabs and their URLsbrowser-relay navigate if needed — go to the target pagebrowser-relay snapshot — understand the page structurebrowser-relay click, browser-relay type, browser-relay key, browser-relay scroll) one at a timebrowser-relay wait for the next expected element after navigation or an action; do not guess with fixed sleepsbrowser-relay console if the page behaves unexpectedly or after risky actionsbrowser-relay network if a request fails, hangs, or the UI changes without visible errors10. Use browser-relay download-start and browser-relay downloads for real file downloads
11. Screenshot if visual confirmation is needed
# 1. List tabs
browser-relay tabs
# t_A7k2Pm9QxL Google https://google.com
# 2. Take snapshot to see the page
browser-relay snapshot --tab t_A7k2Pm9QxL
# [input type=text name=q placeholder="Search Google"]
# [button "Google Search"]
# 3. Type into the search box
browser-relay type 'browser relay' --selector 'input[name=q]' --submit --tab t_A7k2Pm9QxL
# 4. Wait for results instead of sleeping
browser-relay wait 'a[href*="github.com"]' --state visible --timeout 10000 --tab t_A7k2Pm9QxL
# 5. New snapshot after navigation
browser-relay snapshot --tab t_A7k2Pm9QxL
# 6. Click a result
browser-relay click 'a[href*="github.com"]' --tab t_A7k2Pm9QxL
Add to your MCP config (~/.claude/mcp.json or equivalent):
{
"mcpServers": {
"browser": {
"command": "browser-relay-mcp",
"env": {
"BROWSER_RELAY_URL": "http://127.0.0.1:18795"
}
}
}
}
| Error | Meaning | Fix |
|-------|---------|-----|
| Extension not connected | Relay server is running but no browser extension connected | Check that Chrome is running with the Browser Relay extension installed |
| No attached tabs | Extension connected but no tab is attached | The extension auto-attaches all regular tabs. Make sure at least one non-chrome:// tab is open |
| Element not found: selector | The CSS selector did not match anything on the page | Try a different selector, or take a snapshot first to inspect the DOM |
| wait_timeout | The selector did not reach the requested attached/visible state before timeout | Re-snapshot the page, check the selector, or retry when the page is expected to load more slowly |
| Session with given id not found (-32001) | The relay holds stale session state (e.g. after an extension reload) | Run browser-relay fix — restarts the relay and clears stale sessions; the extension reconnects automatically |
curl http://127.0.0.1:18795/
# → OK
curl http://127.0.0.1:18795/api/debug
# → { "version": "<package-version>", "connected": true/false, "tabCount": N }
Execute Python code in a safe sandboxed environment via [inference.sh](https://inference.sh). Pre-installed: NumPy, Pandas, Matplotlib, requests, BeautifulSoup, Selenium, Playwright, MoviePy, Pillow, OpenCV, trimesh, and 100+ more libraries. Use for: data processing, web scraping, image manipulation, video creation, 3D model processing, PDF generation, API calls, automation scripts. Triggers: python, execute code, run script, web scraping, data analysis, image processing, video editing, 3D models, automation, pandas, matplotlib
Execute Python code in a safe sandboxed environment via [inference.sh](https://inference.sh). Pre-installed: NumPy, Pandas, Matplotlib, requests, BeautifulSoup, Selenium, Playwright, MoviePy, Pillow, OpenCV, trimesh, and 100+ more libraries. Use for: data processing, web scraping, image manipulation, video creation, 3D model processing, PDF generation, API calls, automation scripts. Triggers: python, execute code, run script, web scraping, data analysis, image processing, video editing, 3D models, automation, pandas, matplotlib
Upgrade browser versions (Chrome or Firefox) in the Flutter Web Engine and/or Framework tests. Use when asked to roll or upgrade Chrome or Firefox to a newer version.
Migrate PowerToys module UI tests from the legacy WinAppDriver/Selenium harness (Microsoft.PowerToys.UITest) to the new winappcli-based harness (Microsoft.PowerToys.UITest.Next). Use when asked to port/convert/rewrite/modernize a module's UI tests to the .Next framework, create a new [Module].UITests.Next project alongside existing legacy tests, or stand up brand-new winappcli UI tests for a module that has none by reading its human test sign-off markdown. Covers the API mapping (By/Element/Session/UITestBase, KeyboardHelper/MouseHelper/ClipboardHelper), project/csproj scaffolding, naming rules, common PowerToys test recipes (toggle a module, read an activation shortcut, fire a global hotkey, inspect the clipboard, discover overlay/editor windows), build/run validation, and CI-stability hardening for fewer CI iterations. Keywords: UI test, UITests, UITestAutomation.Next, winappcli, WinAppDriver, Selenium, migrate, port, modernize, .Next, MSTest, CI stability, flaky test, stabilize on CI.
> Documentation reference for writing Python code using the browser-use open-source library. Use this skill whenever the user needs help with Agent, Browser, or Tools configuration, is writing code that imports from browser_use, asks about @sandbox deployment, supported LLM models, Actor API, custom tools, lifecycle hooks, MCP server setup, or monitoring/observability with Laminar or OpenLIT. Also trigger for questions about browser-use installation, prompting strategies, or sensitive data handling. Do NOT use this for Cloud API/SDK usage or pricing — use the cloud skill instead. Do NOT use this for directly automating a browser via CLI commands — use the browser-use skill instead.
Run agent-browser + Chrome inside Vercel Sandbox microVMs for browser automation from any Vercel-deployed app. Use when the user needs browser automation in a Vercel app (Next.js, SvelteKit, Nuxt, Remix, Astro, etc.), wants to run headless Chrome without binary size limits, needs persistent browser sessions across commands, or wants ephemeral isolated browser environments. Triggers include "Vercel Sandbox browser", "microVM Chrome", "agent-browser in sandbox", "browser automation on Vercel", or any task requiring Chrome in a Vercel Sandbox.
Use the browse CLI for Browserbase browser automation, Browserbase cloud APIs, Browserbase Functions, templates, web fetch/search, diagnostics, and Browse.sh skill discovery/installation. Use when the user asks to navigate pages, inspect browser state, run local or remote browser sessions, manage Browserbase resources, call Browserbase Functions, browse or scaffold Browserbase templates, fetch or search web content, diagnose browse setup, find or install a skill for a website task, discover site-specific Browse.sh skills, or install/refresh this browse skill.
Development workflows for the playwright-cli repository. Use when the user asks about rolling dependencies, releasing, or other repo maintenance tasks.
Take reliefeai/browser-relay from the repository into ~/.claude/skills for personal
use, or into .claude/skills inside a project.
The agent identifies a skill by the name field in its header. Two skills with the
same name cannot sit side by side — one of them will be ignored.
The instructions reference npm.
Without those the skill loads but fails at the first command.