Skip to content
Closed
Show file tree
Hide file tree
Changes from 22 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
ab68dc7
Use standard skill frontmatter for setup instead of setup.json
Feb 22, 2026
abe5f59
Fix: use compatibility field and inline setup check instead of invent…
Feb 22, 2026
cf762a8
Rename browser-automation/ to browser/ to match skill name
Feb 22, 2026
4444477
Align skills with Agent Skills spec (agentskills.io)
Feb 22, 2026
2764231
Switch skill license from Apache-2.0 to MIT
Feb 22, 2026
5ea8052
Address review feedback: fix copyright year and package name
shrey150 Feb 23, 2026
e75e7f8
Improve skill description for agent discovery
Feb 24, 2026
5965eca
Add metadata.openclaw requires + improve local vs remote guidance
Feb 24, 2026
2cda0fa
Guide agent toward snapshot-first workflow and high-level commands
shrey150 Feb 24, 2026
1ada63a
Rewrite commands section to match actual browse CLI
shrey150 Feb 24, 2026
f63168f
Fix troubleshooting for zombie daemon "No active page" error
shrey150 Feb 24, 2026
3fb2f49
Fix stale browser-automation references; rewrite skill docs with real…
shrey150 Feb 24, 2026
6d020cf
Document browse mode command for on-the-fly local/remote switching
shrey150 Feb 24, 2026
5b74333
browser(skill): remove auto-install for non-existent @browserbasehq/b…
cursoragent Feb 24, 2026
a2fdade
Revert "browser(skill): remove auto-install for non-existent @browser…
cursoragent Feb 25, 2026
07ddb74
docs(browser): remove broken commands, document undocumented features
shrey150 Feb 26, 2026
06fcff2
rename `browse mode` to `browse env` in docs
shrey150 Feb 26, 2026
d1aa1f1
docs(browser): restore drag, highlight, is, and get html/visible/chec…
shrey150 Feb 26, 2026
068b527
docs(browser): add refs, open --wait, --json, and --session to REFERE…
shrey150 Feb 26, 2026
b4ea2f9
docs(browser): use consistent heading style for global flags
shrey150 Feb 26, 2026
acc6cc3
docs(browser): add TOC, remove duplicated sections, tighten env switc…
shrey150 Feb 26, 2026
909f675
Add agent-browser remote interop and sub-agent fleet skills
shrey150 Feb 27, 2026
63df3bc
Rename browser-fleet skill to browse-fleet-subagents
shrey150 Feb 27, 2026
9e5c1a3
Fix Browserbase session close flow in agent-browser-remote script
shrey150 Feb 27, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .claude-plugin/marketplace.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
"keywords": ["browser", "automation", "web-scraping", "stagehand", "screenshots"],
"strict": false,
"skills": [
"./skills/browser-automation"
"./skills/browser"
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New skills not registered in marketplace discovery catalog

High Severity

The two new skills (agent-browser-remote and browse-fleet-subagents) are added with full SKILL.md files and listed in the README.md skills table, but neither is registered in marketplace.json. Since marketplace.json is the discovery catalog that Claude Code uses to find and load skills, these skills won't be discoverable or installable through the plugin system. The browse plugin's skills array only contains ./skills/browser.

Additional Locations (1)

Fix in Cursor Fix in Web

]
},
{
Expand Down
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ This plugin includes the following skills (see `skills/` for details):

| Skill | Description |
|-------|-------------|
| [browser-automation](skills/browser-automation/SKILL.md) | Browser control using natural language commands (navigate, click, extract data, screenshot) |
| [browser](skills/browser/SKILL.md) | Automate web browser interactions via CLI commands — supports remote Browserbase sessions with anti-bot stealth, CAPTCHA solving, and residential proxies |
| [agent-browser-remote](skills/agent-browser-remote/SKILL.md) | Use Agent Browser with Browserbase remote CDP sessions when local browsing hits CAPTCHAs, anti-bot checks, or JavaScript-heavy sites |
| [browser-fleet](skills/browser-fleet/SKILL.md) | Orchestrate high-volume browser work via sub-agent fanout with clear decomposition, retries, and cleanup patterns |
| [functions](skills/functions/SKILL.md) | Deploy serverless browser automation to Browserbase cloud using the `bb` CLI |

## Installation
Expand Down Expand Up @@ -60,4 +62,4 @@ rm -rf .chrome-profile
## Resources

- [Stagehand Documentation](https://github.com/browserbase/stagehand)
- [Claude Code Skills](https://support.claude.com/en/articles/12512176-what-are-skills)
- [Claude Code Skills](https://support.claude.com/en/articles/12512176-what-are-skills)
21 changes: 21 additions & 0 deletions skills/agent-browser-remote/LICENSE.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2026 Browserbase, Inc.

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
94 changes: 94 additions & 0 deletions skills/agent-browser-remote/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
---
name: agent-browser-remote
description: Use Agent Browser with Browserbase remote CDP sessions. Trigger this skill when users are driving browser tasks with agent-browser and encounter CAPTCHAs, anti-bot pages, IP-based blocking, JavaScript-heavy sites, geo restrictions, or request remote cloud browser execution.
compatibility: "Requires `agent-browser` and Node.js. Requires Browserbase credentials (`BROWSERBASE_API_KEY`, `BROWSERBASE_PROJECT_ID`) for remote sessions."
license: MIT
allowed-tools: Bash
metadata:
capabilities:
- agent-browser
- remote-browser
- cdp-interop
- stealth
- captcha-solving
- proxies
openclaw:
requires:
bins:
- agent-browser
- node
install:
- kind: node
package: "agent-browser"
bins: [agent-browser]
homepage: https://github.com/browserbase/skills
---

# Agent Browser + Remote CDP

Use this skill when `agent-browser` local mode struggles on protected sites, or when the user explicitly wants remote cloud browsers.

## Setup check

```bash
which agent-browser || npm install -g agent-browser
agent-browser install
```

Set Browserbase credentials (or run `openclaw browserbase setup`):

```bash
export BROWSERBASE_API_KEY="..."
export BROWSERBASE_PROJECT_ID="..."
```

## Fast path

Create a Browserbase session, then point `agent-browser` at the returned CDP URL.

```bash
eval "$(node scripts/browserbase-session.mjs create --proxies true --advanced-stealth true --format shell)"
agent-browser --cdp "$BROWSERBASE_CDP_URL" open https://example.com
agent-browser --cdp "$BROWSERBASE_CDP_URL" snapshot -i --json
```

When done:

```bash
node scripts/browserbase-session.mjs close --session-id "$BROWSERBASE_SESSION_ID"
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Script path unresolvable from user working directory

High Severity

The SKILL.md instructs Claude to run node scripts/browserbase-session.mjs as a relative path, but the script lives at skills/agent-browser-remote/scripts/browserbase-session.mjs relative to the repo root. When Claude Code follows these bash instructions, commands execute in the user's project directory, where no scripts/browserbase-session.mjs exists. Every other skill in this repo uses globally-installed CLI tools (e.g., browse, pnpm bb) rather than relative file paths.

Fix in Cursor Fix in Web

```

## When to switch from local to remote

Switch to remote when any of these appear:
- CAPTCHA or challenge pages (reCAPTCHA, hCaptcha, Turnstile)
- bot checks ("checking your browser", "verify you are human")
- repeated `403` / `429` from sites that should be accessible
- empty DOM/snapshot on JavaScript-heavy pages that should have content
- geo-specific content requirements

Stay local for simple docs sites, localhost, and basic internal QA flows.

## Command patterns

Per-command CDP (explicit, stateless):

```bash
agent-browser --cdp "$BROWSERBASE_CDP_URL" open https://target.com
agent-browser --cdp "$BROWSERBASE_CDP_URL" snapshot -i --json
agent-browser --cdp "$BROWSERBASE_CDP_URL" click @e2
```

Or connect once, then run normal commands:

```bash
agent-browser connect "$BROWSERBASE_CDP_URL"
agent-browser open https://target.com
agent-browser snapshot -i --json
```

## Notes

- `--proxies true` requires a Browserbase plan that includes proxies.
- `--advanced-stealth true` requires a plan that includes advanced stealth.
- Always close remote sessions explicitly when the task ends.
177 changes: 177 additions & 0 deletions skills/agent-browser-remote/scripts/browserbase-session.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
#!/usr/bin/env node

const DEFAULT_API_BASE = process.env.BROWSERBASE_API_BASE_URL || "https://api.browserbase.com";

function usage() {
console.error(
[
"Usage:",
" node scripts/browserbase-session.mjs create [options]",
" node scripts/browserbase-session.mjs close --session-id <id> [options]",
"",
"Create options:",
" --api-key <key> Browserbase API key (or BROWSERBASE_API_KEY)",
" --project-id <id> Browserbase project ID (or BROWSERBASE_PROJECT_ID)",
" --proxies <true|false> Enable proxies",
" --advanced-stealth <true|false> Enable advanced stealth",
" --keep-alive <true|false> Keep session alive on Browserbase",
" --format <json|shell|url> Output format (default: json)",
" --api-base-url <url> API base URL (default: https://api.browserbase.com)",
"",
"Close options:",
" --session-id <id> Session ID to close (required)",
" --api-key <key> Browserbase API key (or BROWSERBASE_API_KEY)",
" --api-base-url <url> API base URL",
].join("\n"),
);
}

function parseArgs(argv) {
const out = { _: [] };
for (let i = 0; i < argv.length; i += 1) {
const arg = argv[i];
if (!arg.startsWith("--")) {
out._.push(arg);
continue;
}
const key = arg.slice(2);
const next = argv[i + 1];
if (!next || next.startsWith("--")) {
out[key] = true;
continue;
}
out[key] = next;
i += 1;
}
return out;
}

function parseBool(value, name) {
if (value === undefined) return undefined;
if (value === true || value === false) return value;
const normalized = String(value).trim().toLowerCase();
if (["1", "true", "yes", "on"].includes(normalized)) return true;
if (["0", "false", "no", "off"].includes(normalized)) return false;
throw new Error(`Invalid boolean for --${name}: ${value}`);
}

function shellQuote(value) {
return `'${String(value).replace(/'/g, `'\\''`)}'`;
}

async function createSession(args) {
const apiKey = args["api-key"] || process.env.BROWSERBASE_API_KEY;
const projectId = args["project-id"] || process.env.BROWSERBASE_PROJECT_ID;
const format = String(args.format || "json").toLowerCase();
const apiBaseUrl = String(args["api-base-url"] || DEFAULT_API_BASE).replace(/\/$/, "");

if (!apiKey) throw new Error("Missing API key. Set --api-key or BROWSERBASE_API_KEY.");
if (!projectId) throw new Error("Missing project ID. Set --project-id or BROWSERBASE_PROJECT_ID.");
if (!["json", "shell", "url"].includes(format)) {
throw new Error(`Invalid --format: ${format}`);
}

const proxies = parseBool(args.proxies, "proxies");
const advancedStealth = parseBool(args["advanced-stealth"], "advanced-stealth");
const keepAlive = parseBool(args["keep-alive"], "keep-alive");

const payload = { projectId };
if (proxies !== undefined) payload.proxies = proxies;
if (keepAlive !== undefined) payload.keepAlive = keepAlive;
if (advancedStealth !== undefined) {
payload.browserSettings = { advancedStealth };
}

const response = await fetch(`${apiBaseUrl}/v1/sessions`, {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-BB-API-Key": apiKey,
},
body: JSON.stringify(payload),
});

if (!response.ok) {
const text = await response.text();
throw new Error(`Failed to create session (${response.status}): ${text || response.statusText}`);
}

const data = await response.json();
const sessionId = data.id;
const connectUrl = data.connectUrl;

if (!sessionId || !connectUrl) {
throw new Error("Browserbase response missing id or connectUrl.");
}

const output = {
sessionId,
connectUrl,
debuggerUrl: `https://www.browserbase.com/sessions/${sessionId}`,
};

if (format === "url") {
console.log(output.connectUrl);
return;
}

if (format === "shell") {
console.log(`export BROWSERBASE_SESSION_ID=${shellQuote(output.sessionId)}`);
console.log(`export BROWSERBASE_CDP_URL=${shellQuote(output.connectUrl)}`);
console.log(`export BROWSERBASE_DEBUGGER_URL=${shellQuote(output.debuggerUrl)}`);
return;
}

console.log(JSON.stringify(output, null, 2));
}

async function closeSession(args) {
const apiKey = args["api-key"] || process.env.BROWSERBASE_API_KEY;
const sessionId = args["session-id"] || args.sessionId;
const apiBaseUrl = String(args["api-base-url"] || DEFAULT_API_BASE).replace(/\/$/, "");

if (!apiKey) throw new Error("Missing API key. Set --api-key or BROWSERBASE_API_KEY.");
if (!sessionId) throw new Error("Missing session ID. Set --session-id <id>.");

const response = await fetch(`${apiBaseUrl}/v1/sessions/${encodeURIComponent(sessionId)}`, {
method: "DELETE",
headers: {
"X-BB-API-Key": apiKey,
},
});

if (!response.ok) {
const text = await response.text();
throw new Error(`Failed to close session (${response.status}): ${text || response.statusText}`);
}

console.log(JSON.stringify({ closed: true, sessionId }, null, 2));
}

async function main() {
const argv = process.argv.slice(2);
if (argv.length === 0 || argv.includes("--help") || argv.includes("-h")) {
usage();
process.exit(argv.length === 0 ? 1 : 0);
}

const [command, ...rest] = argv;
const args = parseArgs(rest);

if (command === "create") {
await createSession(args);
return;
}
if (command === "close") {
await closeSession(args);
return;
}

usage();
process.exit(1);
}

main().catch((error) => {
console.error(String(error?.message || error));
process.exit(1);
});
Loading