Pagerunner Skill — Quick Start Guide
Pagerunner is real Chrome browser automation for AI agents. It gives Claude, Cursor, Windsurf, or any MCP client native control over your real Chrome — with your existing login sessions, cookies, and browser history already loaded.
For AI Agents: Decision Guide
If you are an AI agent executing a task with this skill, follow these rules. They are non-negotiable — they prevent the most common failures.
Rule 1: Every workflow starts the same way
CODEBLOCK0
Get target_id from list_tabs before anything else. Without it, no other tools work.
Rule 2: wait_for before every interaction (no exceptions)
After navigate(), the page is loading. Selectors don't exist yet. Always wait before clicking, filling, or evaluating:
CODEBLOCK1
Skipping this causes "selector not found" errors. If you don't know a stable selector, use get_content first to find one.
Rule 3: Understand the page before acting
Don't guess at selectors. Call get_content to see what's on the page, then act:
CODEBLOCK2
Rule 4: Which input tool to use
| If the app uses... | Use... |
|---|
| React / Vue / Angular | INLINECODE6 — clears field, fires change events |
| Plain HTML / native inputs |
type_text() — types without clearing |
| Unsure |
fill() — it's the safer default |
Rule 5: Verify after every action
After submitting a form or clicking a button, confirm it worked:
CODEBLOCK3
Rule 6: evaluate() must return labeled objects
CODEBLOCK4
Pagerunner's metadata block will warn you if you return an array. Read it.
Rule 7: Always close sessions with try/finally
CODEBLOCK5
INLINECODE10 also writes an auto-checkpoint (v0.6.0+), preserving session state.
Choose Your Path
Solo Developer (Claude Code / Cursor)
Goal: Close the implementation loop. Edit code → see the result in the browser → iterate without manual verification.
Quick Start (5 lines):
CODEBLOCK6
Killer Feature: Your Chrome, already logged into everything. No API token setup.
Learn More: See PATTERNS.md → "Frontend dev loop"
📱 Power User (OpenClaw / Hermes)
Goal: Get browser tasks done from your phone while the laptop runs unattended.
Quick Start (8 lines):
CODEBLOCK7
Killer Features: Agent profile isolation + snapshot persistence + daemon for always-on
Real Example:
CODEBLOCK8
Learn More: See PATTERNS.md → "Authentication persistence"
🔒 Security-Conscious (NemoClaw / regulated industries)
Goal: Automate workflows on sensitive data without PII reaching the LLM.
Quick Start (1 flag):
CODEBLOCK9
Killer Features: PII never leaves your machine in plaintext + local NER + audit trail
Learn More: See SECURITY.md → "Anonymization modes"
⚙️ Server-Side / Infrastructure (Hermes + cron)
Goal: Persistent browser automation across scheduled runs. Agents coordinate via shared state.
Quick Start (daemon setup):
CODEBLOCK10
CODEBLOCK11
Killer Features: Daemon + KV coordination + snapshots for auth handoff + session persistence across restarts (v0.6.0+)
Learn More: See ADVANCED.md → "Session Persistence & Auto-Reattach"
Common Gotchas
1️⃣ Arrays Cause Hallucinations
Problem: evaluate() returns [25, 2]. Claude guesses "25 likes, 2 replies" but it's actually "25 views, 2 likes."
Why: Arrays have no field labels. Order is ambiguous.
Solution: Always return labeled objects from evaluate():
CODEBLOCK12
Pro Tip: Pagerunner metadata warns you if evaluate returns an array. Read the metadata block.
2️⃣ Selectors Timing
Problem: React/Vue renders asynchronously. Selector might not exist for 500ms.
Solution: Always use wait_for with a selector before clicking:
CODEBLOCK13
Never assume content exists immediately after navigation.
3️⃣ Fill vs Type
- -
fill() — clears the field and types (uses React synthetic events) type_text() — types without clearing (for plain HTML)
Use fill() for modern frameworks. Use type_text() for simple inputs.
4️⃣ Snapshot + TOTP
Problem: TOTP codes change every 30 seconds. Can't snapshot mid-auth.
Solution: Log in manually, wait until you're past the TOTP challenge, then snapshot. The saved session includes all cookies — next restore won't need TOTP again.
5️⃣ Wait_For Ambiguity
INLINECODE19 can wait for a selector, a URL pattern, or a fixed delay. The response tells you what happened.
Read the metadata block. It shows _condition_type (selector/url/fixed_delay) and _condition_met (true/false).
6️⃣ Sessions Survive Daemon Restarts (v0.6.0+)
Problem: You restart the daemon expecting a clean slate, but existing Chrome windows are still attached.
Why: v0.6.0 uses TCP-based Chrome transport — Chrome runs independently of the daemon process. Sessions auto-reattach on startup.
Solution: This is intentional. Call list_sessions() to see surviving sessions. Call close_session(id) to clean up explicitly if you don't want them. See ADVANCED.md → "Session Persistence & Auto-Reattach".
Core Workflow: Form Filling with Error Recovery
Real-world example. Fill a React form, handle validation errors.
CODEBLOCK14
Key patterns:
- - Use
fill() for React/Vue/Angular (synthetic events) - Always
wait_for before interacting with dynamic content - Try-catch around the whole interaction block for recovery
- Screenshots as verification checkpoints
When to Use Pagerunner vs Other Tools
| Task | Tool | Why |
|---|
| Read static HTML | WebFetch | Simpler, no browser |
| React/Vue app, need to interact |
Pagerunner | WebFetch returns empty shell |
| Debug live webpage | Chrome DevTools MCP | Specializes in dev tools |
| Test cross-browser | Playwright MCP | Pagerunner is Chrome-only |
| Cloud remote browsers | agent-browser cloud / Browserbase | Pagerunner is local-only |
| Headless Chromium (no profile) | agent-browser headless | Pagerunner needs Chrome + profile |
|
MCP-native in IDE |
Pagerunner | MCP first-class in Claude Code/Cursor |
|
PII-sensitive workflows |
Pagerunner | Only tool with anonymization + audit |
|
Autonomous task from phone |
Pagerunner | Daemon + profile isolation |
Deeper Dives
Setup
1. Install Pagerunner
CODEBLOCK15
2. Register as MCP server
CODEBLOCK16
For Claude Desktop, add to ~/Library/Application Support/Claude/claude_desktop_config.json:
CODEBLOCK17
3. Configure Chrome profiles (optional)
CODEBLOCK18
This reads your Chrome profiles and writes ~/.pagerunner/config.toml.
Note: Close any Chrome window before opening a Pagerunner session on that profile (Chrome locks directories).
Next Steps
Pick your ICP above, follow the quick start, then dive into the relevant doc:
- - Solo Dev → PATTERNS.md → "Frontend dev loop"
- Power User → PATTERNS.md → "Authentication persistence"
- Security-Conscious → SECURITY.md
- Server-Side → ADVANCED.md → "Multi-agent patterns"
Happy automating!
Pagerunner 技能 — 快速入门指南
Pagerunner 是为 AI 智能体提供的真实 Chrome 浏览器自动化工具。它让 Claude、Cursor、Windsurf 或任何 MCP 客户端能够原生控制你的真实 Chrome 浏览器——并已加载你现有的登录会话、Cookie 和浏览历史。
面向 AI 智能体:决策指南
如果你是正在使用此技能执行任务的 AI 智能体,请遵循以下规则。这些规则不可协商——它们能防止最常见的故障。
规则 1:每个工作流都以相同方式开始
javascript
const sessionId = await open_session({ profile: personal }); // 或 agent-work 等
const [tab] = await list_tabs(sessionId);
const tabId = tab.target_id; // 保存此值——每个工具都需要它
在进行任何其他操作之前,先从 listtabs 获取 targetid。没有它,其他工具都无法工作。
规则 2:每次交互前都要 wait_for(无例外)
在 navigate() 之后,页面正在加载。选择器尚不存在。在点击、填写或评估之前始终等待:
javascript
await navigate(sessionId, tabId, url);
await wait_for(sessionId, tabId, { selector: .any-stable-element, ms: 5000 });
// 只有现在才能安全地点击、填写、get_content、evaluate
跳过此步骤会导致选择器未找到错误。如果你不知道稳定的选择器,请先使用 get_content 找到一个。
规则 3:在操作前了解页面
不要猜测选择器。调用 get_content 查看页面上有什么,然后再操作:
javascript
const structure = await get_content(sessionId, tabId);
// 显示:可见文本、表单字段、按钮、导航状态
// 在 fill/click/evaluate 之前使用此信息找到正确的选择器
规则 4:使用哪个输入工具
| 如果应用使用... | 使用... |
|---|
| React / Vue / Angular | fill() — 清除字段,触发变更事件 |
| 普通 HTML / 原生输入 |
type_text() — 输入但不清除 |
| 不确定 | fill() — 这是更安全的默认选项 |
规则 5:每次操作后验证
提交表单或点击按钮后,确认操作成功:
javascript
await click(sessionId, tabId, .submit-btn);
await wait_for(sessionId, tabId, { selector: .success-message, .error-message, ms: 5000 });
const result = await get_content(sessionId, tabId);
// 检查结果是否包含预期的确认信息——永远不要假设成功
规则 6:evaluate() 必须返回带标签的对象
javascript
// ❌ 永远不要这样做——数组字段顺序不明确,会导致错误答案
return [likes, replies];
// ✅ 始终这样做——带标签的字段没有歧义
return { likes, replies };
如果你返回数组,Pagerunner 的元数据块会发出警告。请阅读它。
规则 7:始终使用 try/finally 关闭会话
javascript
const sessionId = await open_session({ profile: ... });
try {
// ... 工作流 ...
} finally {
await close_session(sessionId); // 即使工作流抛出异常也会执行
}
close_session 还会写入自动检查点(v0.6.0+),保存会话状态。
选择你的路径
独立开发者(Claude Code / Cursor)
目标: 闭环实现。编辑代码 → 在浏览器中查看结果 → 无需手动验证即可迭代。
快速入门(5 行):
javascript
const sessionId = await open_session({ profile: personal });
const [tab] = await list_tabs(sessionId);
await navigate(sessionId, tab.target_id, http://localhost:3000);
await screenshot(sessionId, tab.target_id); // 查看你构建的内容
await close_session(sessionId);
杀手级功能: 你的 Chrome,已登录所有内容。无需设置 API 令牌。
了解更多: 参见 PATTERNS.md → 前端开发循环
📱 高级用户(OpenClaw / Hermes)
目标: 在笔记本电脑无人值守运行时,从手机完成浏览器任务。
快速入门(8 行):
javascript
// 首次:手动登录并保存会话
pagerunner open-session agent-work
// ... 执行登录步骤 ...
pagerunner save-snapshot https://jira.mycompany.com
// 之后:智能体配置文件已预认证
pagerunner open-session agent-work
pagerunner restore-snapshot https://jira.mycompany.com
// 智能体已登录。现在开始工作:navigate、get_content、填写表单
杀手级功能: 智能体配置文件隔离 + 快照持久化 + 守护进程实现始终在线
真实示例:
WhatsApp:检查我的 Jira 是否有阻塞项
→ OpenClaw 触发技能
→ opensession(profile=agent-work) → restoresnapshot
→ 导航到 Jira → get_content → 总结
→ 截图 → 发送回 WhatsApp
了解更多: 参见 PATTERNS.md → 认证持久化
🔒 安全敏感型(NemoClaw / 受监管行业)
目标: 在敏感数据上自动化工作流,且 PII 不触及 LLM。
快速入门(1 个标志):
javascript
open_session({
profile: agent,
anonymize: true // 就这样。PII 在到达你之前已被剥离。
});
// 每个 get_content 和 evaluate 结果中的 PII 都被替换为令牌:
// john@company.com → [EMAIL:a3f9b2]
// Claude 使用令牌工作
// Pagerunner 仅在写入表单时进行去令牌化
// 审计日志记录每个操作(合规证明)
杀手级功能: PII 永远不以明文形式离开你的机器 + 本地 NER + 审计追踪
了解更多: 参见 SECURITY.md → 匿名化模式
⚙️ 服务端 / 基础设施(Hermes + cron)
目标: 跨计划运行的持久浏览器自动化。智能体通过共享状态协调。
快速入门(守护进程设置):
bash
pagerunner daemon & # 运行一次,持有数据库锁
现在在 cron、shell 脚本或 Hermes 任务中使用 Pagerunner
多个智能体通过 KV 存储共享状态
v0.6.0:Chrome 窗口在守护进程重启后仍然存在
kill $(pgrep -f pagerunner daemon) && pagerunner daemon &
会话自动重新连接——不会丢失工作
javascript
// 智能体 A:收集数据
await kvset(pipeline, pricingdata, JSON.stringify(results));
// 智能体 B(稍后):从 A 停止的地方继续
const data = JSON.parse(await kvget(pipeline, pricingdata));
杀手级功能: 守护进程 + KV 协调 + 用于认证交接的快照 + 跨重启的会话持久化(v0.6.0+)
了解更多: 参见 ADVANCED.md → 会话持久化与自动重新连接
常见陷阱
1️⃣ 数组导致幻觉
问题: evaluate() 返回 [25, 2]。Claude 猜测25 个点赞,2 条回复,但实际上是25 次浏览,2 个点赞。
原因: 数组没有字段标签。顺序不明确。
解决方案: 始终从 evaluate() 返回带标签的对象:
javascript
// ❌ 错误
return [likes, replies];
// ✅ 正确
return { likes, replies };
专业提示: 如果 evaluate 返回数组,Pagerunner 元数据会发出警告。请阅读元数据块。
2️⃣ 选择器时序
问题: React/Vue 异步渲染。选择器可能在 500ms 内不存在。
解决方案: 在点击之前始终使用带选择器的 wait_for:
javascript
await navigate(sessionId, tabId, newUrl);
await wait_for(sessionId, tabId, selector: .load-more-btn, ms: 5000);
await click(sessionId, tabId, .load-more-btn); // 现在安全
永远不要假设导航后内容立即可用。
3️⃣ Fill 与 Type 的区别
- - fill() — 清除字段并输入(使用 React 合成事件)
- type_text() — 输入但不清除(用于普通 HTML)
对现代框架使用 fill()。对简单输入使用 type_text()。
4️⃣ 快照 + T