小马的 AI 工具集

隐身浏览

面向 AI Agent 的隐身无头浏览器,绕过 Cloudflare 与反爬,可替代 Puppeteer/Playwright

隐身浏览
类型 8,262 星标 更新 2026-08-02 许可 MIT 原仓库 主页
camofox-browser 图标

camofox-browser

面向 AI 代理的反检测浏览器服务器,基于 Camoufox 构建

许可证: MIT GitHub stars npm 版本 GitHub 最后提交

站在强大的 Camoufox 肩膀上——一个在 C++ 层面进行指纹伪造的 Firefox 分支。


Jo 标志

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 被拦截。Headless Chrome 被指纹识别。隐身插件成为指纹本身。

Camoufox 在 C++ 实现层面 修补 Firefox——navigator.hardwareConcurrency、WebGL 渲染器、AudioContext、屏幕几何信息、WebRTC——所有内容在 JavaScript 触及之前就被伪造。没有 shim、没有包装器、没有痕迹。

该项目将该引擎封装为专为代理构建的 REST API:可访问性快照替代臃肿的 HTML、用于点击的稳定元素引用,以及针对常见网站的搜索宏。

功能

  • C++ 反检测 - 绕过 Google、Cloudflare 和大多数机器人检测
  • 元素引用 - 稳定的 e1e2e3 标识符,用于可靠交互
  • 令牌高效 - 可访问性快照比原始 HTML 小约 90%
  • 在任何地方运行 - 延迟启动浏览器 + 空闲时关闭,空闲时内存占用约 40MB。设计用于与你的其余堆栈共享同一台机器——树莓派、5 美元 VPS、共享基础设施。
  • 会话隔离 - 每个用户独立的 cookies/存储
  • Cookie 导入 - 注入 Netscape 格式的 cookie 文件,用于认证浏览
  • 文件上传 - 从配置的上传目录附加文件,无需原生 OS 对话框
  • 代理 + 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-dlpYouTube 转录提取(快速路径)pip install yt-dlpbrew 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  # 首次运行时下载 Camoufox(约 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_PATHCAMOFOX_EXECUTABLE_PATH。这对 NixOS 路径(如 /nix/store/.../camoufox-bin)很有用;可执行文件必须来自包含 properties.jsonversion.jsonfontconfig/ 的 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-scriptsCAMOUFOX_EXECUTABLE 实现该目的。

Docker

附带的 Makefile 会自动检测你的 CPU 架构,并在 Docker 构建之外预先下载 Camoufox 和 yt-dlp 二进制文件,因此重建速度很快(约 30 秒 vs 约 3 分钟)。

# 构建并启动(自动检测架构:M1/M2 上为 aarch64,Intel 上为 x86_64)
make up

# 停止并移除容器
make down

# 强制重新构建(例如升级 VERSION/RELEASE 后)
make reset

# 仅下载二进制文件(不构建)
make fetch

# 显式覆盖架构或版本
make up ARCH=x86_64
make up VERSION=135.0.1 RELEASE=beta.24

Windows

在 Windows 上,make 不可用。请改用附带的 build.ps1 PowerShell 脚本:

# 构建并启动
.\build.ps1 up

# 停止并移除容器
.\build.ps1 down

# 仅构建镜像
.\build.ps1 build

# 强制重新构建
.\build.ps1 reset

# 仅下载二进制文件(不构建)
.\build.ps1 fetch

# 覆盖架构
.\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 foundset: 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

# 安装 Railway CLI,然后:
railway link
railway up

通过 Railway 面板或 CLI 设置密钥:

railway variables set CAMOFOX_API_KEY="your-generated-key"

使用

从浏览器导入 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. 让你的代理导入它们:

从 linkedin.txt 导入我的 LinkedIn Cookie

代理调用 camofox_import_cookies -> 读取文件 -> 使用 Bearer 令牌 POST 到服务器 -> Cookie 被注入浏览器会话。后续对 linkedin.com 的 camofox_create_tab 调用将自动携带认证信息。

工作原理

