Camofox浏览器服务器
AI代理的防检测浏览器服务器-包装的TypeScript REST API 伪装狐 隐形浏览器引擎
  ](package.json) ](https://www.npmjs.com/package/camofox-browser)
目录
为什么选择CamoFox?
问题标准浏览器自动化(Puppeteer、Playwright、Selenium)很容易被现代反机器人系统检测到。JavaScript级别的补丁很脆弱,很快就会被绕过。
解决方案:CamoFox浏览器服务器包装 伪装狐,一个Firefox分叉 C++引擎级指纹欺骗没有JavaScript注入——反检测发生在浏览器引擎级别。
| 功能 | 木偶师/剧作家 | CamoFox浏览器服务器 |
|---|---|---|
| 反检测 | JavaScript补丁(脆弱) | C++引擎级别(健壮) |
| 指纹欺骗 | 有限 | 完全(引擎级别) |
| 令牌效率 | 原始HTML/屏幕截图 | 可访问性快照(较小+结构化) |
| 集成 | 直接SDK | 适用于任何语言/AI代理的REST API |
| AI代理支持 | 多种多样 | MCP+OpenClaw兼容 |
特性
- C++反检测 --伪装引擎级别的指纹欺骗(不是JS注入)
- REST API --用于浏览器自动化和AI代理集成的语言无关HTTP端点
- 多会话 --并发隔离浏览器上下文
userId(默认值:最多50个会话,最多10个选项卡/会话) - 持久浏览器配置文件 --每个用户都会获得一个专用的Firefox配置文件。Cookie、localStorage、IndexedDB和所有浏览器存储在会话之间自动持久。
- 地理预设 --8个内置区域预设(区域设置/时区/地理位置)+自定义预设文件
- 会话级代理/地理覆盖 --通过命名配置文件或原始凭据进行每会话代理配置,具有混合地理模式(
explicit-wins或proxy-locked) - 14搜索宏 --谷歌、YouTube、亚马逊、Reddit(搜索+子版块JSON)、维基百科、推特、Yelp、Spotify、网飞、领英、Instagram、TikTok、Twitch
- 元素参考 --带有稳定注释的可访问性快照
eN用于精确交互的元素参考 - Cookie持久性 --将Netscape/Playwright风格的Cookie导入会话(仅在以下情况下需要承载身份验证
CAMOFOX_API_KEY已设置) - OpenClaw插件 --OpenClaw兼容端点(
/start,/tabs/open,/act等等) - TypeScript --严格模式、键入请求形状、模块化Express路线
- YouTube转录提取 -yt-dlp+浏览器回退(服务级别;当前没有公开的公共API路由)
- 快照分页 --基于偏移的大页面快照窗口
- 图片列表路线 --通过具有选择器、扩展、延迟加载和blob分辨率控制的共享资源提取器进行仅图像提取
- 结构化提取 -在没有任意JavaScript的情况下,通过核心API、CLI和OpenClaw进行确定性方案驱动的JSON提取
- 浏览器健康监控 --具有恢复/降级状态跟踪功能的健康探针
- 🖥️ 命令行接口命令模式 --50多个基于终端的浏览器自动化命令
- 🔐 认证保险库 --AES-256-GCM加密凭证存储(LLM安全)
- 📜 管道脚本 --从文件执行命令脚本
- 🔍 控制台捕获 --捕获和过滤浏览器控制台消息和未捕获的错误
- 📼 剧作家追踪 --记录并导出Playwright跟踪以进行调试
- 🗂️ 跟踪工件管理 --列出、下载和删除每个用户会话的托管跟踪ZIP
预览状态
CamoFox浏览器服务器已安装 预览 (第一阶段)。预览版可用于浏览器自动化和代理集成,但带有特定的兼容性承诺和明确的非目标。
预览意味着什么
- 如今,REST API和CLI可用于代理工作流; CamoFox MCP 可作为外部配套集成使用
- 次要版本之间可能会添加新功能
- 为重命名或移动的端点维护向后兼容的别名(请参见 兼容性政策)
- 本地状态(配置文件、注册表、会话)使用带有故障关闭完整性检查的版本化格式
什么预览不能保证
- 冻结API表面 --端点行为、请求形状或响应格式可能会在次要版本之间发生变化
- 自动本地状态迁移 --浏览器配置文件、下载注册表和会话文件使用版本化的sidecar格式;不兼容的升级需要手动重置(请参阅 地方政府复苏)
- 降级安全 --回滚到旧版本可能需要清除本地状态
- 固定GA时间表 --晋升为GA需要满足循证退出标准,而不是日历日期
兼容性政策
在预览期间,CamoFox遵循 仅添加弃用模型:
- 遗留别名 (例如。,
listItemId一起接受sessionKey,OpenClaw/act路由到核心端点)继续与它们的替代品一起工作 - 已弃用的字段 被默默地接受;在GA或有记录的迁移窗口并在CHANGELOG中提前通知之前,不得删除
- 没有现有端点 在次要版本中被删除——删除仅在具有事先CHANGELOG通知的主要版本中发生
地方政府复苏
浏览器配置文件、下载注册表和CLI会话文件使用版本化的sidecar格式。升级CamoFox时:
- 兼容版本:正常状态负载
- 不兼容或损坏状态:服务器拒绝加载不兼容的配置文件和下载注册表;CLI拒绝不兼容的已保存会话文件。两者都记录了具有特定恢复路径的可操作错误。
- 恢复:删除错误消息中指示的受影响的配置文件目录、会话文件或下载注册表。下次使用时将重新创建干净状态。
支持的Sidecar包括有限的前向迁移路径(例如指纹v0→ v1);当给定版本不存在迁移路径时,服务器拒绝加载文件并记录可操作的恢复消息。没有静默修复或降级路径——这种故障关闭的默认设置可以防止数据损坏,但代价是手动干预不受支持的版本跳转。
快速开始
来源
git clone https://github.com/redf0x1/camofox-browser.git
cd camofox-browser
npm install
npm run build
npm start使用npm(CLI)
npm install -g camofox-browser
# Start the server
camofox-browser
# Or use the CLI for browser automation
camofox open https://example.com
camofox snapshot
camofox click e5看 命令行界面 以获取完整的命令参考。
使用Docker
Docker镜像: ghcr.io/redf0x1/camofox-browserdocker build -t camofox-browser .
docker run -d \
--name camofox-browser \
-p 9377:9377 \
-p 6080:6080 \
-e CAMOFOX_HOST=0.0.0.0 \
-e CAMOFOX_API_KEY=change-me \
-v ~/.camofox:/home/node/.camofox \
camofox-browser要在容器重启期间持久化浏览器配置文件(Cookie、localStorage、IndexedDB等),请保持上面显示的卷装载。
使用Docker Compose
services:
camofox-browser:
build: .
ports:
- "9377:9377"
environment:
CAMOFOX_HOST: "0.0.0.0"
CAMOFOX_PORT: "9377"
# Required when CAMOFOX_HOST is non-loopback
CAMOFOX_API_KEY: "change-me"
# CAMOFOX_ADMIN_KEY: "change-me"
# Optional: proxy routing (also enables Camoufox geoip mode)
# PROXY_HOST: ""
# PROXY_PORT: ""
# PROXY_USERNAME: ""
# PROXY_PASSWORD: ""验证
curl http://localhost:9377/health
# {"ok":true,"engine":"camoufox","browserConnected":true}命令行界面
CamoFox Browser包含一个强大的CLI,可直接从终端实现浏览器自动化。CLI会在需要时自动启动服务器。
安装
# Global install (recommended)
npm install -g camofox-browser
# Or use npx (no install needed)
npx camofox-browser open https://example.com快速开始
camofox open https://example.com # Open a page in anti-detection browser
camofox snapshot # Get accessibility tree with element refs
camofox click e5 # Click element [e5]
camofox type e3 "hello world" # Type into element [e3]
camofox screenshot --output page.png # Save screenshot
camofox close # Close the tab核心命令
# Browser lifecycle
camofox open # Open URL in new tab
camofox close [tabId] # Close tab
camofox navigate # Navigate current tab to URL
# Inspection
camofox snapshot # Get accessibility tree with [eN] refs
camofox screenshot [--output file] # Take screenshot (saves to file)
camofox annotate # Screenshot + element ref overlay
camofox get-url # Get current page URL
camofox get-text # Get page text content
camofox get-links # Get all links on page
camofox get-tabs # List open tabs
camofox extract-structured @schema.json # Extract deterministic JSON from a schema
# Interaction
camofox click # Click element by ref
camofox type # Type text into element
camofox fill '[e1]="user" [e2]="pw"' # Fill multiple fields at once
camofox scroll # Scroll up/down/left/right
camofox select # Select dropdown option
camofox hover # Hover over element
camofox press # Press keyboard key
camofox drag # Drag element to target
# Navigation
camofox go-back # Browser back
camofox go-forward # Browser forward
camofox search "query" --engine google # Search (14 engines supported)
camofox eval "document.title" # Execute JavaScript
camofox wait [--timeout ms] # Wait for element文本输入: CamoFox对键入或填充的文本没有字符限制。短文本保持人性化以防检测,而长文本会自动切换到批量DOM插入,因此大输入不会截断。
会话管理
camofox session save # Save current browser state
camofox session load # Restore browser state
camofox session list # List saved sessions
camofox session delete # Delete saved sessionCookie管理
camofox cookie export # Export cookies to JSON file
camofox cookie import # Import cookies from JSON file认证保险库
使用AES-256-GCM加密在本地安全存储凭据。凭据是 从不 输出到stdout——对LLM代理自动化是安全的。
camofox auth save
[--url URL] # Save credentials (prompts for master password)
camofox auth load
# Show profile info (username only)
camofox auth list # List saved profiles (no secrets shown)
camofox auth delete
# Delete a profile
camofox auth change-password
# Change master password
# Inject credentials into a browser tab (LLM-safe)
camofox snapshot # Get element refs first
camofox auth load gmail --inject --username-ref e5 --password-ref e12安全: 主密码使用Argon2d-KDF(带PBKDF2回退)。Vault文件以0600权限存储。这 --inject 标志直接将凭据发送到浏览器——LLM代理永远看不到密码。管道脚本
从文件中执行多个命令以实现自动化工作流:
# Create a script
cat > login-flow.txt ` | `CAMOFOX_USER` |用户/配置文件ID| `cli-default` |
| `--port
` | `PORT` |服务器端口| `9377` |
| `--format ` |--|输出: `json`, `text`, `plain` | `text` |
| `-V, --version` |--|显示版本|--|
| `-h, --help` |--|显示帮助|--|
### 输出格式
camofox get-url --format json # {"url":"https://example.com"} camofox get-url --format text # URL: https://example.com camofox get-url --format plain # https://example.com
> **提示:** 使用 `--format json` 用于程序化解析和LLM代理集成。
## 安全
### 反检测
CamoFox使用 [伪装狐](https://github.com/daijro/camoufox),一个Firefox分叉 **C++级指纹欺骗**与基于Chromium的工具不同,CamoFox在谷歌、Cloudflare和其他反机器人服务上传递机器人检测。
### 认证保险库
- **AES-256-GCM** 加密 **Argon2d** 密钥推导(PBKDF2回退)
- 凭证 **从不** 出现在stdout中(对LLM代理管道安全)
- 存储的Vault文件 `0600` 权限
- 所有保管库操作都需要主密码
### LLM代理安全
- 这 `--inject` 标志直接将凭据发送到浏览器——编排CLI的LLM代理永远不会看到原始密码
- 输出格式设计用于安全解析,而不会暴露凭据
- 管道脚本可以引用身份验证配置文件,而无需嵌入机密
## 使用AI代理
CamoFox与AI编码代理和LLM驱动的自动化无缝协作:
### AI编码助理(推荐)
将CamoFox技能添加到您的AI编码助手中,以实现完全的浏览器自动化:
npx skills add redf0x1/camofox-browser
这适用于 **克劳德代码**, **法典**, **光标**, **Gemini CLI**, **GitHub Copilot**, **鹅**, **开源代码**, **帆板运动**,以及 [40+其他代理商](https://github.com/vercel-labs/skills#supported-agents).
**可用技能:**
|技能|专注|最适合|
|-------|-------|----------|
| `camofox-browser` |全面覆盖(CLI+neneneba API+OpenClaw)|完整参考|
| `camofox-cli` |仅限CLI(50多个命令)|终端优先工作流|
| `dogfood` |QA测试工作流程|系统化web应用程序测试|
| `gemini-image` |Gemini图像生成| AI图像自动化|
| `reddit` |Reddit自动化| Reddit发布/评论|
安装程序将提示您选择要配置哪些技能和代理。
#### 克劳德代码
npx skills add redf0x1/camofox-browser
Installs to .claude/skills/camofox-browser/SKILL.md
#### Cursor/GitHubCopilot/Codex
npx skills add redf0x1/camofox-browser
Installs to .agents/skills/ directory
> **提示:** 技能从仓库中符号链接,因此它们保持最新状态。不要手动复制 `SKILL.md` 文件夹。
### MCP集成(推荐)
### CLI集成
AI代理可以使用CLI `--format json` 对于结构化输出:
camofox open https://example.com # Open page camofox snapshot --format json # Get structured element tree camofox click e5 # Interact with elements camofox auth load gmail --inject --username-ref e5 --password-ref e12 # Safe credential injection
### 管道自动化
创建AI代理可以执行的可重用自动化脚本:
camofox run automation-flow.txt # Execute multi-step workflow
## 建筑
AI Agent (MCP / OpenClaw / REST Client) │ ▼ HTTP REST API (port 9377) ┌──────────────────────────────────────────┐ │ CamoFox Browser Server │ │ (Express + TypeScript) │ ├──────────────────────────────────────────┤ │ Routes Services │ │ ├── Core API ├── Browser │ │ └── OpenClaw compat ├── Session │ │ └── Tab ops │ ├──────────────────────────────────────────┤ │ Camoufox Engine (anti-detect) │ │ Firefox fork + engine-level spoofing │ └──────────────────────────────────────────┘
### 持久配置文件(v1.3.0)
- 每 `userId` 在自己的持久Firefox进程/上下文中运行(由 `launchPersistentContext(userDataDir)`)
- 配置文件数据存储在 `~/.camofox/profiles/{userId}/` (通过以下方式覆盖 `CAMOFOX_PROFILES_DIR`)
- 空闲用户上下文通过LRU驱逐关闭(配置文件数据保留在磁盘上)
## API 参考
基本URL: `http://localhost:9377`
> **安全默认值:** `CAMOFOX_HOST` 现在默认为 `127.0.0.1`。如果绑定超出环回(例如 `0.0.0.0` 在Docker或PaaS中), `CAMOFOX_API_KEY` 启动时需要。在非环回绑定中,默认情况下会阻止环回/私有/链路本地/元数据主机上的导航目标,除非您明确设置 `CAMOFOX_ALLOW_PRIVATE_NETWORK=true`。如果您也配置 `PROXY_HOST`/`PROXY_PORT`,暴露的部署必须选择加入 `CAMOFOX_ALLOW_PRIVATE_NETWORK=true` 直到代理端私有目标验证存在。
### API文档
Camofox浏览器API包括OpenAPI 3.1.0文档,用于运输路线表面的代表性子集:
- **交互式API资源管理器**: [http://localhost:9377/api/docs](http://localhost:9377/api/docs) --带有实时请求测试的Swagger UI
- **OpenAPI规范**: [http://localhost:9377/openapi.json](http://localhost:9377/openapi.json) --机器可读OpenAPI 3.1.0规范
OpenAPI规范涵盖了核心和OpenClaw端点的代表性子集,包括请求模式、响应形状、身份验证要求和验证规则。
### 核心终点
注意:对于任何以现有选项卡为目标的端点(`/tabs/:tabId/...`),服务器解析 `tabId` **在...之内 `userId` 范围**.如果你忽略了 `userId`,你通常会得到 `404 Tab not found`.
|方法|端点|描述|必需|身份验证|
|--------|----------|-------------|----------|------|
|职位| `/sessions/:userId/cookies` |将cookie导入用户会话(Playwright cookie对象)|路径: `userId`;主体: `{ "cookies": Cookie[] }` |有条件: `Authorization: Bearer $CAMOFOX_API_KEY` |
|得到| `/health` |健康检查(也预启动浏览器)|无|无|
|得到| `/presets` |列出可用的地理预设(内置+自定义)|无|无|
|职位| `/tabs` |创建新选项卡(支持 `preset` +每个字段覆盖)|正文: `userId` + (`sessionKey` 或 `listItemId`)|有条件: `Authorization: Bearer $CAMOFOX_API_KEY` |
|得到| `/tabs?userId=...` |列出用户的所有选项卡(与OpenClaw兼容的响应形状)|查询: `userId` |没有|
|职位| `/tabs/:tabId/navigate` |导航到URL或展开搜索 `macro` + `query` |主体: `userId` + (`url` 或 `macro`)|有条件: `Authorization: Bearer $CAMOFOX_API_KEY` |
|得到| `/tabs/:tabId/snapshot?userId=...` |辅助功能快照注释为 `eN` 元素引用|查询: `userId` |没有|
|职位| `/tabs/:tabId/wait` |等待页面准备就绪(DOM+可选网络空闲)|正文: `userId` |有条件: `Authorization: Bearer $CAMOFOX_API_KEY` |
|职位| `/tabs/:tabId/click` |点击方式 `ref` (例如。 `e12`)或CSS `selector` |主体: `userId` + (`ref` 或 `selector`)|有条件: `Authorization: Bearer $CAMOFOX_API_KEY` |
|职位| `/tabs/:tabId/type` |按以下方式键入元素 `ref` 或CSS `selector` |主体: `userId` + (`ref` 或 `selector`) + `text` |有条件: `Authorization: Bearer $CAMOFOX_API_KEY` |
|职位| `/tabs/:tabId/press` |按下某个键(例如。 `Enter`, `Escape`)|正文: `userId` + `key` |有条件: `Authorization: Bearer $CAMOFOX_API_KEY` |
|职位| `/tabs/:tabId/scroll` |按像素向上/向下/向左/向右滚动|正文: `userId` |有条件: `Authorization: Bearer $CAMOFOX_API_KEY` |
|职位| `/tabs/:tabId/scroll-element` |将特定元素滚动到视图中|Body:userId,ref/selector |条件: `Authorization: Bearer $CAMOFOX_API_KEY` |
|职位| `/tabs/:tabId/back` |返回|正文: `userId` |有条件: `Authorization: Bearer $CAMOFOX_API_KEY` |
|职位| `/tabs/:tabId/forward` |前进|正文: `userId` |有条件: `Authorization: Bearer $CAMOFOX_API_KEY` |
|职位| `/tabs/:tabId/refresh` |刷新|正文: `userId` |有条件: `Authorization: Bearer $CAMOFOX_API_KEY` |
|得到| `/tabs/:tabId/links?userId=...&limit=50&offset=0` |提取链接(分页)|查询: `userId` |没有|
|得到| `/tabs/:tabId/images?userId=...` |列出提取的图像|查询: `userId` |有条件: `Authorization: Bearer $CAMOFOX_API_KEY` |
|得到| `/tabs/:tabId/screenshot?userId=...&fullPage=true` |屏幕截图(PNG字节)|查询: `userId` |没有|
|得到| `/tabs/:tabId/stats?userId=...` |标签统计+访问过的网址|查询: `userId` |没有|
|删除| `/tabs/:tabId` |关闭选项卡(需要JSON正文: `{ "userId": "..." }`)|正文: `userId` |有条件: `Authorization: Bearer $CAMOFOX_API_KEY` |
|删除| `/tabs/group/:listItemId` |关闭选项卡组(需要JSON正文: `{ "userId": "..." }`)|正文: `userId` |有条件: `Authorization: Bearer $CAMOFOX_API_KEY` |
|删除| `/sessions/:userId` |关闭用户的所有会话|路径: `userId` |有条件: `Authorization: Bearer $CAMOFOX_API_KEY` |
|职位| `/sessions/:userId/toggle-display` |切换显示模式(无头/有头/虚拟)|路径: `userId`;主体: `{ "headless": true\|false\|"virtual" }` |有条件: `Authorization: Bearer $CAMOFOX_API_KEY` |
|得到| `/tabs/:tabId/cookies` |导出选项卡Cookie |查询: `userId` |有条件: `Authorization: Bearer $CAMOFOX_API_KEY` |
|得到| `/tabs/:tabId/downloads` |列表选项卡下载|查询: `userId` |没有|
|得到| `/users/:userId/downloads` |列出用户下载|路径: `userId` |没有|
|得到| `/downloads/:downloadId` |下载元数据|查询: `userId` |没有|
|得到| `/downloads/:downloadId/content` |流式下载内容|查询: `userId` |没有|
|删除| `/downloads/:downloadId` |删除跟踪下载|正文或查询: `userId` |有条件: `Authorization: Bearer $CAMOFOX_API_KEY` |
|职位| `/tabs/:tabId/extract-resources` |提取可下载资源|正文: `userId` |有条件: `Authorization: Bearer $CAMOFOX_API_KEY` |
|职位| `/tabs/:tabId/batch-download` |批量下载资源|正文: `userId` |有条件: `Authorization: Bearer $CAMOFOX_API_KEY` |
|职位| `/tabs/:tabId/resolve-blobs` |将blob URL解析为base64 |正文: `userId` + `urls[]` |没有|
|职位| `/tabs/:tabId/trace/start` |开始跟踪记录|正文: `userId` |有条件: `Authorization: Bearer $CAMOFOX_API_KEY` |
|职位| `/tabs/:tabId/trace/stop` |停止并保存跟踪ZIP |正文: `userId` |有条件: `Authorization: Bearer $CAMOFOX_API_KEY` |
|职位| `/tabs/:tabId/trace/chunk/start` |开始跟踪块|正文: `userId` |有条件: `Authorization: Bearer $CAMOFOX_API_KEY` |
|职位| `/tabs/:tabId/trace/chunk/stop` |停止块并保存ZIP |正文: `userId` |有条件: `Authorization: Bearer $CAMOFOX_API_KEY` |
|得到| `/tabs/:tabId/trace/status` |检查跟踪状态|查询: `userId` |有条件: `Authorization: Bearer $CAMOFOX_API_KEY` |
|得到| `/sessions/:userId/traces` |列出用户的托管跟踪ZIP |路径: `userId` |有条件: `Authorization: Bearer $CAMOFOX_API_KEY` |
|得到| `/sessions/:userId/traces/:filename` |下载托管跟踪ZIP |路径: `userId`, `filename` |有条件: `Authorization: Bearer $CAMOFOX_API_KEY` |
|删除| `/sessions/:userId/traces/:filename` |删除托管跟踪ZIP |路径: `userId`, `filename` |有条件: `Authorization: Bearer $CAMOFOX_API_KEY` |
|得到| `/tabs/:tabId/console` |获取控制台消息|查询: `userId` |有条件: `Authorization: Bearer $CAMOFOX_API_KEY` |
|得到| `/tabs/:tabId/errors` |获取未捕获的JS错误|查询: `userId` |有条件: `Authorization: Bearer $CAMOFOX_API_KEY` |
|职位| `/tabs/:tabId/console/clear` |清除控制台+错误|正文或查询: `userId` |有条件: `Authorization: Bearer $CAMOFOX_API_KEY` |
|职位| `/tabs/:tabId/extract-structured` |从结构化模式中提取确定性JSON |正文: `userId` + `schema` |有条件: `Authorization: Bearer $CAMOFOX_API_KEY` |
### 切换显示模式
POST /sessions/:userId/toggle-display {"headless": "virtual"}
**认证:** 有条件--需要 `Authorization: Bearer $CAMOFOX_API_KEY` 当 `CAMOFOX_API_KEY` 已设置。
在无头模式和头模式之间切换浏览器。当遇到验证码或需要视觉交互的问题时,切换到头部模式以显示浏览器窗口。
退货:
{"ok": true, "headless": "virtual", "vncUrl": "http://localhost:6080/vnc.html?autoconnect=true&resize=scale&token=...", "message": "Browser visible via VNC", "userId": "agent1"}
**注:** 这将重新启动浏览器上下文。所有选项卡都无效,但Cookie/身份验证状态通过持久配置文件保持不变。
### 浏览器查看器(noVNC)
当显示模式设置为 `"virtual"` 或 `false`,服务器自动启动可通过web浏览器访问的VNC查看器。
1. Switch to virtual mode
POST /sessions/:userId/toggle-display {"headless": "virtual"}
Response includes vncUrl — open in browser to see Firefox
2. Solve CAPTCHA or interact with the browser
3. Switch back to headless
POST /sessions/:userId/toggle-display {"headless": true}
VNC automatically stops
VNC会话在2分钟后自动终止(可通过以下方式配置 `CAMOFOX_VNC_TIMEOUT_MS`).
### 评估JavaScript
在页面上下文中执行JavaScript表达式,并返回JSON可序列化结果。
认证:仅在以下情况下需要 `CAMOFOX_API_KEY` 在服务器上设置;否则不需要身份验证。
注意:异步表达式必须封装在异步IIFE中(例如, `(async () => { ... })()`).顶层 `await` 不支持。
POST /tabs/:tabId/evaluate {"userId": "agent1", "expression": "document.title"}
退货: `{"ok": true, "result": "Page Title", "resultType": "string", "truncated": false}`
### 评估JavaScript(扩展)
执行长时间运行的JavaScript表达式(最多300秒超时)。受API-key条件保护。价格有限。
认证:仅在以下情况下需要 `CAMOFOX_API_KEY` 在服务器上设置;否则不需要身份验证。
注意:异步表达式必须封装在异步IIFE中(例如, `(async () => { ... })()`).顶层 `await` 不支持。
POST /tabs/:tabId/evaluate-extended {"userId": "agent1", "expression": "(async () => { const response = await fetch('/api/data'); return await response.json(); })()", "timeout": 60000}
退货: `{"ok": true, "result": {...}, "resultType": "object", "truncated": false}`
### OpenClaw端点
与OpenClaw兼容的别名(由OpenClaw插件使用)。
|方法|端点|描述|必需|身份验证|
|--------|----------|-------------|----------|------|
|得到| `/` |状态(别名 `/health`)|无|无|
|职位| `/tabs/open` |打开选项卡(OpenClaw请求/响应形状)|正文: `userId` + `url` |有条件: `Authorization: Bearer $CAMOFOX_API_KEY` |
|职位| `/start` |启动浏览器引擎|无|无|
|职位| `/stop` |停止浏览器引擎|无| `x-admin-key: $CAMOFOX_ADMIN_KEY` |
|职位| `/navigate` |导航(OpenClaw请求形状: `targetId` 体内)|身体: `userId` + `targetId` + `url` |有条件: `Authorization: Bearer $CAMOFOX_API_KEY` |
|得到| `/snapshot?userId=...&targetId=...` |快照(OpenClaw响应形状)|查询: `userId` + `targetId` |没有|
|职位| `/act` |联合行动(`click`, `type`, `press`, `scroll`, `scrollIntoView`, `hover`, `wait`, `close`, `extractStructured`)|正文: `userId` + `targetId` + `kind` |有条件: `Authorization: Bearer $CAMOFOX_API_KEY` |
### 结构化提取
结构化提取从DOM模式返回确定性JSON,无需任意JavaScript。当你想要稳定的数据契约而不是临时的数据契约时,可以使用它 `evaluate()` 电话。
核心API:
curl -X POST "$CAMOFOX_URL/tabs/$TAB_ID/extract-structured" \ -H 'Content-Type: application/json' \ -d '{ "userId": "agent1", "schema": { "kind": "object", "fields": { "title": { "kind": "text", "selector": "h1", "required": true, "trim": true }, "products": { "kind": "list", "selector": ".product", "item": { "kind": "object", "fields": { "name": { "kind": "text", "selector": ".name", "required": true, "trim": true }, "href": { "kind": "url", "selector": "a.product-link", "attr": "href", "required": true } } } } } } }'
CLI:
camofox extract-structured @schema.json --user --format json
OpenClaw:
curl -X POST "$CAMOFOX_URL/act" \ -H 'Content-Type: application/json' \ -d '{ "kind": "extractStructured", "targetId": "tab-123", "userId": "agent1", "schema": { "kind": "object", "fields": { "title": { "kind": "text", "selector": "h1", "required": true } } } }'
笔记:
- 无效的架构在HTTP 400中失败
- 所需的运行时未命中导致整个HTTP 422请求失败 `fieldPath`
- 可选标量/对象/列表节点规范化为 `null` / `null` / `[]`
- 选择器必须是CSS;无XPath、任意JavaScript或AI提取
- 原资源开采和结构化开采故意分开
## 搜索宏
通过以下方式使用宏 `POST /tabs/:tabId/navigate` 随着 `{ "macro": "@google_search", "query": "..." }`.
|宏|引擎|
|-------|--------|
| `@google_search` 谷歌
| `@youtube_search` 油管
| `@amazon_search` |亚马逊|
| `@reddit_search` |Reddit(JSON)|
| `@reddit_subreddit` |Reddit子版块(JSON)|
| `@wikipedia_search` |维基百科|
| `@twitter_search` |推特/X|
| `@yelp_search` |Yelp|
| `@spotify_search` |Spotify|
| `@netflix_search` |Netflix|
| `@linkedin_search` |领英|
| `@instagram_search` |Instagram标签|
| `@tiktok_search` |试试看|
| `@twitch_search` |Twitch|
## 地理预设
内置预设(也可通过 `GET /presets`):
|预设|区域设置|时区|位置|
|--------|--------|----------|----------|
| `us-east` | `en-US` | `America/New_York` |纽约(40.7128,-74.0060)|
| `us-west` | `en-US` | `America/Los_Angeles` |洛杉矶(34.0522,-118.2437)|
| `japan` | `ja-JP` | `Asia/Tokyo` |东京(35.6895139.6917)|
| `uk` | `en-GB` | `Europe/London` |伦敦(51.5074,-0.1278)|
| `germany` | `de-DE` | `Europe/Berlin` |柏林(52.5200,13.4050)|
| `vietnam` | `vi-VN` | `Asia/Ho_Chi_Minh` |胡志明市(10.823106.6297)|
| `singapore` | `en-SG` | `Asia/Singapore` |新加坡(1.352103.8198)|
| `australia` | `en-AU` | `Australia/Sydney` |悉尼(-33.8688,151.2003)|
创建一个带有预设的选项卡:
curl -X POST http://localhost:9377/tabs \ -H 'Content-Type: application/json' \ -d '{"userId":"agent1","sessionKey":"task1","preset":"japan","url":"https://example.com"}'
自定义预设:设置 `CAMOFOX_PRESETS_FILE=/path/to/presets.json` (JSON对象;键成为预设名称)。
## 会话级代理和地理覆盖
CamoFox支持会话级代理和地理定位配置,其混合模型将服务器默认值与每个会话覆盖相结合。
### 代理配置模型
**服务器级基线** (通过环境变量):
- `PROXY_HOST`, `PROXY_PORT`, `PROXY_USERNAME`, `PROXY_PASSWORD` --作为所有会话的默认值应用
- 配置后启用迷彩地理IP模式
**会话级别覆盖** (通过 `POST /tabs` 或CLI):
- `proxyProfile` --从中选择一个命名的代理配置文件 `CAMOFOX_PROXY_PROFILES_FILE`
- `proxy` --提供原始代理字段(`host`, `port`, `username`, `password`)直接
- 会话级代理会覆盖该特定服务器的基线 `userId + sessionKey` 组合
**会话标识规则**:
- 相同的 `userId` 可能运行不同 `sessionKey` 与不同代理/地理配置并行的配置文件
- 相同的 `userId + sessionKey` 组合可以保持稳定的代理/地理标识——拒绝具有冲突代理/地理字段的请求
- 会话重用和清理范围代理/地理标识 `userId + sessionKey`,不仅 `userId`
### 地理模式行为
CamoFox提供了两种地理模式,用于控制显式地理字段(区域设置、时区、地理位置)如何与代理导出的地理进行交互:
**`geoMode=explicit-wins`** (默认):
- 显式地理字段(区域设置、时区、地理位置)仍然具有权威性
- 忽略代理导出的地理建议
- 无论代理位置如何,当您想要精确的地理控制时,请使用此模式
**`geoMode=proxy-locked`**:
- 拒绝与代理导出的地理冲突的显式地理字段
- 代理导出的地理信息具有权威性
- 使用此模式确保与代理退出位置的地理一致性
### CLI示例
具有命名配置文件的会话级代理:
camofox open https://example.com --proxy-profile tokyo-exit --user agent1
带有原始字段的会话级代理:
camofox open https://example.com \ --proxy-host proxy.example.com \ --proxy-port 8080 \ --proxy-username user \ --proxy-password pass \ --user agent1
将代理与地理模式结合:
camofox open https://example.com \ --proxy-profile london-exit \ --geo uk \ --geo-mode proxy-locked \ --user agent1
### API示例
使用具有明确地理位置的命名代理配置文件:
curl -X POST http://localhost:9377/tabs \ -H 'Content-Type: application/json' \ -d '{ "userId": "agent1", "sessionKey": "task1", "url": "https://example.com", "proxyProfile": "tokyo-exit", "preset": "japan", "geoMode": "explicit-wins" }'
使用带有代理锁定地理位置的原始代理字段:
curl -X POST http://localhost:9377/tabs \ -H 'Content-Type: application/json' \ -d '{ "userId": "agent1", "sessionKey": "task2", "url": "https://example.com", "proxy": { "host": "proxy.example.com", "port": 8080, "username": "user", "password": "pass" }, "geoMode": "proxy-locked" }'
### 命名代理配置文件
在JSON文件中定义代理配置文件并指向 `CAMOFOX_PROXY_PROFILES_FILE` 对于它:
{ "tokyo-exit": { "server": "http://tokyo.proxy.example.com:8080", "username": "user", "password": "pass" }, "london-exit": { "server": "http://london.proxy.example.com:8080" } }
然后在API请求或CLI命令中按名称使用配置文件。
## 环境变量
|变量|默认值|描述|
|----------|---------|-------------|
| `CAMOFOX_PORT` | `9377` |服务器端口|
| `PORT` |(可选)|可选端口env-var(PaaS中常见)|
| `NODE_ENV` | `development` |节点环境|
| `CAMOFOX_HOST` | `127.0.0.1` |服务器绑定主机。集 `0.0.0.0` 用于Docker/PaaS/网络曝光。非环回绑定需要 `CAMOFOX_API_KEY`. |
| `CAMOFOX_ADMIN_KEY` |(空)|必填 `POST /stop` (通过发送 `x-admin-key`) |
| `CAMOFOX_API_KEY` |(空)|通过以下方式保护受保护的端点(选项卡创建、导航、交互、会话管理、下载、图像提取、跟踪、控制台) `Authorization: Bearer` 设置时标题。每当需要时 `CAMOFOX_HOST` 将服务器暴露在环回之外。 |
| `CAMOFOX_ALLOW_PRIVATE_NETWORK` | `true` 在环回绑定时, `false` 否则|允许导航到环回/私有/链接本地/元数据目标。未设置为安全默认值;仅对有意需要内部网络可达性的可信部署启用。 |
| `CAMOFOX_HEADLESS` | `true` |显示模式: `true` (无头), `false` (标题), `virtual` (Xvfb)|
| `CAMOFOX_VNC_RESOLUTION` | `1920x1080x24` |虚拟Xvfb显示分辨率(`WIDTHxHEIGHTxDEPTH`) |
| `CAMOFOX_VNC_TIMEOUT_MS` | `120000` |自动停止前VNC会话的最大持续时间(毫秒)|
| `CAMOFOX_EVAL_EXTENDED_RATE_LIMIT_MAX` | `20` |每个窗口每个用户的最大评估扩展请求数|
| `CAMOFOX_EVAL_EXTENDED_RATE_LIMIT_WINDOW_MS` | `60000` |速率限制窗口持续时间(毫秒)|
| `CAMOFOX_COOKIES_DIR` | `~/.camofox/cookies` |OpenClaw插件cookie工具使用的目录|
| `CAMOFOX_PROFILES_DIR` | `~/.camofox/profiles` |配置文件存储目录(持久的每用户Firefox配置文件)|
| `CAMOFOX_DOWNLOADS_DIR` | `~/.camofox/downloads` |下载工件目录|
| `CAMOFOX_DOWNLOAD_TTL_MS` | `86400000` |下载元数据保留TTL|
| `CAMOFOX_MAX_DOWNLOAD_SIZE_MB` | `100` |最大单次下载大小|
| `CAMOFOX_MAX_BATCH_CONCURRENCY` | `5` |批量下载并发上限|
| `CAMOFOX_MAX_BLOB_SIZE_MB` | `5` |最大blob有效载荷大小|
| `CAMOFOX_MAX_DOWNLOADS_PER_USER` | `500` |每位用户下载记录上限|
| `CAMOFOX_CONSOLE_BUFFER_SIZE` | `1000` |每个选项卡控制台/错误消息缓冲区大小(最小 `100`) |
| `HANDLER_TIMEOUT_MS` | `30000` |处理程序超时回退|
| `MAX_CONCURRENT_PER_USER` | `3` |每个用户的并发操作|
| `CAMOFOX_VNC_BASE_PORT` | `6080` |noVNC/网络锁定基本端口|
| `CAMOFOX_VNC_HOST` | `localhost` |返回的URL中没有VNC主机|
| `CAMOFOX_CLI_USER` | `cli-default` |默认CLI用户id|
| `CAMOFOX_SERVER_PID_FILE` |(未设置)| CLI服务器管理器使用的可选守护程序PID文件路径|
| `CAMOFOX_IDLE_TIMEOUT_MS` | `1800000` |第1阶段空闲清理阈值(ms)|
| `CAMOFOX_IDLE_EXIT_TIMEOUT_MS` | `1800000` |第2阶段守护进程退出静默窗口(毫秒,默认值与第1阶段匹配)|
| `CAMOFOX_PRESETS_FILE` |(未设置)|可选的JSON文件定义/覆盖地理预设|
| `CAMOFOX_PROXY_PROFILES_FILE` |(未设置)|可选的JSON文件,定义会话级覆盖的命名代理配置文件|
| `CAMOFOX_SESSION_TIMEOUT` | `1800000` |会话空闲超时(毫秒)(分钟) `60000`) |
| `CAMOFOX_MAX_SESSIONS` | `50` |最大并发会话数|
| `CAMOFOX_MAX_TABS` | `10` |每个会话的最大选项卡数|
| `PROXY_HOST` |(空)|代理主机(服务器级默认值;启用代理路由)|
| `PROXY_PORT` |(空)|代理端口(服务器级默认)|
| `PROXY_USERNAME` |(空)|代理用户名(服务器级默认)|
| `PROXY_PASSWORD` |(空)|代理密码(服务器级默认值)|
| `CAMOFOX_MAX_SNAPSHOT_CHARS` | `80000` |截断前快照中的最大字符数|
| `CAMOFOX_MAX_SNAPSHOT_NODES` | `2000` |截断前最大可访问性快照节点数|
| `CAMOFOX_SNAPSHOT_TAIL_CHARS` | `5000` |截断快照末尾保留的字符|
| `CAMOFOX_BUILDREFS_TIMEOUT_MS` | `12000` |建筑图元引用超时|
| `CAMOFOX_TAB_LOCK_TIMEOUT_MS` | `30000` |获取标签锁超时|
| `CAMOFOX_TRACES_DIR` | `~/.camofox/traces` |管理剧作家跟踪工件目录|
| `CAMOFOX_TRACE_MAX_DURATION_MS` | `300000` |自动停止前的最大跟踪记录持续时间|
| `CAMOFOX_HEALTH_PROBE_INTERVAL_MS` | `60000` |健康探针检查间隔|
| `CAMOFOX_FAILURE_THRESHOLD` | `3` |健康状况恶化前的连续故障|
| `CAMOFOX_YT_DLP_TIMEOUT_MS` | `30000` |yt-dlp字幕提取超时|
| `CAMOFOX_YT_BROWSER_TIMEOUT_MS` | `25000` |浏览器转录回退超时|
| `CAMOFOX_OS` |(未设置)|可选的服务器范围迷彩操作系统覆盖(`windows`, `macos`, `linux`,或逗号分隔列表用于随机化)|
| `CAMOFOX_ALLOW_WEBGL` |(未设置)|可选的服务器范围WebGL覆盖;格式错误的值无法启动|
| `CAMOFOX_SCREEN_WIDTH` |(未设置)|可选屏幕宽度覆盖;仅适用于 `CAMOFOX_SCREEN_HEIGHT` |
| `CAMOFOX_SCREEN_HEIGHT` |(未设置)|可选屏幕高度覆盖;仅适用于 `CAMOFOX_SCREEN_WIDTH` |
| `CAMOFOX_HUMANIZE` |(未设置)|可选的服务器范围人性化覆盖|
> `CAMOFOX_OS` 和 `CAMOFOX_SCREEN_*` 是 **生成时间** 控件:它们只影响新生成的指纹,对现有指纹无效 `fingerprint.json` sidecar正在使用中。重置配置文件或删除 `fingerprint.json` 强制在新默认值下进行再生。 `CAMOFOX_ALLOW_WEBGL` 和 `CAMOFOX_HUMANIZE` 是 **发射时间** 覆盖并应用于每次浏览器启动,无论是否重用sidecar。
### 空闲生命周期策略
CamoFox实现了两阶段空闲生命周期,用于优雅的清理和守护进程退出:
**第一阶段——闲置清理**
- 之后 `CAMOFOX_IDLE_TIMEOUT_MS` 如果空闲时间不足(默认值:30分钟),服务器将运行清理以关闭空闲会话和选项卡
- 如果正在启动浏览器上下文或创建会话,则清理会延迟
- 新的交互活动(选项卡创建、导航、交互)取消任何待处理的清理
**第二阶段——守护进程退出**
- 第一阶段清理完成后,服务器将等待 `CAMOFOX_IDLE_EXIT_TIMEOUT_MS` (默认值:匹配第一阶段超时)
- 如果在此安静窗口期间没有发生新活动,则守护进程将优雅地退出
- 任何新的请求活动都会取消挂起的退出计时器
**活动检测**:
- 实时选项卡、启动浏览器上下文或分阶段会话创建被视为活动工作,并阻止清理
- 空会话(没有标签的会话)不会阻止清理,但会解除挂起的守护进程退出
- 新的交互式活动会重置清理和退出计时器
这种两阶段模型确保在守护进程退出之前进行清理,防止资源泄漏,同时允许服务器在完全空闲时干净地关闭。
## 部署
### Docker(推荐)
docker build -t camofox-browser . docker run -p 9377:9377 -p 6080:6080 \ -v ~/.camofox:/home/node/.camofox \ -e CAMOFOX_HOST=0.0.0.0 \ -e CAMOFOX_PORT=9377 \ -e CAMOFOX_API_KEY=change-me \ camofox-browser
### Fly.io
此回购包括一个启动器 `fly.toml` 对于一个命令部署。
fly launch fly deploy
### 铁路
- 创建新项目→ 从这个GitHub仓库部署
- 集 `CAMOFOX_HOST=0.0.0.0`
- 集 `CAMOFOX_API_KEY` 一个强烈的秘密
- 集 `CAMOFOX_PORT=9377` (铁路也将提供 `PORT`,支持)
- 确保服务公开端口 `9377`
### 渲染
- 创建新的Web服务→ 从这个GitHub仓库部署
- 使用Docker(推荐)并公开端口 `9377`
- 集 `CAMOFOX_HOST=0.0.0.0`
- 集 `CAMOFOX_API_KEY` 一个强烈的秘密
- 集 `CAMOFOX_PORT=9377` (或依赖Render `PORT`)
### 系统要求
- Node.js 20+
- 2GB+RAM(浏览器+上下文需要大量内存)
- Linux推荐用于生产环境;macOS适合开发
## 与一起使用
|项目|描述|
|---------|-------------|
| [CamoFox MCP](https://github.com/redf0x1/camofox-mcp) |用于Claude、Cursor、VS代码的MCP(模型上下文协议)服务器|
| [龙虾](https://openclaw.ai) |开源AI代理框架(包括兼容端点)|
| [伪装狐](https://github.com/daijro/camoufox) |反检测Firefox浏览器引擎|
## 项目结构
src/ ├── cli/ │ ├── commands/ # Command modules (core, navigation, interaction, etc.) │ │ ├── console.ts # Console capture commands │ │ └── trace.ts # Playwright tracing commands │ ├── vault/ # Auth vault (encryption, storage) │ ├── server/ # Server lifecycle management │ ├── transport/ # HTTP transport layer │ ├── output/ # Output formatting │ └── utils/ # Shared utilities ├── server.ts # Express app entry point ├── types.ts # Shared TypeScript interfaces ├── routes/ │ ├── core.ts # Core REST API (~42 endpoints) │ └── openclaw.ts # OpenClaw compatibility (~7 endpoints) ├── services/ │ ├── browser.ts # Browser lifecycle + persistent context pool │ ├── batch-downloader.ts # Batch download orchestrator │ ├── context-pool.ts # Browser context pool with LRU eviction │ ├── download.ts # Download tracking service │ ├── health.ts # Browser health tracking │ ├── resource-extractor.ts # Page resource extraction │ ├── session.ts # Session management + limits │ ├── tab.ts # Tab operations (snapshot/click/type/etc.) │ ├── tracing.ts # Playwright tracing service │ ├── vnc.ts # VNC/virtual display lifecycle │ └── youtube.ts # YouTube transcript extraction ├── middleware/ │ ├── auth.ts # API/admin auth helpers │ ├── errors.ts # Error handling │ ├── logging.ts # Structured logging │ └── rate-limit.ts # In-memory rate limiter └── utils/ ├── config.ts # Environment config parsing ├── cookies.ts # Cookie utilities ├── download-helpers.ts # Download helper functions ├── launcher.ts # Browser launcher utilities ├── macros.ts # Search macro expansion ├── presets.ts # Geo preset definitions/loader └── snapshot.ts # Snapshot truncation/windowing
## 贡献
看 [贡献.md](CONTRIBUTING.md)
## 学分
- [伪装狐](https://camoufox.com) -基于Firefox的浏览器,具有C++反检测功能
- [向迷彩服的原创创作者daijro捐款](https://camoufox.com/about/)
- [龙虾](https://openclaw.ai) -开源AI代理框架
## 许可证
[麻省理工学院](LICENSE)
## 加密诈骗警告
现在这个项目引起了人们的关注,人们正在用名为“Camofox”的加密代币做一些粗略的事情。 **Camofox不是一个加密项目,也永远不会是。** 任何使用Camofox名称的代币、硬币或NFT都与我们无关。