Control a remote browser through Claw Relay using the CLI client. Use when you need to navigate authenticated websites, click buttons, fill forms, take scree...
---
name: claw-relay-openclaw
description: Control a remote browser through Claw Relay using the CLI client. Use when you need to navigate authenticated websites, click buttons, fill forms, take screenshots, or read page content on a user's real browser — and your platform doesn't support MCP. Triggers on remote browser control, authenticated browsing, real browser, cookie-based access, browser relay.
---
# Claw Relay — OpenClaw CLI Client
> **If your platform supports MCP (Copilot CLI, Claude Desktop, Gemini CLI), use `skills/browser/SKILL.md` instead.** This skill is for OpenClaw, nanobot, ZeroClaw, and other agents that call tools via `exec`.
## ⚠️ IMPORTANT: No MCP Required
**Do NOT write an MCP server, bridge, or wrapper.** You already have everything you need:
- The `exec` tool (built into OpenClaw)
- The `relay-client.cjs` script (in this folder)
That's it. One `exec` call per browser action. No MCP, no bridge, no custom server.
## Setup
Set environment variables (or pass as flags):
```bash
export CLAW_RELAY_URL="wss://relay.clawrelay.dev/"
export CLAW_RELAY_TOKEN="your-token"
export CLAW_RELAY_AGENT="your-agent-id"
```
The client script is at `skills/openclaw/relay-client.cjs` in the claw-relay repo.
## Usage
```bash
node relay-client.cjs [--url URL] [--token TOKEN] [--agent-id ID] ACTION [ARGS...]
```
Flags override env vars. Every invocation connects, authenticates, performs ONE action, prints JSON, and exits.
## Actions
| Action | Args | Description |
|--------|------|-------------|
| `navigate` | `<url>` | Navigate to URL |
| `snapshot` | — | Get accessibility tree with element refs |
| `screenshot` | `[filepath]` | Take screenshot; saves to filepath if given |
| `click` | `<ref>` | Click element by ref |
| `fill` | `<ref> <text>` | Replace input content with text |
| `type` | `<ref> <text>` | Append text to input |
| `press` | `<key>` | Press keyboard key (Enter, Tab, Escape, etc.) |
| `hover` | `<ref>` | Hover over element |
| `select` | `<ref> <values...>` | Select dropdown option(s) |
| `evaluate` | `<js>` | Run JavaScript in the page |
| `close` | — | Close the browser tab |
## Workflow
```
navigate → snapshot → find ref → act → snapshot → verify
```
1. **Navigate** to the target URL
2. **Snapshot** to read the page and get element refs (e.g. `e3`, `e7`)
3. **Act** — click, fill, type, press using refs from the snapshot
4. **Verify** — snapshot again to confirm the page changed
### Example: Search GitHub
```bash
# Step 1: Navigate
node relay-client.cjs navigate https://github.com
# Step 2: Snapshot to find the search input ref
node relay-client.cjs snapshot
# Step 3: Fill the search box (say ref is e3)
node relay-client.cjs fill e3 claw-relay
# Step 4: Press Enter
node relay-client.cjs press Enter
# Step 5: Snapshot to read results
node relay-client.cjs snapshot
```
### Example: Click a Button
```bash
# Find the button
node relay-client.cjs snapshot
# Output shows button at ref e7
# Click it
node relay-client.cjs click e7
# Verify
node relay-client.cjs snapshot
```
### Example: Take a Screenshot
```bash
node relay-client.cjs screenshot /tmp/page.png
# Output: {"ok":true,"path":"/tmp/page.png","bytes":...}
```
### Example: Run JavaScript
```bash
node relay-client.cjs evaluate "document.title"
```
## OpenClaw exec Integration
Use the `exec` tool directly. Each call connects, authenticates, performs one action, and exits:
```bash
exec: node /path/to/relay-client.cjs snapshot
exec: node /path/to/relay-client.cjs navigate https://github.com
exec: node /path/to/relay-client.cjs click e3
```
Set `CLAW_RELAY_URL`, `CLAW_RELAY_TOKEN`, and `CLAW_RELAY_AGENT` in your environment or pass them as flags each time.
**Do NOT try to keep a persistent connection, start a background process, or write wrapper scripts.** The CLI handles connection lifecycle automatically.
## Security Constraints
- **Allowlist** — your agent can only access sites explicitly allowed in its config
- **Blocklist** — banking, email, and auth providers are always blocked regardless of allowlist
- **Rate limiting** — actions are rate-limited per agent
- **Audit log** — every action is logged with agent ID, action, target, and result
## Troubleshooting
### "Invalid token or agent_id"
- Agent ID is **case-sensitive**. Check `config.yaml` for exact casing (e.g., `Rusty` ≠ `rusty`)
- Make sure the token matches exactly — no extra spaces or line breaks
- The relay must be restarted after editing `config.yaml`
### "Agent lacks scope for 'navigate'"
- Your agent's `scopes` in `config.yaml` don't include the action you're trying to use
- Common scopes: `read` (snapshot/screenshot), `navigate`, `interact` (click/fill/type), `execute` (evaluate)
- Ask the relay admin to update your scopes
### Script errors
- **"require is not defined"** — the script must be `.cjs`, not `.js` (the repo uses ES modules)
- **"Cannot find module 'ws'"** — run `npm install` in the `relay-server/` directory first
### Common mistakes
- ❌ Writing an MCP server or bridge — you don't need one
- ❌ Keeping a persistent connection — each call is stateless
- ❌ Wrapping the CLI in another script — just call it directly via `exec`
## What Makes This Different
Local browser tools require agent and browser on the same machine. Claw Relay doesn't. Your agent runs anywhere and controls the user's real browser remotely — real cookies, real sessions, real logins. No headless browser, no fake profiles.
don't have the plugin yet? install it then click "run inline in claude" again.
converted unstructured relay guide into implexa's six-part format, added explicit decision branches for auth failures and rate limits, documented websocket and credential inputs, clarified success criteria with json output contract, and included edge cases like stale refs and timeout handling.
control a remote browser instance through Claw Relay's CLI client when your agent needs to interact with authenticated websites, fill forms, click buttons, take screenshots, or read page content. use this skill if your platform doesn't support MCP (message passing protocol) or if you need access to the user's real browser with real cookies and real sessions. unlike headless browser tools, Claw Relay runs the browser on the user's machine while your agent runs anywhere, giving you authenticated access without storing credentials.
environment variables or CLI flags (flags override env vars):
CLAW_RELAY_URL: websocket endpoint for the relay server (e.g., wss://relay.clawrelay.dev/)CLAW_RELAY_TOKEN: authentication token issued by the relay adminCLAW_RELAY_AGENT: your agent ID as declared in the relay's config.yaml (case-sensitive)external connections:
CLAW_RELAY_URL. expects outbound TLS on port 443. relay must be running and reachable from your agent's network.client script:
relay-client.cjs: CommonJS script (not ES modules) located in the claw-relay repo at skills/openclaw/relay-client.cjs or equivalent. requires Node.js 14+ and the ws npm package (npm install ws in the relay-server directory).prerequisites:
config.yaml with appropriate scopesnode CLI available in agent's execution environmentverify relay connectivity and credentials
CLAW_RELAY_URL, CLAW_RELAY_TOKEN, CLAW_RELAY_AGENTnode relay-client.cjs snapshot (or any action)ok: true or error message indicating auth failure, agent not found, or network timeoutnavigate to target URL
https://github.com)node relay-client.cjs navigate <url>{"ok": true} on success; {"ok": false, "error": "..."} if URL is blocklisted or agent lacks navigate scopecapture page snapshot to identify elements
node relay-client.cjs snapshotaccessibility_tree (nested text structure) and elements (array of clickable/interactive refs like e1, e3, e7)perform action: click, fill, type, press, hover, select, or evaluate
e3, text "search term", key name "Enter")node relay-client.cjs click <ref> | node relay-client.cjs fill <ref> <text> | node relay-client.cjs type <ref> <text> | node relay-client.cjs press <key> | node relay-client.cjs hover <ref> | node relay-client.cjs select <ref> <values...> | node relay-client.cjs evaluate <javascript>{"ok": true} or error (invalid ref, element not found, scope not granted)verify result by taking new snapshot
node relay-client.cjs snapshotcapture visual evidence (optional)
node relay-client.cjs screenshot [filepath]{"ok": true, "path": "/tmp/page.png", "bytes": 12345} on success; error if filepath is not writable or browser state is invalidclose browser session (optional cleanup)
node relay-client.cjs close{"ok": true}if initial snapshot fails with "Invalid token or agent_id":
CLAW_RELAY_AGENT matches the exact casing in config.yaml (e.g., Rusty not rusty)CLAW_RELAY_TOKEN has no leading/trailing whitespaceCLAW_RELAY_URLif action fails with "Agent lacks scope for 'ACTION'":
scopes in relay config don't include the action (e.g., navigate, interact, read, execute)if URL is blocklisted or navigate fails:
if element ref from snapshot is stale or "element not found":
if rate limit encountered (429 or action rejected):
if JavaScript evaluate returns null or undefined:
evaluate "try { ... } catch(e) { e.message }"if screenshot path is invalid or not writable:
/tmp/page.png or /home/user/screenshots/page.png)C:/Users/user/page.png)if websocket connection times out or relay is unreachable:
CLAW_RELAY_URL is correct and relay server is runningaction responses are always JSON. all actions return one of:
success: {"ok": true, ...} with action-specific fields:
navigate: no extra fieldssnapshot: includes accessibility_tree (string, nested text hierarchy) and elements (array of {ref: "eN", type: "button|input|link|...", text: "...", visible: true|false})screenshot: includes path (file location) and bytes (file size in bytes)click, fill, type, press, hover, select, close: no extra fieldsevaluate: includes result (JSON-serializable value or null)failure: {"ok": false, "error": "human-readable error message"}
file outputs:
side effects on remote browser:
navigate loads a new page in the browser tabclick, fill, type, press, hover, select modify form state, trigger events, or navigate if the action targets a linkevaluate may have side effects if the JavaScript modifies the DOMclose closes the tabyou know the skill worked when:
JSON response contains "ok": true , the relay accepted the command, authenticated the agent, and executed the action without error.
snapshot returns elements with refs , you can see the accessibility tree and locate interactive elements (e.g., {ref: "e3", type: "input", text: "Search..."}). if the tree is empty or contains only static text, the page may not be fully loaded; wait and retry.
page state changes after action , taking a new snapshot after click, fill, or type shows different content, new elements, or a different URL. compare accessibility trees before and after to confirm change.
screenshot is written to disk , the file exists at the specified path and is a valid PNG (byte size > 0). open it to visually verify the remote browser state.
form is filled or button is clicked , if you fill an input and then snapshot, the input's text value in the accessibility tree matches what you typed. if you click a button, the resulting page (from next snapshot) reflects the button's action (e.g., form submitted, modal opened, navigation occurred).
JavaScript evaluate returns a value , if you run evaluate "document.title", the result field contains the page title. if you run evaluate "document.querySelectorAll('button').length", result is the button count.
no "Invalid token", "lacks scope", or "blocklisted" errors , successful auth and scope check. if you see these errors, the skill failed before any browser action occurred; fix credentials and scopes.
network round-trip completes within timeout , CLI exits cleanly with JSON output (not hanging or timing out). if it times out, relay server or network is unreachable.
human-readable signal: you can read the accessibility tree, interact with the page using element refs, see the page change after each action, and take screenshots of the remote user's real browser. no errors means the agent is authenticated, scoped, and the relay is reachable.