~/.camofox/cookies/linkedin.txt          (Netscape 格式,磁盘上)
        |
        v
camofox_import_cookies 工具               (解析文件,按域名过滤)
        |
        v  POST /sessions/:userId/cookies
        |  Authorization: Bearer <CAMOFOX_API_KEY>
        |  请求体: { cookies: [Playwright cookie 对象] }
        v
camofox 服务器                             (验证、清理、注入)
        |
        v  context.addCookies(...)
        |
Camoufox 浏览器会话                        (经过认证的浏览)
  • cookiesPath 相对于 Cookie 目录解析——禁止目录遍历逃逸
  • 每次请求最多 500 个 Cookie,文件大小限制 5MB
  • Cookie 对象会被清理,仅保留 Playwright 允许的字段

会话持久化

默认情况下,camofox 将每个用户的 Cookie 和 localStorage 持久化到 ~/.camofox/profiles/。会话在浏览器重启后仍然存在——只需登录一次(通过 Cookie 或 VNC),后续会话会自动恢复已认证状态。

~/.camofox/
|-- cookies/          # 引导 Cookie 文件(Netscape 格式)
\-- profiles/         # 持久化会话状态(自动管理)
    \-- <hashed-userId>/
        \-- storage_state.json

通过 CAMOFOX_PROFILE_DIR 覆盖目录,或在持久化插件配置中设置 "profileDir"。要禁用持久化,请在 camofox.config.json 中设置 "persistence": { "enabled": false }

默认情况下,存储状态仅包含 Cookie 和 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}'

当会话关闭时写入追踪。关闭会话以刷新它,然后列出、获取和查看:

# 关闭会话以刷新追踪
curl -X DELETE http://localhost:9377/sessions/agent1

# 列出追踪文件
curl http://localhost:9377/sessions/agent1/traces
# {"traces":[{"filename":"trace-2026-04-18T04-05-00-...zip","sizeBytes":42810,"createdAt":...}]}

# 下载(Content-Type: application/zip)
curl http://localhost:9377/sessions/agent1/traces/trace-2026-04-18T04-05-00-abc.zip > session.zip

# 在 Playwright 的 Trace Viewer 中查看
npx playwright show-trace session.zip

# 删除
curl -X DELETE http://localhost:9377/sessions/agent1/traces/trace-2026-04-18T04-05-00-abc.zip

为什么选择追踪而不是视频:Camoufox 基于 Firefox,而 Playwright 的 recordVideo 仅支持 Chromium。追踪在 Firefox 上有效,并且比视频提供更多信息(网络 + DOM + 控制台 + 截图)。

现有会话无法动态切换追踪(Tracing)设置。如需更改标记,请先执行 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 会自动设置 localetimezonegeolocation,使其与代理的出口 IP 匹配
  • 浏览器指纹(语言、时区、坐标)与代理位置保持一致
  • 未配置代理时,默认使用 en-USAmerica/Los_Angeles、旧金山坐标

Telemetry

浏览器自动化会以难以预测的方式失败——Cloudflare 验证、网站改版导致选择器失效、重定向循环、对话框风暴、渲染器崩溃。范围广,失败模式多样。没有遥测数据,唯一的信号就是“没成功”。

遥测为我们提供关于哪些网站失败如何失败以及失败频率的结构化数据,以便我们优先修复那些真正影响用户的问题模式。当出现以下情况时,它会自动创建 GitHub Issue:

  • 未捕获的异常导致进程崩溃
  • 事件循环停滞超过 5 秒(看门狗检测)
  • 挫败模式——同一标签页连续 3 次或更多失败(超时、上下文失效、导航中止)

每条报告包含失败类型、堆栈跟踪、标签页健康计数器(HTTP 状态码直方图、控制台错误数、请求失败数、重定向深度)以及目标 URL——所有内容均已匿名化。

工作方式

遥测数据被发送至一个轻量级的 Cloudflare Worker 端点 https://camofox-telemetry.askjo.workers.dev。该端点以环境变量形式持有 GitHub App 凭据——本包中不包含任何凭据

