Skip to main content

Prerequisites

Before starting, ensure you have:
  • Node.js 18+ installed
  • ~500MB disk space for Camoufox browser download (happens on first run)
  • curl or any HTTP client for testing
Camoufox downloads automatically on first launch (~300MB). This is a one-time download that’s cached locally.

Start the server

1

Clone and install

Clone the repository and install dependencies:
git clone https://github.com/jo-inc/camofox-browser
cd camofox-browser
npm install
2

Launch the server

Start the Camofox server:
npm start
You’ll see output like:
{"ts":"2026-02-28T10:15:30.123Z","level":"info","msg":"server listening","port":9377}
The server runs on port 9377 by default. Change with CAMOFOX_PORT=8080 npm start.
On first run, Camoufox will download the browser engine (~300MB). This takes 1-2 minutes depending on your connection.
3

Verify it's running

Check the health endpoint:
curl http://localhost:9377/health
Response:
{
  "ok": true,
  "engine": "camoufox",
  "browserConnected": false,
  "browserRunning": false,
  "activeTabs": 0,
  "consecutiveFailures": 0
}
browserRunning: false is normal - the browser launches lazily on first tab creation to save resources.

Your first automation

Let’s navigate to a website, get its content, and interact with an element.
1

Create a tab

Create a new browser tab:
curl -X POST http://localhost:9377/tabs \
  -H 'Content-Type: application/json' \
  -d '{
    "userId": "agent1",
    "sessionKey": "task1",
    "url": "https://example.com"
  }'
Response:
{
  "tabId": "3f8a9b2c-1d4e-4f5a-8b9c-2d3e4f5a6b7c",
  "url": "https://example.com/"
}
Save the tabId - you’ll need it for subsequent requests.
  • userId: Isolates cookies/storage between users (multi-tenant support)
  • sessionKey: Groups tabs by conversation or task
2

Get page snapshot

Get an accessibility snapshot with element refs:
curl "http://localhost:9377/tabs/3f8a9b2c-1d4e-4f5a-8b9c-2d3e4f5a6b7c/snapshot?userId=agent1"
Response:
{
  "url": "https://example.com/",
  "snapshot": "- heading \"Example Domain\"\n  - paragraph \"This domain is for use in illustrative examples in documents.\"\n  - link \"More information...\" [e1]\n",
  "refsCount": 1,
  "truncated": false,
  "totalChars": 156,
  "hasMore": false,
  "nextOffset": null
}
The snapshot field contains the accessibility tree with element refs (e1, e2, etc.).
Accessibility snapshots are ~90% smaller than raw HTML, saving context window tokens.
3

Interact with an element

Click the link using its ref e1:
curl -X POST http://localhost:9377/tabs/3f8a9b2c-1d4e-4f5a-8b9c-2d3e4f5a6b7c/click \
  -H 'Content-Type: application/json' \
  -d '{
    "userId": "agent1",
    "ref": "e1"
  }'
Response:
{
  "ok": true,
  "url": "https://www.iana.org/domains/reserved",
  "refsAvailable": true
}
The browser navigated to the link’s target! Notice refsAvailable: true - refs are automatically rebuilt after navigation.
4

Try a search macro

Navigate using a search macro:
curl -X POST http://localhost:9377/tabs/3f8a9b2c-1d4e-4f5a-8b9c-2d3e4f5a6b7c/navigate \
  -H 'Content-Type: application/json' \
  -d '{
    "userId": "agent1",
    "macro": "@google_search",
    "query": "best coffee beans 2026"
  }'
Response:
{
  "ok": true,
  "tabId": "3f8a9b2c-1d4e-4f5a-8b9c-2d3e4f5a6b7c",
  "url": "https://www.google.com/search?q=best+coffee+beans+2026",
  "refsAvailable": true
}
Search macros expand to full URLs automatically. Available macros:
  • @google_search
  • @youtube_search
  • @amazon_search
  • @reddit_search
  • @wikipedia_search
  • @twitter_search
  • And 8 more!

Type into a form

Let’s search Google by typing into the search box:
curl -X POST http://localhost:9377/tabs/YOUR_TAB_ID/navigate \
  -H 'Content-Type: application/json' \
  -d '{
    "userId": "agent1",
    "url": "https://www.google.com"
  }'
Element refs reset after navigation. Always get a fresh snapshot after clicking links or submitting forms.

Scroll and get more content

For long pages, scroll down to load more content:
curl -X POST http://localhost:9377/tabs/YOUR_TAB_ID/scroll \
  -H 'Content-Type: application/json' \
  -d '{
    "userId": "agent1",
    "direction": "down",
    "amount": 1000
  }'
Then get a fresh snapshot:
curl "http://localhost:9377/tabs/YOUR_TAB_ID/snapshot?userId=agent1"

Close the tab

When done, close the tab:
curl -X DELETE "http://localhost:9377/tabs/YOUR_TAB_ID?userId=agent1"
Response:
{"ok": true}

Next steps

Installation

Learn about Docker, Fly.io deployment, and OpenClaw plugin setup

API reference

Explore all available endpoints and parameters

Search macros

See all 14 built-in search shortcuts

Cookie import

Import cookies for authenticated browsing (LinkedIn, Amazon, etc.)

Common workflows

curl "http://localhost:9377/tabs/YOUR_TAB_ID/screenshot?userId=agent1" \
  -o screenshot.png
Returns a PNG image.
curl -X DELETE http://localhost:9377/sessions/agent1
Closes all tabs and deletes all cookies/storage for agent1.

Build docs developers (and LLMs) love