Stealth headless browser for AI agents — bypass Cloudflare, bot detection, and anti-scraping. Drop-in Puppeteer/Playwright replacement.
| 文件 | 最后提交记录 | 最后更新时间 |
|---|---|---|
| 1 个月前 | ||
| 3 个月前 | ||
| 5 个月前 | ||
| 4 个月前 | ||
| 20 天前 | ||
| 19 天前 | ||
| 20 天前 | ||
| 1 个月前 | ||
| 20 天前 | ||
| 3 个月前 | ||
| 3 个月前 | ||
| 4 个月前 | ||
| 1 个月前 | ||
| 6 个月前 | ||
| 22 天前 | ||
| 20 天前 | ||
| 6 个月前 | ||
| 1 个月前 | ||
| 20 天前 | ||
| 3 个月前 | ||
| 6 个月前 | ||
| 20 天前 | ||
| 4 个月前 | ||
| 4 个月前 | ||
| 4 个月前 | ||
| 4 个月前 | ||
| 19 天前 | ||
| 19 天前 | ||
| 19 天前 | ||
| 19 天前 | ||
| 1 个月前 | ||
| 1 个月前 | ||
| 4 个月前 | ||
| 1 个月前 | ||
| 6 个月前 | ||
| 20 天前 | ||
| 4 个月前 | ||
| 4 个月前 |
camofox-browser
为 AI 代理打造的反检测浏览器服务,由 Camoufox 驱动
站在 Camoufox 这位巨人的肩膀上——这是一款在 C++ 层面实现指纹伪装能力的 Firefox 分支。
由 jo 个人 AI 代理 的开发团队打造——jo 一半运行在你的 Mac 上,一半运行在专属于你的云端机器上,完全无需维护。支持 macOS、Telegram、WhatsApp 和电子邮件。 免费试用测试版 ->
git clone https://github.com/jo-inc/camofox-browser && cd camofox-browser
npm install && npm start
# -> http://localhost:9377
为什么
AI 智能体需要浏览真实的网页。Playwright 会被拦截,无头 Chrome 会被指纹识别,而隐身插件本身反而成了指纹特征。
Camoufox 在 C++ 实现层面 对 Firefox 进行修补——navigator.hardwareConcurrency、WebGL 渲染器、AudioContext、屏幕几何信息、WebRTC——所有这些都在 JavaScript 能触及之前就被伪装完毕。没有 shim、没有包装层、没有任何可被识别的痕迹。
本项目将该引擎封装为一个专为智能体设计的 REST API:用无障碍快照替代臃肿的 HTML,用稳定的元素引用实现点击操作,并为常见网站提供搜索宏。
功能特性
- C++ 级反检测 — 绕过 Google、Cloudflare 以及大多数机器人检测系统
- 元素引用 — 稳定的
e1、e2、e3标识符,确保可靠的交互操作 - 高 Token 效率 — 无障碍快照比原始 HTML 小约 90%
- 随处可运行 — 浏览器懒启动 + 空闲自动关闭,空闲时内存占用约 40MB。专为与你的其他服务共享同一台机器而设计——树莓派、5 美元 VPS、共享基础设施均可。
- 会话隔离 — 每个用户独立存储 Cookie 和数据
- Cookie 导入 — 注入 Netscape 格式的 Cookie 文件,实现已认证状态的浏览
- 文件上传 — 从配置的上传目录附加文件,无需原生操作系统对话框
- 代理 + GeoIP — 通过住宅代理路由流量,自动匹配区域设置和时区
- 结构化日志 — 带请求 ID 的 JSON 日志行,便于生产环境可观测性
- YouTube 字幕提取 — 通过 yt-dlp 从任意 YouTube 视频提取字幕,无需 API 密钥
- 搜索宏 —
@google_search、@youtube_search、@amazon_search、@reddit_subreddit以及另外 10 余种 - 快照截图 — 在无障碍快照旁附带 base64 PNG 截图
- 大页面处理 — 自动截断快照,支持基于偏移量的分页
- 下载捕获 — 捕获浏览器下载内容并可通过 API 获取(可选内联 base64)
- DOM 图片提取 — 列出
<img>的 src/alt 属性,可选返回内联 data URL - 随处部署 — Docker、Fly.io、Railway
- VNC 交互式登录 — 通过 noVNC 可视化登录网站,导出存储状态供智能体复用
- OpenAPI 文档 — 自动生成的规范文件位于
/openapi.json,交互式文档位于/docs - 结构化提取 —
POST /tabs/:tabId/extract接口,配合 JSON Schema 通过x-ref将属性映射到快照引用 - 会话追踪 — 按会话选择性地捕获 Playwright 追踪(截图 + DOM 快照 + 网络),并提供 API 端点来列出、获取和删除追踪压缩包
- 遥测 — 通过 GitHub Issues 自动上报匿名化的崩溃/挂起遥测数据。用于识别导致故障的网站和常见故障模式。私有域名经 HMAC 哈希处理,路径/参数被剥离,令牌/IP 被脱敏。可通过
CAMOFOX_CRASH_REPORT_ENABLED=false关闭。
可选依赖
| 依赖项 | 用途 | 安装方式 |
|---|---|---|
| yt-dlp | YouTube 字幕提取(快速通道) | pip install yt-dlp 或 brew install yt-dlp |
Docker 镜像已内置 yt-dlp。本地开发时,请自行安装以启用 /youtube/transcript 接口。若未安装,该接口将回退至基于浏览器的较慢方案。
快速开始
OpenClaw 插件
openclaw plugins install @askjo/camofox-browser
工具: camofox_create_tab | camofox_snapshot | camofox_click | camofox_type | camofox_navigate | camofox_scroll | camofox_screenshot | camofox_close_tab | camofox_list_tabs | camofox_import_cookies
独立运行
通过 npm 运行:
npx @askjo/camofox-browser
或者从源码构建:
git clone https://github.com/jo-inc/camofox-browser
cd camofox-browser
npm install
npm start # downloads Camoufox on first run (~300MB)
默认端口为 9377。所有选项请参阅环境变量。
注意: postinstall 脚本在获取 Camoufox 二进制文件之前,会先自行取消设置
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD。如果没有这个覆盖,导出的PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD=1(在 Playwright 配置为使用系统 Chrome 时很常见)会静默跳过二进制文件下载,并在运行时导致服务器崩溃。外部 Camoufox 可执行文件: 在
npm install之前以及启动服务器时,设置CAMOUFOX_EXECUTABLE=/path/to/camoufox-bin,以跳过捆绑下载并启动该可执行文件。兼容别名包括CAMOUFOX_EXECUTABLE_PATH和CAMOFOX_EXECUTABLE_PATH。这对于 NixOS 路径(如/nix/store/.../camoufox-bin)非常有用;该可执行文件必须来自包含properties.json、version.json和fontconfig/的 Camoufox 包。离线环境或自定义二进制文件管理: 如果您已有 Camoufox 包,请优先使用
CAMOUFOX_EXECUTABLE。否则,可以通过npm install --ignore-scripts禁用自动获取(这会跳过所有依赖项的生命周期脚本——最直接的方式),或者更精细地使用npm install --omit=optional并手动执行npx camoufox-js fetch指向您的镜像。请注意,PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD=1 npm install不再跳过 Camoufox 下载(postinstall 会在本地清理环境变量);如需实现该效果,请使用--ignore-scripts或CAMOUFOX_EXECUTABLE。
Docker
附带的 Makefile 会自动检测您的 CPU 架构,并在 Docker 构建之外预下载 Camoufox 和 yt-dlp 二进制文件,从而大幅加快重建速度(约 30 秒 vs 约 3 分钟)。
# 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
Windows
在 Windows 上,make 不可用。请改用附带的 build.ps1 PowerShell 脚本:
# 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
注意: 推荐使用 PowerShell 7+ (
pwsh),但powershell.exe(Windows PowerShell 5.1)也可正常使用。该脚本需要安装了 WSL2 后端的 Docker Desktop for Windows。换行符: 本项目包含一个
.gitattributes文件,强制对所有.sh文件使用 Unix(LF)换行符。如果你已经克隆了仓库,并且在docker build过程中遇到sh: not found或set: Illegal option -错误,请运行:Get-ChildItem -Recurse *.sh | ForEach-Object { (Get-Content $_) -join "`n" + "`n" | Set-Content $_ -NoNewline }此命令会将 shell 脚本转换为 LF 换行符。得益于
.gitattributes,后续克隆将自动处理此问题。
警告:请勿直接运行
docker build。 Dockerfile 使用绑定挂载(bind mounts)从dist/目录加载预下载的二进制文件。请始终使用make up(或先执行make fetch再执行make build)——该流程会先下载二进制文件。
Fly.io
对于 Fly.io 或其他远程 CI 环境,你需要一个在构建阶段下载二进制文件(而非使用绑定挂载)的 Dockerfile。
Railway
已包含一个 railway.toml 配置文件。它使用 Dockerfile.ci(该文件在构建时下载二进制文件),并会自动将 Railway 的 PORT 环境变量映射到 CAMOFOX_PORT。
# Install Railway CLI, then:
railway link
railway up
通过 Railway 控制面板或 CLI 设置密钥:
railway variables set CAMOFOX_API_KEY="your-generated-key"
使用方法
Cookie 导入
将浏览器中的 Cookie 导入 Camoufox,即可跳过 LinkedIn、Amazon 等网站的交互式登录流程。
配置步骤
1. 生成密钥:
# macOS / Linux
openssl rand -hex 32
2. 在启动 OpenClaw 之前,先设置环境变量:
export CAMOFOX_API_KEY="your-generated-key"
openclaw start
插件与服务器共用同一个密钥(插件用于认证请求,服务器用于验证请求)。二者运行在同一环境中——只需设置一次即可。
为何使用环境变量? 该密钥属于机密信息。
openclaw.json中的插件配置以明文存储,因此机密信息不应放在其中。请在 shell 配置文件、systemd 单元、Docker 环境或 Fly.io 机密中设置CAMOFOX_API_KEY。
Cookie 导入默认禁用。 如果未设置
CAMOFOX_API_KEY,服务器将以 403 拒绝所有 cookie 请求。
3. 从浏览器导出 Cookie:
安装一个可导出 Netscape 格式 cookie 文件的浏览器扩展(例如 Chrome/Firefox 的 "cookies.txt")。导出你想要认证的网站的 cookie。
4. 放置 Cookie 文件:
mkdir -p ~/.camofox/cookies
cp ~/Downloads/linkedin_cookies.txt ~/.camofox/cookies/linkedin.txt
默认目录为 ~/.camofox/cookies/。可通过 CAMOFOX_COOKIES_DIR 环境变量覆盖。
5. 让您的智能体导入这些 Cookie:
从 linkedin.txt 导入我的 LinkedIn Cookie
智能体会调用 camofox_import_cookies -> 读取文件 -> 使用 Bearer 令牌向服务器发送 POST 请求 -> Cookie 被注入浏览器会话。随后对 linkedin.com 发起的 camofox_create_tab 调用将自动完成身份认证。
工作原理
~/.camofox/cookies/linkedin.txt (Netscape format, on disk)
|
v
camofox_import_cookies tool (parses file, filters by domain)
|
v POST /sessions/:userId/cookies
| Authorization: Bearer <CAMOFOX_API_KEY>
| Body: { cookies: [Playwright cookie objects] }
v
camofox server (validates, sanitizes, injects)
|
v context.addCookies(...)
|
Camoufox browser session (authenticated browsing)
cookiesPath相对于 cookies 目录进行解析——禁止路径穿越到该目录之外- 每个请求最多 500 个 cookie,文件大小限制为 5MB
- Cookie 对象会经过清洗,仅保留 Playwright 字段中的允许列表字段
会话持久化
默认情况下,camofox 会将每个用户的 cookies 和 localStorage 持久化到 ~/.camofox/profiles/ 目录中。会话在浏览器重启后依然保留——只需登录一次(通过 cookies 或 VNC),后续会话便会自动恢复已认证状态。
~/.camofox/
|-- cookies/ # Bootstrap cookie files (Netscape format)
\-- profiles/ # Persisted session state (auto-managed)
\-- <hashed-userId>/
\-- storage_state.json
使用 CAMOFOX_PROFILE_DIR 环境变量覆盖目录,或在持久化插件配置中设置 "profileDir"。要禁用持久化,请在 camofox.config.json 中设置 "persistence": { "enabled": false }。
默认情况下,存储状态仅包含 cookies 和 localStorage。如需同时持久化 IndexedDB,请在持久化插件配置中设置 "indexedDB": true。这会捕获所有可序列化的 IndexedDB 记录——不仅限于认证数据——但可能导致快照体积显著增大,检查点速度变慢。
会话追踪
捕获会话中每个操作的 Playwright 追踪记录:页面截图、DOM 快照、网络请求和控制台输出。输出为单个 .zip 文件,可在 Playwright 内置的 Trace Viewer 中打开。
在打开第一个标签页时传入 trace: true 即可按会话选择启用此功能:
curl -X POST http://localhost:9377/tabs \
-H 'Content-Type: application/json' \
-d '{"userId":"agent1","sessionKey":"task1","url":"https://example.com","trace":true}'
trace(跟踪记录)在会话关闭时写入。请关闭会话以刷新数据,然后依次执行列出、获取和查看操作:
# Close the session to flush the trace
curl -X DELETE http://localhost:9377/sessions/agent1
# List trace files
curl http://localhost:9377/sessions/agent1/traces
# {"traces":[{"filename":"trace-2026-04-18T04-05-00-...zip","sizeBytes":42810,"createdAt":...}]}
# Download (Content-Type: application/zip)
curl http://localhost:9377/sessions/agent1/traces/trace-2026-04-18T04-05-00-abc.zip > session.zip
# View it in Playwright's Trace Viewer
npx playwright show-trace session.zip
# Delete
curl -X DELETE http://localhost:9377/sessions/agent1/traces/trace-2026-04-18T04-05-00-abc.zip
为什么用追踪记录(traces)而不是视频:Camoufox 基于 Firefox 构建,而 Playwright 的 recordVideo 仅支持 Chromium。追踪记录在 Firefox 上可用,并且能提供比视频更丰富的信息(网络请求 + DOM + 控制台 + 截图)。
追踪记录无法在现有会话上动态开启。如需更改该标志,请先调用 DELETE /sessions/:userId。
存储默认位置为 ~/.camofox/traces/<hashed-userId>/,并在服务器启动时进行清理:
CAMOFOX_TRACES_DIR— 基础目录(默认:~/.camofox/traces)CAMOFOX_TRACES_MAX_BYTES— 每条追踪记录的最大大小,超出后会在下次启动时被删除(默认:50MB)CAMOFOX_TRACES_TTL_HOURS— 超过该时长的追踪记录会在下次启动时被删除(默认:24)
独立服务器用法
curl -X POST http://localhost:9377/sessions/agent1/cookies \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer YOUR_CAMOFOX_API_KEY' \
-d '{"cookies":[{"name":"foo","value":"bar","domain":"example.com","path":"/","expires":-1,"httpOnly":false,"secure":false}]}'
Docker / Fly.io / Railway
docker run -p 9377:9377 \
-e CAMOFOX_API_KEY="your-generated-key" \
-v ~/.camofox/cookies:/home/node/.camofox/cookies:ro \
camofox-browser
对于 Fly.io:
fly secrets set CAMOFOX_API_KEY="your-generated-key"
对于 Railway:
railway variables set CAMOFOX_API_KEY="your-generated-key"
代理 + GeoIP
通过代理路由所有浏览器流量,并借助 Camoufox 内置的 GeoIP,根据代理 IP 地址自动推导区域设置、时区和地理位置。
简单代理(单一端点):
export PROXY_HOST=166.88.179.132
export PROXY_PORT=46040
export PROXY_USERNAME=myuser
export PROXY_PASSWORD=mypass
npm start
回连代理(轮换粘性会话):
对于像 Decodo、Bright Data 或 Oxylabs 这类通过单一网关端点提供基于会话的粘性 IP 的服务商:
export PROXY_STRATEGY=backconnect
export PROXY_BACKCONNECT_HOST=gate.provider.com
export PROXY_BACKCONNECT_PORT=7000
export PROXY_USERNAME=myuser
export PROXY_PASSWORD=mypass
npm start
每个浏览器上下文都会获得一个唯一的固定会话,因此不同用户会分配到不同的IP地址。当发生代理错误或遭遇Google拦截时,会话会自动轮换。
或者使用Docker:
docker run -p 9377:9377 \
-e PROXY_HOST=166.88.179.132 \
-e PROXY_PORT=46040 \
-e PROXY_USERNAME=myuser \
-e PROXY_PASSWORD=mypass \
camofox-browser
当配置了代理时:
- 所有流量均通过代理路由
- Camoufox 的 GeoIP 会自动将
locale、timezone和geolocation设置为与代理出口 IP 相匹配 - 浏览器指纹(语言、时区、坐标)与代理位置保持一致
- 未配置代理时,默认使用
en-US、America/Los_Angeles以及旧金山坐标
遥测
浏览器自动化会以难以预测的方式失败——Cloudflare 质询、网站改版导致选择器失效、重定向循环、对话框风暴、渲染进程崩溃。失败范围广泛,失败模式多种多样。没有遥测,唯一的信号就是“它没跑通”。
遥测为我们提供结构化数据,告诉我们哪些网站失败、如何失败以及失败频率,这样我们就能优先修复那些真正影响用户的模式。当出现以下情况时,遥测会自动提交 GitHub Issue:
- 未捕获异常导致进程崩溃
- 事件循环停滞超过 5 秒(看门狗检测)
- 挫败模式——同一个标签页上连续 3 次以上失败(超时、上下文失效、导航中断)
每条报告都包含失败类型、堆栈跟踪、标签页健康计数器(HTTP 状态码直方图、控制台错误、请求失败、重定向深度)以及目标 URL——全部经过匿名化处理。
工作原理
遥测数据发送至位于 https://camofox-telemetry.askjo.workers.dev 的轻量级 Cloudflare Worker 端点。该端点将 GitHub App 凭据作为环境密钥保存——本包中不包含任何密钥。
lib/reporter.js (client, no secrets)
| anonymize -> POST https://camofox-telemetry.askjo.workers.dev/report
v
Cloudflare Worker (holds GitHub App key)
| validate -> rate-limit -> dedup -> create GitHub Issue
v
GitHub Issue created
端点源码位于本仓库的 workers/crash-reporter/index.ts 中。
验证方式
您无需信任我们——可自行验证线上端点实际运行的内容:
# 1. Ask the endpoint what code it's running
curl https://camofox-telemetry.askjo.workers.dev/source
# -> { "commit": "abc1234", "sha256": "e3b0c44...", "source": "https://github.com/..." }
# 2. Compare the sha256 against the source in this repo
sha256sum workers/crash-reporter/index.ts
# 3. Check the commit matches what CI deployed
# https://github.com/jo-inc/camofox-browser/actions/workflows/telemetry-deploy.yml
git log --oneline workers/crash-reporter/index.ts | head -1
如果哈希值不匹配,说明端点运行的代码与仓库中的代码不一致。部署工作流(.github/workflows/telemetry-deploy.yml)会在部署时注入提交哈希和源码哈希——每次部署都可以在 GitHub Actions 中追溯审计。
也可以完全跳过验证:设置 CAMOFOX_CRASH_REPORT_ENABLED=false 可禁用所有遥测,或通过 CAMOFOX_CRASH_REPORT_URL 指向你自己的端点。
隐私保护
所有上报数据在离开进程之前都会经过严苛的匿名化处理(lib/reporter.js L28-290):
- URL —— 知名的公共域名(Google、Amazon、Reddit、Cloudflare 等)会原样显示,以便我们识别哪些站点引发问题。私有或未知域名会被替换为稳定的 HMAC 哈希值(
site-a1b2c3d4)——不同报告中的同一域名会产生相同的哈希,便于关联分析,但无法逆向还原原始域名。路径部分简化为*/*/*(仅保留层级深度),查询参数变为?[3](仅保留参数数量)。密钥、数值或路径内容永远不会被包含在内。 - 文件路径 —— 仅保留文件名(
<path>/server.js) - 令牌、机密信息、API 密钥 —— 替换为
<token> - IP 地址、邮箱、环境变量 —— 一律脱敏
- Docker/Fly 机器 ID —— 替换为
<id> - 标签页健康状态 —— 纯计数器(崩溃次数、错误次数、状态码分布直方图)。不包含页面内容、URL 或任何用户数据。
重复问题通过堆栈签名进行识别,并自动添加 +1 评论,而不会创建新 issue。
# Disable telemetry
export CAMOFOX_CRASH_REPORT_ENABLED=false
# Point to your own endpoint (see below)
export CAMOFOX_CRASH_REPORT_URL=https://your-endpoint.example.com/report
# Adjust rate limit (default: 10 per hour)
export CAMOFOX_CRASH_REPORT_RATE_LIMIT=5
自托管遥测端点
若要将遥测报告提交至您自己的 GitHub 仓库,而非 jo-inc/camofox-browser,请按以下步骤操作:
-
创建 GitHub App -- Settings -> Developer settings -> GitHub Apps -> New
- 权限设置:Repository -> Issues -> Read & Write
- 取消勾选 Webhook -> Active(无需启用)
- 点击 Generate a key -- 下载
.pem文件 - 将应用安装到目标仓库(Install App -> 选择仓库)
- 记下您的 App ID(应用 General 页面上的数字)和 Installation ID(安装后从 URL 中获取:
github.com/settings/installations/{id})
-
部署端点 -- 克隆此仓库并部署 worker:
cd workers/crash-reporter # 编辑 wrangler.toml:将 account_id 设置为您的 Cloudflare 账户 ID npx wrangler deploy该 worker 是一个零 npm 依赖的单一 TypeScript 文件,也可在 Deno、Bun 或任何支持 Web Crypto API 的运行时上运行。
-
设置 worker 密钥:
cd workers/crash-reporter echo "YOUR_APP_ID" | npx wrangler secret put GH_APP_ID echo "YOUR_INSTALL_ID" | npx wrangler secret put GH_INSTALL_ID # 密钥必须为 PKCS#8 DER base64 格式(非原始 PEM) openssl pkcs8 -topk8 -inform PEM -outform DER -nocrypt -in your-app.pem | \ base64 | tr -d '\n' | npx wrangler secret put GH_PRIVATE_KEY # 在您的仓库中创建 issue echo "your-org/your-repo" | npx wrangler secret put GH_REPO -
将 camofox-browser 指向您的端点:
export CAMOFOX_CRASH_REPORT_URL=https://your-worker.your-subdomain.workers.dev/report -
验证:
curl https://your-worker.your-subdomain.workers.dev/health # -> {"status":"ok"}
结构化日志
所有日志输出均为 JSON 格式(每行一个对象),便于日志聚合器解析:
{"ts":"2026-02-11T23:45:01.234Z","level":"info","msg":"req","reqId":"a1b2c3d4","method":"POST","path":"/tabs","userId":"agent1"}
{"ts":"2026-02-11T23:45:01.567Z","level":"info","msg":"res","reqId":"a1b2c3d4","status":200,"ms":333}
健康检查请求(/health)不计入请求日志,以减少干扰。
基础浏览
# 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"}'
API
标签页生命周期
| 方法 | 端点 | 描述 |
|---|---|---|
POST |
/tabs |
使用初始 URL 创建标签页 |
GET |
/tabs?userId=X |
列出打开的标签页 |
GET |
/tabs/:id/stats |
标签页统计(工具调用、访问过的 URL) |
DELETE |
/tabs/:id |
关闭标签页 |
DELETE |
/tabs/group/:groupId |
关闭组内所有标签页 |
DELETE |
/sessions/:userId |
关闭某用户的所有标签页 |
页面交互
| 方法 | 端点 | 描述 |
|---|---|---|
GET |
/tabs/:id/snapshot |
包含元素引用的无障碍快照。查询参数:includeScreenshot=true(附加 base64 编码的 PNG)、offset=N(对大型快照进行分页) |
POST |
/tabs/:id/click |
通过引用或 CSS 选择器点击元素 |
POST |
/tabs/:id/type |
向元素输入文本 |
POST |
/tabs/:id/press |
按下键盘按键 |
POST |
/tabs/:id/scroll |
滚动页面(上/下/左/右) |
POST |
/tabs/:id/navigate |
导航至 URL 或搜索宏 |
POST |
/tabs/:id/wait |
等待选择器出现或超时 |
GET |
/tabs/:id/links |
提取页面上的所有链接 |
GET |
/tabs/:id/images |
列出 <img> 元素。查询参数:includeData=true(返回内联 data URL)、maxBytes=N、limit=N |
GET |
/tabs/:id/downloads |
列出捕获的下载内容。查询参数:includeData=true(base64 编码的文件数据)、consume=true(读取后清除)、maxBytes=N |
GET |
/tabs/:id/screenshot |
截取屏幕截图 |
POST |
/tabs/:id/back |
后退 |
POST |
/tabs/:id/forward |
前进 |
POST |
/tabs/:id/refresh |
刷新页面 |
YouTube 字幕
| 方法 | 端点 | 描述 |
|---|---|---|
POST |
/youtube/transcript |
从 YouTube 视频中提取字幕 |
curl -X POST http://localhost:9377/youtube/transcript \
-H 'Content-Type: application/json' \
-d '{"url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ", "languages": ["en"]}'
# -> { "status": "ok", "transcript": "[00:18] [music] We're no strangers to love [music]\n...", "video_title": "...", "total_words": 548 }
在可用时使用 yt-dlp(速度快,无需浏览器)。若未安装 yt-dlp,则回退到基于浏览器的拦截方式——但由于 YouTube 片头广告的存在,该方式更慢且可靠性较低。
服务器
| 方法 | 端点 | 描述 |
|---|---|---|
GET |
/health |
健康检查 |
POST |
/start |
启动浏览器引擎 |
POST |
/stop |
停止浏览器引擎 |
会话
| 方法 | 端点 | 描述 |
|---|---|---|
POST |
/sessions/:userId/cookies |
向用户会话添加 Cookie(Playwright Cookie 对象) |
GET |
/sessions/:userId/storage_state |
导出持久化的浏览器存储(VNC 插件) |
DELETE |
/sessions/:userId/storage_state |
重置当前会话并删除其持久化的浏览器存储(持久化插件) |
搜索宏
@google_search | @youtube_search | @amazon_search | @reddit_search | @reddit_subreddit | @wikipedia_search | @twitter_search | @yelp_search | @spotify_search | @netflix_search | @linkedin_search | @instagram_search | @tiktok_search | @twitch_search
Reddit 宏直接返回 JSON(无需解析 HTML):
@reddit_search— 搜索整个 Reddit,返回包含 25 条结果的 JSON@reddit_subreddit— 浏览某个子版块(例如,查询"programming"→/r/programming.json)
浏览器配置
浏览器行为可通过 camofox.config.json 进行调优:
{
"newPageTimeoutMs": 10000
}
newPageTimeoutMs 控制标签页创建时,等待 Firefox 生成页面的最长时间。如果上下文无响应,Camofox 仅替换该用户的上下文并重试一次。默认值为 10 秒。
环境变量
| 变量 | 说明 | 默认值 |
|---|---|---|
CAMOFOX_PORT |
服务端口 | 9377 |
PORT |
服务端口(备用,适用于 Fly.io、Railway 等平台) | 9377 |
CAMOFOX_BIND_HOST |
可选的服务绑定主机。设为 127.0.0.1 仅允许本机回环访问,或设为 0.0.0.0 以在所有接口上启用 IPv4。未设置时,Node 使用其默认的全接口绑定。 |
- |
CAMOFOX_API_KEY |
启用 Cookie 导入端点(未设置时禁用) | - |
CAMOFOX_ADMIN_KEY |
POST /stop 所需的密钥 |
- |
CAMOFOX_ACCESS_KEY |
若设置,则所有路由(/health、Cookie 导入和 /stop 除外)均要求携带 Authorization: Bearer <key> 头。这允许您安全地将服务暴露到回环之外。 |
- |
CAMOFOX_EVALUATE_MAX_BODY_SIZE |
POST /tabs/:tabId/evaluate 的 JSON 请求体最大大小;其他 JSON 路由仍限制为 100kb。 |
1mb |
CAMOUFOX_EXECUTABLE |
使用外部 Camoufox 可执行文件,而非下载/启动内置缓存。必须指向带有同级资源的 Camoufox 包。 | - |
CAMOUFOX_EXECUTABLE_PATH |
CAMOUFOX_EXECUTABLE 的兼容别名 |
- |
CAMOFOX_EXECUTABLE_PATH |
CAMOUFOX_EXECUTABLE 的兼容别名 |
- |
CAMOFOX_DISABLE_DEFAULT_ADDONS |
设为 1/true 以跳过下载和启动默认的 uBlock Origin(UBO)插件。适用于 addons.mozilla.org 下载不稳定或不希望下载的部署场景(否则下载失败会留下损坏的插件缓存,从而阻止启动)。 |
0 |
CAMOFOX_COOKIES_DIR |
Cookie 文件的目录 | ~/.camofox/cookies |
CAMOFOX_UPLOADS_DIR |
允许 POST /tabs/:tabId/upload 文件附件的目录。该目录之外(包括符号链接逃逸)的路径将被拒绝。 |
~/.camofox/uploads |
CAMOFOX_PROFILE_DIR |
持久化会话配置文件的目录 | ~/.camofox/profiles |
CAMOFOX_TRACES_DIR |
会话跟踪压缩包的目录 | ~/.camofox/traces |
CAMOFOX_TRACES_MAX_BYTES |
单次跟踪的最大大小,若超出,下次启动时将被清除 | 52428800(50MB) |
CAMOFOX_TRACES_TTL_HOURS |
早于此时长的跟踪将在启动时被清除 | 24 |
MAX_SESSIONS |
最大并发浏览器会话数 | 50 |
MAX_TABS_PER_SESSION |
每个会话的最大标签页数 | 10 |
SESSION_TIMEOUT_MS |
会话无活动超时时间 | 1800000(30分钟) |
BROWSER_IDLE_TIMEOUT_MS |
空闲时关闭浏览器(0 = 永不关闭) | 300000(5分钟) |
CAMOFOX_INTERACTIVE |
交互式浏览器模式:desktop 打开真实的本地 Camoufox 窗口;off 保持正常的无头行为 |
off |
HANDLER_TIMEOUT_MS |
任何处理程序的最大执行时间 | 30000(30秒) |
MAX_CONCURRENT_PER_USER |
每个用户的并发请求上限 | 3 |
MAX_OLD_SPACE_SIZE |
Node.js V8 堆内存限制(MB) | 128 |
PROXY_STRATEGY |
代理模式:backconnect(旋转粘性会话)或留空(单一端点) |
- |
PROXY_PROVIDER |
会话格式的提供商名称(例如 decodo) |
decodo |
PROXY_HOST |
代理主机名或 IP(简单模式) | - |
PROXY_PORT |
代理端口(简单模式) | - |
PROXY_USERNAME |
代理认证用户名 | - |
PROXY_PASSWORD |
代理认证密码 | - |
PROXY_BACKCONNECT_HOST |
回连网关主机名 | - |
PROXY_BACKCONNECT_PORT |
回连网关端口 | 7000 |
PROXY_COUNTRY |
代理地理定位的目标国家 | - |
PROXY_STATE |
代理地理定位的目标州/地区 | - |
TAB_INACTIVITY_MS |
关闭空闲时长超过此值的标签页 | 300000(5分钟) |
CAMOFOX_CRASH_REPORT_ENABLED |
启用匿名崩溃/挂起遥测(设为 false 可禁用) |
true |
CAMOFOX_CRASH_REPORT_URL |
遥测端点(自托管端点) | https://camofox-telemetry.askjo.workers.dev/report |
CAMOFOX_CRASH_REPORT_REPO |
遥测相关问题的 GitHub 仓库 | jo-inc/camofox-browser |
CAMOFOX_CRASH_REPORT_RATE_LIMIT |
每小时最大遥测报告数 | 10 |
ENABLE_VNC |
启用 VNC 插件以实现交互式浏览器访问(1) |
- |
VNC_PASSWORD |
VNC 访问密码(生产环境推荐设置) | - |
NOVNC_PORT |
noVNC 网页界面端口 | 6080 |
交互式桌面浏览器
Camofox 默认以无头模式运行。在带有本地图形桌面的机器上,可选择开启可见的 Camoufox 窗口:
CAMOFOX_INTERACTIVE=desktop npm start
也可以在 camofox.config.json 中设置相同的偏好,然后重启服务器:
{
"interactive": { "mode": "desktop" }
}
环境变量会覆盖文件设置。将 CAMOFOX_INTERACTIVE=off 可恢复为正常的无头浏览行为。此模式面向使用同一台机器的个人用户,不会暴露远程浏览器控制服务。
架构
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)
会话在空闲30分钟后自动过期。浏览器本身在无活跃会话5分钟后关闭,并在下一次请求时重新启动。
当会话达到标签页上限时,最旧/使用最少的标签页会被自动回收,而不是返回错误——这样长时间运行的代理会话就不会走入死胡同。
安全模型
本节为使用者及自动化安全审查人员记录 camofox-browser 的安全边界。
代码隔离
所有 process.env 读取操作集中在 lib/config.js 中。所有 child_process 的使用位于 lib/launcher.js(服务器子进程)和 plugins/youtube/youtube.js(yt-dlp)中。主文件 server.js 包含路由处理程序,但零 process.env 读取和零 child_process 导入。没有任何单个文件将环境/凭据访问与网络发送相结合。
无内置机密
本包不包含任何凭据、私钥、API 令牌或签名密钥。所有机密均在运行时通过环境变量(CAMOFOX_API_KEY、CAMOFOX_ACCESS_KEY)提供,或者是 Cloudflare Worker 环境机密(遥测端点的 GitHub App 密钥)。
Cookie 导入默认禁用
Cookie 导入端点(POST /sessions/:userId/cookies)由 CAMOFOX_API_KEY 保护。如果未设置此环境变量,服务器将以 HTTP 403 拒绝所有 Cookie 导入请求。Cookie 文件从沙箱目录(~/.camofox/cookies/)读取,并带有路径遍历防护——尝试逃逸该目录的行为将被阻止。每个请求最多 500 个 Cookie,文件大小限制为 5MB。
访问控制
CAMOFOX_ACCESS_KEY 为所有路由(/health 除外)提供全局 Bearer 令牌认证。设置后,每个请求必须包含 Authorization: Bearer <key>。建议任何超出 localhost 的部署都启用此功能。
二进制下载
Camoufox 浏览器引擎(约 300MB)在 npm install 时由 camoufox-js 下载,该 npm 包由 Camoufox 项目 维护。下载源为官方 GitHub Releases,完整性验证由 camoufox-js 处理。无自定义下载 URL、无短链接、无原始 IP 地址。
遥测
匿名的崩溃/挂起遥测数据会发送至一个 Cloudflare Worker 端点。该端点的源代码位于本仓库中,可供审计。验证方式:对端点发起 GET /source 请求,将返回部署时的提交哈希和 sha256 值,方便你与仓库进行比对。报告器(lib/reporter.js L28-290)采用了极为谨慎的匿名化处理:私有域名经过 HMAC 哈希(不可逆),路径会被剥离,令牌/IP/邮箱信息均被脱敏。页面内容、Cookie 或用户数据绝不会被发送。可通过设置 CAMOFOX_CRASH_REPORT_ENABLED=false 来禁用,或通过 CAMOFOX_CRASH_REPORT_URL 指定你自己的端点。
会话持久化
持久化插件会将 Cookie 和 localStorage 保存至 ~/.camofox/profiles/<hashed-userId>/ 目录,从而确保已认证的会话在浏览器重启后依然有效。用户 ID 经过哈希处理后用作目录名称。如需禁用,可在 camofox.config.json 中将 persistence 从插件数组中移除。
网络访问
出站连接包括:(1)代理所导航的 URL(核心功能),(2)遥测端点(匿名数据,可选择退出)。入站连接:REST API 监听于 9377 端口,默认绑定所有网络接口,或可通过 CAMOFOX_BIND_HOST 指定绑定地址,并可选地通过 CAMOFOX_ACCESS_KEY 进行访问保护。
子进程使用
可能会启动两个子进程:(1)Camoufox 浏览器引擎(核心功能,lib/launcher.js),(2)用于 YouTube 转录文本提取的 yt-dlp(可选功能,plugins/youtube/youtube.js)。两者均在与路由处理器隔离的独立文件中运行。
测试
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 output
npm
npm install @askjo/camofox-browser
致谢
- Camoufox —— 基于 Firefox 的浏览器,内置 C++ 反检测能力
- 向 Camoufox 原作者 daijro 捐赠
- OpenClaw —— 开源 AI 智能体框架
加密货币诈骗警告
随着该项目逐渐受到关注,一些居心不良的人开始利用名为“Camofox”的加密代币从事不法活动。Camofox 并非加密货币项目,也永远不会成为加密货币项目。 任何以 Camofox 名义发行的代币、币种或 NFT 均与我们无关。
许可证
MIT
项目介绍
AI 智能体专用无头浏览器自动化服务器,可访问通常被屏蔽的网站【此简介由AI生成】