lib/reporter.js (客户端,无凭据)
    |  匿名化 -> POST https://camofox-telemetry.askjo.workers.dev/report
    v
Cloudflare Worker (持有 GitHub App 密钥)
    |  验证 -> 限速 -> 去重 -> 创建 GitHub Issue
    v
GitHub Issue 创建完成

端点源代码位于本仓库的 workers/crash-reporter/index.ts

验证

你无需信任我们——可以自行验证当前运行的端点:

# 1. 询问端点正在运行的代码
curl https://camofox-telemetry.askjo.workers.dev/source
# -> { "commit": "abc1234", "sha256": "e3b0c44...", "source": "https://github.com/..." }

# 2. 将 sha256 与本仓库中的源代码进行比较
sha256sum workers/crash-reporter/index.ts

# 3. 检查提交是否与 CI 部署的版本一致
#    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 或用户数据。

重复的 issue 通过堆栈签名检测,并会以 +1 评论的形式追加到现有 issue 中,而不会创建新 issue。

# 禁用遥测
export CAMOFOX_CRASH_REPORT_ENABLED=false

# 指向你自己的端点(见下文)
export CAMOFOX_CRASH_REPORT_URL=https://your-endpoint.example.com/report

# 调整限速(默认:每小时 10 次)
export CAMOFOX_CRASH_REPORT_RATE_LIMIT=5

自托管遥测端点

要将遥测报告归档到你自己的 GitHub 仓库中,而非 jo-inc/camofox-browser

  1. 创建 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}
  2. 部署端点 — 克隆此仓库并部署 worker:

    cd workers/crash-reporter
    # 编辑 wrangler.toml:将 account_id 设置为你的 Cloudflare 账户 ID
    npx wrangler deploy

    worker 是一个零 npm 依赖的单一 TypeScript 文件。它也可以在 Deno、Bun 或任何支持 Web Crypto API 的运行时上运行。

  3. 设置 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
  4. 将 camofox-browser 指向你的端点:

    export CAMOFOX_CRASH_REPORT_URL=https://your-worker.your-subdomain.workers.dev/report
  5. 验证:

    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)被排除在请求日志之外,以减少干扰。

基本浏览

# 创建标签页
curl -X POST http://localhost:9377/tabs \
  -H 'Content-Type: application/json' \
  -d '{"userId": "agent1", "sessionKey": "task1", "url": "https://example.com"}'

# 获取无障碍快照(含元素引用)
curl "http://localhost:9377/tabs/TAB_ID/snapshot?userId=agent1"
# -> { "snapshot": "[button e1] Submit  [link e2] Learn more", ... }

# 通过引用点击
curl -X POST http://localhost:9377/tabs/TAB_ID/click \
  -H 'Content-Type: application/json' \
  -d '{"userId": "agent1", "ref": "e1"}'

# 向元素输入文本
curl -X POST http://localhost:9377/tabs/TAB_ID/type \
  -H 'Content-Type: application/json' \
  -d '{"userId": "agent1", "ref": "e2", "text": "hello", "pressEnter": true}'

