| name | browser-guide |
| description | Best practices for using the managed browser — handling login walls, CAPTCHAs, lazy-loaded content, paywalls, and tab cleanup. Target=camoufox 主力路径。 |
| metadata | {"openclaw":{"emoji":"🌐"}} |
Browser Best Practices
Follow these rules whenever you drive a browser against web pages.
0. 浏览器后端选择(先读这一节)
本 skill 默认主力路径是 target=camoufox——即全局可用的 camoufox-cli 命令。下方所有操作命令、示例、selector 都只针对 target=camoufox 写。
如果你当前是 target=host(existing-session 真机 Chrome + chrome-mcp relay)或 target=node(remote-cdp 远端 Chrome):
- 只按本 skill 列出的「流程 / 步骤 / 提示事项」执行——不要照搬下面的
camoufox-cli ... 命令、snapshot ref、eval 入参等具体操作和示例。
- 浏览器操作走你当前后端自带的浏览器工具语义(host: chrome-mcp relay;node: remote-cdp + playwright-core),按各后端自身约定调用即可。
- 何时有头 / 何时无头、登录流程顺序、CAPTCHA 处理原则、lazy-load 滚动节奏、paywall 等用户交互约定是后端无关的,照本 skill 执行。
0.1 camoufox-cli 基本用法
camoufox-cli --session <name> [--persistent] [--headed] [--json] <command> [args...]
--session <name>:会话隔离单元,同名 session 共享一个 profile 目录。涉及登录的平台用一个且只用一个持久化 session 名。
--persistent:冻结指纹到 ~/.camoufox-cli/profiles/<name>/camoufox-cli.json(首次生成后冻结)。持久化平台 session 必带;临时性 session(新闻等不登录站点)不带——走默认临时 profile,每次随机指纹,关闭自清。
--headed:有头模式。需要用户配合过验证码、扫码、收短信的,或者填表场景,必须 --headed。例外:微信公众号 wx_mp 可无头截含二维码区域截图发用户登录;微信视频号 wechat-channel / 微博 / 闲鱼等扫码登录页无法无头截 QR,必须 --headed 弹窗让用户在浏览器里手动扫码。其他场景,包括探活,都可以使用默认的无头模式。
--viewport <WxH>:固定窗口尺寸,如 1920x1080。camoufox 默认按指纹给移动端窗口比例,导致有头登录时二维码看不全;有头扫码登录(微博 / 闲鱼 / 视频号等)一律加 --viewport 1920x1080 强制桌面比例。业务无头操作无需此 flag。
--json:命令输出走 JSON 信封({ok, ...} / {error, ...}),agent 解析稳定,推荐常带。
- 命令集(含
upload / identity export):
open / back / forward / reload / url / title / close / snapshot / click / fill / type / select / check / hover / press / text / eval / screenshot / pdf / scroll / wait / tabs / switch / close-tab / sessions / cookies / install / upload / identity
fail-first 队列:同一 session 已有命令在跑时,新命令直接 fail,返回文本:
session <name> 正忙,请等待当前操作完成后再试
读到这条 fail 文本说明有其他进程在使用同名session,你应该等待一段时间后再重试,卡死用 camoufox-cli close --all 兜底 teardown。
0.2 snapshot ref 优先
camoufox-cli 的 snapshot 返回带 ref 的语义快照(@e1 @e2 …),后续 click / fill / type / upload / hover / press 全部优先传 ref,不要自己 hack CSS selector。找不到元素时先 snapshot 看真实 DOM 结构再决定 selector 改写,不要盲试。
0.3 用后即关(critical — 机器会被撑死)
每个 camoufox-cli --session <s> open 都会拉起一个独立 daemon + 完整 Firefox 实例(每个 200-400MB + 若干 content 进程)。不关就一直在(idle 60s 才自退)。一次任务里开几十个 session 又不 close,13GB 机器几分钟就死机(真实事故:72 open / 1 close)。
铁律:
- 临时性 session(搜索 / 抓取 / 不登录站点):用完立即
camoufox-cli --session <s> --json close。哪怕后面还要搜,也先 close 再开下一个,或干脆复用同一个 session 名(不要每次 search-$(date +%s) 起新名)——同名 session 复用同一个 daemon,不堆积。
- 持久化 session(登录态平台):登录/取数结束后也 close。登录态存在 profile 目录里(
~/.camoufox-cli/profiles/<name>/),daemon 退出不丢登录,下次 open 自动加载。持久化 ≠ 一直开着。
- 批量收尾:一个任务结束前,
camoufox-cli --json close --all 兜底清掉所有自己开的 session。
- 不要每条搜索一个唯一 session 名还不 close。这是已确认的死机模式。
源头已有兜底:daemon idle 60s 自退 + 全局并发 daemon 上限 8(超了驱逐最老的)。但 skill 侧仍必须自觉 close——兜底是最后防线,不是不关的理由。
1. Login Prompts
When a page shows a login wall, first identify which login mechanism is offered, then follow the matching procedure below.
General constraint: retry at most 2 times per login attempt — frequent retries risk account suspension.
1-A. Browser saved credentials
- Check whether the login form has auto-filled credentials from saved passwords. If so, use them.
- On failure, continue to 1-B / 1-C / 1-D as appropriate.
1-B. QR Code login
When the login page shows a QR code (WeChat Official Account backend, WeChat Channels, Xiaohongshu creator centre, X/Twitter, etc.):
camoufox-cli --session <s> --json screenshot /tmp/qr-<platform>.png 截下 QR 图(或 snapshot 拿到 QR 元素 ref 后用 eval 取其 src/data URI)。
- Send the QR code image to the user via message — send the image itself, not the local file path.
- Notify the user:
"[平台名称] 登录已失效(或首次使用),请用 [平台] APP 扫描以下二维码登录。扫码并在手机上点击确认后,回复"已扫码"。"
- Stop and wait for the user to reply "已扫码"、"好了"、"扫完了" or any equivalent confirmation before continuing.
- While waiting, poll the page every 3 seconds (
snapshot 看 URL 是否跳走 / QR 元素是否消失 / dashboard 是否出现). Auto-detected → resume immediately without waiting for user reply.
- If no scan within 3 minutes and no reply arrives, send: "扫码超时,将继续处理当前可访问的内容。" and proceed.
显式有头/无头模式场景规则:只有以下场景需要显式指定 camoufox-cli 的有头/无头参数:
- login-manager 登录(douyin / kuaishou / bilibili / xhs-publish / xhs-browse 5 平台)——强制
--headed,用户在浏览器手动扫码/短信/账号密码
- 需要用户手动过验证(captcha / 滑块 / 短信)——
--headed,用户才能在浏览器里手动操作
- web-form-fill 表单填报——强制
--headed,便于用户时刻观察填报情况、可随时介入纠正
其他场景默认走 camoufox 持久化 session,不显式指定有头/无头——camoufox-cli 默认行为即可。
wx_mp(公众号)无头截图 QR 是特例,适用于 wx-mp-hunter + wx-mp-engagement 两技能。视频号 / 微博 / 闲鱼等扫码登录页无法无头截 QR,必须 --headed --viewport 1920x1080 弹窗手动扫码(见各 skill 前置条件)。
1-C. SMS verification login
When the login page asks for a phone number and SMS verification code:
- Ask the user for the registered phone number for this platform:
"[平台名称] 需要手机验证码登录,请告知您在该平台注册的手机号。"
- Once received, enter the phone number and trigger the SMS code request. Attempt at most 2 times if the first trigger fails.
- Ask the user for the verification code:
"短信验证码已发送,请将收到的验证码回复给我。"
- Enter the code and complete login. If login fails, inform the user and proceed with accessible content — do not retry a third time.
1-D. Username / password login
When only a username + password form is available:
- Check for browser-saved credentials first (see 1-A).
- If none, ask the user for their preference:
"[平台名称] 需要账号密码登录,浏览器中未找到预存密码。请选择:① 您自行在浏览器中登录后告知我,② 告知用户名和密码由我代为登录。"
- If the user chooses ②, receive the credentials and attempt login. Retry at most 2 times on failure.
- If login fails after 2 attempts, inform the user and continue with accessible content.
1-E. Fallback — login not possible
If login cannot be completed for any reason (timeout, user unavailable, repeated failures):
- Do NOT stop or abort the task.
- Continue with whatever content is accessible in the non-logged-in state.
- At the end, include a note in the result: "注:[平台名称] 未能完成登录,以下内容来自未登录状态,可能不完整。"
2. Simple Verification / CAPTCHA
When a page shows a one-click verification challenge (e.g., a button labelled "去验证", "Verify", "I'm not a robot", or a simple checkbox):
- Try clicking the verification button/checkbox directly(
camoufox-cli --session <s> --json click <ref 或 selector>).
- Wait a few seconds for the page to refresh.
snapshot 检查正常内容是否已加载.
- If the page now shows the expected content, continue your task.
3. Complex Verification Fallback
If the simple click in Step 2 above fails — the page still shows a challenge, the challenge is a puzzle/slider/image-selection CAPTCHA, or an error occurs:
- Do NOT retry blindly. Stop attempting automated verification.
- Send a message to the user: "xx 页面有验证码,我无法解决,请在浏览器中完成,完成后请通知我。"(xx 为页面标题).
涉及登录的 session 必须是 有头模式,用户才能在浏览器里手动过验证。无头跑出来的 session 遇验证码先 teardown 再换有头重开。
- Wait for the user to confirm.
- If no response arrives within 5 minutes, continue with whatever content is accessible.
4. Lazy-Loaded Content
When a page uses lazy loading (infinite scroll, "load more" sections, content that appears only after scrolling):
- Before scrolling, assess whether the not-yet-loaded content is relevant to the current task.
- If relevant, simulate human-like scrolling:
camoufox-cli --session <s> --json scroll down 增量滚动,pause briefly between scrolls to allow content to load, then snapshot capture new content.
- Repeat until the needed content is visible or no more new content loads.
- Do NOT scroll too fast, do it as a human would. After 7 times of scrolling, you should stop this turn.
- If not relevant, skip scrolling and work with what is already loaded.
5. 页面内 JS 执行(eval / act kind="evaluate")
camoufox-cli 的 eval 在页面上下文跑一段 JS 并回结果。入参必须是一个单一表达式,不是语句块。const/let/var 声明、分号、for/if 语句、function 声明都会触发 Invalid evaluate function 错误。
Wrong(语句块 — 会失败):
const items = document.querySelectorAll('.msg');
let found = false;
for (const item of items) {
if (item.textContent.includes('target')) { found = true; break; }
}
found ? 'ok' : 'no';
Correct(IIFE 包裹):
(function() {
var items = document.querySelectorAll('.msg');
for (var i = 0; i < items.length; i++) {
if (items[i].textContent.indexOf('target') > -1) { return items[i].innerText; }
}
return 'not found';
})()
Correct(纯表达式,简单查询):
document.querySelector('.reply-btn') ? 'found' : 'not found'
Rules:
- Always wrap multi-step logic in an IIFE:
(function(){ ... })()
- 只需要点击的 DOM 查询,优先
click <ref> 而非 eval
- 读文本优先
snapshot 而非 eval
- Never use
const/let/var declarations or ; at the top level of fn
6. Paywall / Subscription Walls
When a page indicates that content is behind a paywall or requires a specific subscription (e.g., "Subscribe to continue reading", "Continue reading with a WSJ subscription", premium-only banners):
- Send a message to the user describing the situation: "xx 页面需要订阅,请在浏览器中登录有效账号或者完成付费,完成后请通知我。"(xx 为页面标题).
- Wait for the user to confirm.
- If no response arrives within 5 minutes, continue with whatever content is accessible (summary, headline, or any visible excerpt).