Anti-detection browser server for AI agents, powered by Camoufox
Standing on the mighty shoulders of Camoufox — a Firefox fork with fingerprint spoofing at the C++ level.
The same engine behind askjo.ai's web browsing.
AI agents need to browse the real web. Playwright gets blocked. Headless Chrome gets fingerprinted. Stealth plugins become the fingerprint.
Camoufox patches Firefox at the C++ implementation level — navigator.hardwareConcurrency, WebGL renderers, AudioContext, screen geometry, WebRTC — all spoofed before JavaScript ever sees them. No shims, no wrappers, no tells.
This project wraps that engine in a REST API built for agents: accessibility snapshots instead of bloated HTML, stable element refs for clicking, and search macros for common sites.
- C++ Anti-Detection — bypasses Google, Cloudflare, and most bot detection
- Element Refs — stable
e1,e2,e3identifiers for reliable interaction - Token-Efficient — accessibility snapshots are ~90% smaller than raw HTML
- Session Isolation — separate cookies/storage per user
- Search Macros —
@google_search,@youtube_search,@amazon_search, and 10 more - Deploy Anywhere — Docker, Fly.io, Railway
openclaw plugins install @askjo/camofox-browserTools: camofox_create_tab · camofox_snapshot · camofox_click · camofox_type · camofox_navigate · camofox_scroll · camofox_screenshot · camofox_close_tab · camofox_list_tabs
git clone https://github.com/jo-inc/camofox-browser
cd camofox-browser
npm install
npm start # downloads Camoufox on first run (~300MB)Default port is 9377. Set CAMOFOX_PORT to override.
docker build -t camofox-browser .
docker run -p 9377:9377 camofox-browserfly.toml and railway.toml are included. Deploy with fly deploy or connect the repo to Railway.
# Create a tab
curl -X POST http://localhost:9377/tabs \
-H 'Content-Type: application/json' \
-d '{"userId": "agent1", "sessionKey": "task1", "url": "https://example.com"}'
# Get accessibility snapshot with element refs
curl "http://localhost:9377/tabs/TAB_ID/snapshot?userId=agent1"
# → { "snapshot": "[button e1] Submit [link e2] Learn more", ... }
# Click by ref
curl -X POST http://localhost:9377/tabs/TAB_ID/click \
-H 'Content-Type: application/json' \
-d '{"userId": "agent1", "ref": "e1"}'
# Type into an element
curl -X POST http://localhost:9377/tabs/TAB_ID/type \
-H 'Content-Type: application/json' \
-d '{"userId": "agent1", "ref": "e2", "text": "hello", "pressEnter": true}'
# Navigate with a search macro
curl -X POST http://localhost:9377/tabs/TAB_ID/navigate \
-H 'Content-Type: application/json' \
-d '{"userId": "agent1", "macro": "@google_search", "query": "best coffee beans"}'| Method | Endpoint | Description |
|---|---|---|
POST |
/tabs |
Create tab with initial URL |
GET |
/tabs?userId=X |
List open tabs |
GET |
/tabs/:id/stats |
Tab stats (tool calls, visited URLs) |
DELETE |
/tabs/:id |
Close tab |
DELETE |
/tabs/group/:groupId |
Close all tabs in a group |
DELETE |
/sessions/:userId |
Close all tabs for a user |
| Method | Endpoint | Description |
|---|---|---|
GET |
/tabs/:id/snapshot |
Accessibility snapshot with element refs |
POST |
/tabs/:id/click |
Click element by ref or CSS selector |
POST |
/tabs/:id/type |
Type text into element |
POST |
/tabs/:id/press |
Press a keyboard key |
POST |
/tabs/:id/scroll |
Scroll page (up/down/left/right) |
POST |
/tabs/:id/navigate |
Navigate to URL or search macro |
POST |
/tabs/:id/wait |
Wait for selector or timeout |
GET |
/tabs/:id/links |
Extract all links on page |
GET |
/tabs/:id/screenshot |
Take screenshot |
POST |
/tabs/:id/back |
Go back |
POST |
/tabs/:id/forward |
Go forward |
POST |
/tabs/:id/refresh |
Refresh page |
| Method | Endpoint | Description |
|---|---|---|
GET |
/health |
Health check |
POST |
/start |
Start browser engine |
POST |
/stop |
Stop browser engine |
@google_search · @youtube_search · @amazon_search · @reddit_search · @wikipedia_search · @twitter_search · @yelp_search · @spotify_search · @netflix_search · @linkedin_search · @instagram_search · @tiktok_search · @twitch_search
Browser Instance (Camoufox)
└── User Session (BrowserContext) — isolated cookies/storage
├── Tab Group (sessionKey: "conv1")
│ ├── Tab (google.com)
│ └── Tab (github.com)
└── Tab Group (sessionKey: "conv2")
└── Tab (amazon.com)
Sessions auto-expire after 30 minutes of inactivity.
npm test # all tests
npm run test:e2e # e2e tests only
npm run test:live # live site tests (Google, macros)
npm run test:debug # with server outputnpm install @askjo/camofox-browserMIT