# 使用搜索宏导航
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=Nlimit=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_KEYPOST /stop 必需-
CAMOFOX_ACCESS_KEY如果设置,所有路由(除 /health、Cookie 导入和 /stop 外)都需要 Authorization: Bearer <key>。允许你在回环之外安全地暴露服务器。-
CAMOFOX_EVALUATE_MAX_BODY_SIZEPOST /tabs/:tabId/evaluate 的最大 JSON 请求体大小;其他 JSON 路由仍限制为 100kb1mb
CAMOUFOX_EXECUTABLE要使用的外部 Camoufox 可执行文件,而不是下载/启动捆绑的缓存。必须指向带有同级资源的 Camoufox 包。-
CAMOUFOX_EXECUTABLE_PATHCAMOUFOX_EXECUTABLE 的兼容别名-
CAMOFOX_EXECUTABLE_PATHCAMOUFOX_EXECUTABLE 的兼容别名-
CAMOFOX_DISABLE_DEFAULT_ADDONS设置为 1/true 以跳过下载和启动默认的 uBlock Origin (UBO) 插件。适用于 addons.mozilla.org 下载不可靠或不需要的部署(否则下载失败会导致损坏的插件缓存,阻止启动)。0
CAMOFOX_COOKIES_DIRCookie 文件目录~/.camofox/cookies
CAMOFOX_UPLOADS_DIR允许 POST /tabs/:tabId/upload 文件附件的目录。路径超出此目录(包括符号链接逃逸)将被拒绝。~/.camofox/uploads
CAMOFOX_PROFILE_DIR持久化会话配置文件目录~/.camofox/profiles
CAMOFOX_TRACES_DIR会话跟踪 zip 文件目录~/.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分钟)
HANDLER_TIMEOUT_MS任何处理器的最大时间30000 (30秒)
MAX_CONCURRENT_PER_USER每个用户的并发请求上限3
MAX_OLD_SPACE_SIZENode.js V8 堆限制(MB)128
PROXY_STRATEGY代理模式:backconnect(轮换粘性会话)或空白(单一端点)-
PROXY_PROVIDER会话格式的提供商名称(例如 decododecodo
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遥测 issue 的 GitHub 仓库jo-inc/camofox-browser
CAMOFOX_CRASH_REPORT_RATE_LIMIT每小时最大遥测报告数10
ENABLE_VNC启用 VNC 插件以进行交互式浏览器访问(1-
VNC_PASSWORDVNC 访问密码(建议生产环境使用)-
NOVNC_PORTnoVNC 网页界面端口6080

架构

Browser Instance (Camoufox)
\-- User Session (BrowserContext) - 隔离的 cookies/存储
    |-- 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_KEYCAMOFOX_ACCESS_KEY)提供,或者属于 Cloudflare Worker 环境机密(遥测端点 GitHub App 密钥)。

Cookie 导入端点(POST /sessions/:userId/cookies)受 CAMOFOX_API_KEY 保护。如果未设置此环境变量,服务器将拒绝所有 Cookie 导入请求并返回 HTTP 403。Cookie 文件从一个沙盒目录(~/.camofox/cookies/)读取,并具有路径遍历防护——试图逃逸该目录的操作会被阻止。每个请求最多 500 个 Cookie,文件大小限制为 5MB。

访问控制

CAMOFOX_ACCESS_KEY 为所有路由(/health 除外)提供全局 Bearer 令牌认证。设置后,每个请求必须包含 Authorization: Bearer <key>。建议在 localhost 之外的任何部署中使用。

二进制文件下载

Camoufox 浏览器引擎(约 300MB)在 npm install 时由 camoufox-js 下载,这是一个由 Camoufox 项目 维护的 npm 包。它从 官方 GitHub 发布版 下载,完整性验证由 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 中从 plugins 数组中移除 persistence 来禁用。

网络访问

出站连接至:(1) 代理导航到的 URL(核心功能),(2) 遥测端点(匿名化,可选择退出)。入站:端口 9377 上的 REST API,默认绑定到所有接口,或者在配置 CAMOFOX_BIND_HOST 时绑定到指定接口,并可选地受 CAMOFOX_ACCESS_KEY 保护。

子进程使用

可能启动两个子进程:(1) Camoufox 浏览器引擎(核心功能,lib/launcher.js),(2) 用于 YouTube 字幕提取的 yt-dlp(可选,plugins/youtube/youtube.js)。两者均在与路由处理器分离的专用文件中隔离。

测试

npm test              # 全部测试
npm run test:e2e      # 仅端到端测试
npm run test:live     # 实时站点测试(Google、macros)
npm run test:debug    # 附带服务器输出

npm

npm install @askjo/camofox-browser

致谢

加密货币诈骗警告

随着本项目获得关注,一些可疑的人正在用名为 “Camofox” 的加密货币代币做可疑的事情。Camofox 不是一个加密货币项目,也永远不会是。 任何使用 Camofox 名称的代币、币或 NFT 都与我们无关。

许可证

MIT

在 GitHub 查看完整项目