by jo-inc
Stealth headless browser for AI agents — bypass Cloudflare, bot detection, and anti-scraping. Drop-in Puppeteer/Playwright replacement.
# Add to your Claude Code skills
git clone https://github.com/jo-inc/camofox-browserGuides for using ai agents skills like camofox-browser.
Last scanned: 4/26/2026
{
"issues": [],
"status": "PASSED",
"scannedAt": "2026-04-26T06:06:54.524Z",
"semgrepRan": false,
"npmAuditRan": true,
"pipAuditRan": true
}Built by the team behind jo, a personal AI agent that runs half on your Mac, half on a dedicated cloud machine just for you -- with zero maintenance needed. Available on macOS, Telegram, WhatsApp, and email. Try the beta free ->
git clone https://github.com/jo-inc/camofox-browser && cd camofox-browser
npm install && npm start
# -> http://localhost:9377
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.
e1, e2, e3 identifiers for reliable interaction@google_search, @youtube_search, @amazon_search, @reddit_subreddit, and 10 more<img> src/alt and optionally return inline data URLs/openapi.json and interactive docs at /docsPOST /tabs/:tabId/extract with a JSON Schema that maps properties to snapshot refs via x-refCAMOFOX_CRASH_REPORT_ENABLED=false.| Dependency | Purpose | Install |
|---|---|---|
| yt-dlp | YouTube transcript extraction (fast path) | pip install yt-dlp or brew install yt-dlp |
The Docker image includes yt-dlp. For local dev, install it for the /youtube/transcript endpoint. Without it, the endpoint falls back to a slower browser-based method.
openclaw plugins install @askjo/camofox-browser
Tools: camofox_create_tab | camofox_snapshot | camofox_click | camofox_type | camofox_navigate | camofox_scroll | camofox_screenshot | camofox_close_tab | camofox_list_tabs | camofox_import_cookies
Run from npm:
npx @askjo/camofox-browser
Or from source:
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. See Environment Variables for all options.
Note: the postinstall script unsets
PLAYWRIGHT_SKIP_BROWSER_DOWNLOADfor itself before fetching the Camoufox binary. Without that override, an exportedPLAYWRIGHT_SKIP_BROWSER_DOWNLOAD=1(common when Playwright is configured to use system Chrome) would silently skip the binary download and crash the server at runtime.External Camoufox executable: set
CAMOUFOX_EXECUTABLE=/path/to/camoufox-binbeforenpm installand when starting the server to skip the bundled download and launch that executable. Compatibility aliases areCAMOUFOX_EXECUTABLE_PATHandCAMOFOX_EXECUTABLE_PATH. This is useful for NixOS paths such as/nix/store/.../camoufox-bin; the executable must come from a Camoufox bundle that includesproperties.json,version.json, andfontconfig/.Air-gapped or custom binary management: prefer
CAMOUFOX_EXECUTABLEwhen you already have a Camoufox bundle. Otherwise disable the auto-fetch withnpm install --ignore-scripts(skips lifecycle scripts for every dependency -- bluntest option) or, more surgically,npm install --omit=optionalplus a manualnpx camoufox-js fetchstep against your mirror. Note thatPLAYWRIGHT_SKIP_BROWSER_DOWNLOAD=1 npm installno longer skips the Camoufox download (the postinstall sanitizes the env locally); use--ignore-scriptsorCAMOUFOX_EXECUTABLEfor that.
The included Makefile auto-detects your CPU architecture and pre-downloads Camoufox + yt-dlp binaries outside the Docker build, so rebuilds are fast (~30s vs ~3min).
# Build and start (auto-detects arch: aarch64 on M1/M2, x86_64 on Intel)
make up
# Stop and remove the container
make down
# Force a clean rebuild (e.g. after upgrading VERSION/RELEASE)
make reset
# Just download binaries (without building)
make fetch
# Override arch or version explicitly
make up ARCH=x86_64
make up VERSION=135.0.1 RELEASE=beta.24
On Windows, make is not available. Use the included build.ps1 PowerShell script instead:
# Build and start
.\build.ps1 up
# Stop and remove the container
.\build.ps1 down
# Build image only
.\build.ps1 build
# Force a clean rebuild
.\build.ps1 reset
# Download binaries only (without building)
.\build.ps1 fetch
# Override architecture
.\build.ps1 up -Arch x86_64
.\build.ps1 up -Arch aarch64
Note: PowerShell 7+ (
pwsh) is recommended butpowershell.exe(Windows PowerShell 5.1) also works. The script requires Docker Desktop for Windows with the WSL2 backend.Line endings: This project includes a
.gitattributesfile that forces Unix (LF) line endings for.shfiles. If you've already cloned the repo and getsh: not foundorset: Illegal option -errors duringdocker build, run:Get-ChildItem -Recurse *.sh | ForEach-Object { (Get-Content $_) -join "`n" + "`n" | Set-Content $_ -NoNewline }This converts shell scripts to LF line endings. Future clones will handle this automatically thanks to
.gitattributes.
WARNING: Do not run
docker builddirectly. The Dockerfile uses bind mounts to pull pre-downloaded binaries fromdist/. Always usemake up(ormake fetchthenmake build) -- it downloads the binaries first.
For Fly.io or other remote CI, you'll need a Dockerfile that downloads binaries at build time instead of using bind mounts.
A railway.toml is included. It uses Dockerfile.ci (which downloads binaries at build time) and maps Railway's PORT env var to CAMOFOX_PORT automatically.
# Install Railway CLI, then:
railway link
railway up
Set secrets via the Railway dashboard or CLI:
railway variables set CAMOFOX_API_KEY="your-generated-key"
Import cookies from your browser into Camoufox to skip interactive login on sites like LinkedIn, Amazon, etc.
1. Generate a secret key:
# macOS / Linux
openssl rand -hex 32
2. Set the environment variable before starting OpenClaw:
export CAMOFOX_API_KEY="your-generated-key"
openclaw start
The same key is used by both the plugin (to authenticate requests) and the server (to verify them). Both run from the same environment -- set it once.
Why an env var? The key is a secret. Plugin config in
openclaw.jsonis stored in plaintext, so secrets don't belong there. SetCAMOFOX_API_KEYin your shell profile, systemd unit, Docker env, or Fly.io secrets.
Cookie import is disabled by default. I
No comments yet. Be the first to share your thoughts!