Install
openclaw skills install camofox-browserHeadless browser server enabling AI agents to create tabs, navigate, interact, and capture snapshots with element references locally or in the cloud.
openclaw skills install camofox-browserHeadless browser automation server for AI agents. Run locally or deploy to any cloud provider.
# Install and start
npm install && npm start
# Server runs on http://localhost:9377
tabIde1, e2, etc.)POST /tabs
{"userId": "agent1", "sessionKey": "task1", "url": "https://example.com"}
Returns: {"tabId": "abc123", "url": "...", "title": "..."}
POST /tabs/:tabId/navigate
{"userId": "agent1", "url": "https://google.com"}
# Or use macro:
{"userId": "agent1", "macro": "@google_search", "query": "weather today"}
GET /tabs/:tabId/snapshot?userId=agent1
Returns accessibility tree with refs:
[heading] Example Domain
[paragraph] This domain is for use in examples.
[link e1] More information...
POST /tabs/:tabId/click
{"userId": "agent1", "ref": "e1"}
# Or CSS selector:
{"userId": "agent1", "selector": "button.submit"}
POST /tabs/:tabId/type
{"userId": "agent1", "ref": "e2", "text": "hello world"}
# Add enter: {"userId": "agent1", "ref": "e2", "text": "search query", "pressEnter": true}
POST /tabs/:tabId/scroll
{"userId": "agent1", "direction": "down", "amount": 500}
POST /tabs/:tabId/back {"userId": "agent1"}
POST /tabs/:tabId/forward {"userId": "agent1"}
POST /tabs/:tabId/refresh {"userId": "agent1"}
GET /tabs/:tabId/links?userId=agent1&limit=50
DELETE /tabs/:tabId?userId=agent1
Use these instead of constructing URLs:
| Macro | Site |
|---|---|
@google_search | |
@youtube_search | YouTube |
@amazon_search | Amazon |
@reddit_search | |
@wikipedia_search | Wikipedia |
@twitter_search | Twitter/X |
@yelp_search | Yelp |
@linkedin_search |
Refs like e1, e2 are stable identifiers for page elements:
/snapshot to get current refs/click or /typeuserId isolates cookies/storage between userssessionKey groups tabs by conversation/task (legacy: listItemId also accepted)DELETE /sessions/:userIdnpm start
# Or: ./run.sh
Firefox-based with anti-detection. Bypasses Google captcha.
npm test # E2E tests
npm run test:live # Live Google tests
npm run test:debug # With server output
docker build -t camofox-browser .
docker run -p 9377:9377 camofox-browser
server.js - Camoufox engine (routes + browser logic only — NO process.env or child_process)lib/config.js - All process.env reads centralized herelib/youtube.js - YouTube transcript extraction via yt-dlp (child_process isolated here)lib/launcher.js - Subprocess spawning (child_process isolated here)lib/cookies.js - Cookie file I/Olib/metrics.js - Prometheus metrics (lazy-loaded, off by default — set PROMETHEUS_ENABLED=1)lib/request-utils.js - HTTP request classification helpers (actionFromReq, classifyError)lib/snapshot.js - Accessibility tree snapshotlib/macros.js - Search macro URL expansionDockerfile - Production containerOpenClaw's skill-scanner flags plugins that have process.env + network calls (e.g. app.post, fetch, http.request) in the same file, or child_process + network calls in the same file. These patterns suggest potential credential exfiltration.
Rule: No single .js file may contain both halves of a scanner rule pair:
process.env lives ONLY in lib/config.jschild_process / execFile / spawn live ONLY in lib/youtube.js and lib/launcher.jsserver.js has the Express routes (app.post, app.get) but ZERO process.env reads and ZERO child_process importslib/metrics.js has NO process.env and NO HTTP method strings (POST, fetch). Prometheus is lazy-loaded only when PROMETHEUS_ENABLED=1.lib/request-utils.js has HTTP method strings (POST) but NO process.env — safe.lib/ module and import the result into server.jsScanner rule details (from src/security/skill-scanner.ts):
env-harvesting (CRITICAL): fires when /process\.env/ AND /\bfetch\b|\bpost\b|http\.request/i match the SAME file. Note: the regex is case-insensitive, so string literals like 'POST' and even comments containing process.env will trigger it.dangerous-exec (CRITICAL): child_process import + exec/spawn call in same filepotential-exfiltration (WARN): readFile + fetch/post/http.request in same fileThis was broken in 1.3.0 (YouTube child_process in server.js), fixed in 1.3.1. Broken again in 1.4.1 (metrics.js had process.env in a comment + 'POST' in actionFromReq), fixed in 1.5.1 by lazy-loading prom-client and splitting actionFromReq into lib/request-utils.js.