browserforce 1.0.5 → 1.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +68 -29
- package/bin.js +2 -1
- package/mcp/src/exec-engine.js +54 -1
- package/mcp/src/index.js +2 -1
- package/package.json +2 -2
- package/skills/browserforce/SKILL.md +2 -2
package/README.md
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
# BrowserForce
|
|
1
|
+
# BrowserForce //
|
|
2
2
|
|
|
3
3
|
> "a lion doesn't concern itself with token counting" — [@steipete](https://x.com/steipete), creator of [OpenClaw](https://github.com/openclaw/openclaw)
|
|
4
|
+
>
|
|
5
|
+
> "a 10x user doesn't concern itself with sandboxed browsers // sandboxes are for kids" — BrowserForce, your friendly neighborhood power source.
|
|
4
6
|
|
|
5
7
|
**You're giving an AI your real Chrome — your logins, cookies, and sessions. That takes conviction.** BrowserForce is built for people who use the best models and don't look back. Security is built in: lock URLs, block navigation, read-only mode, auto-cleanup — you stay in control.
|
|
6
8
|
|
|
@@ -10,15 +12,16 @@ Works with [OpenClaw](https://github.com/openclaw/openclaw), Claude, or any MCP-
|
|
|
10
12
|
|
|
11
13
|
## Comparison
|
|
12
14
|
|
|
13
|
-
| | Playwright MCP | Playwriter | Claude Extension |
|
|
15
|
+
| | Playwright MCP | OpenClaw Browser | Playwriter | Claude Extension | BrowserForce |
|
|
14
16
|
|---|---|---|---|---|---|
|
|
15
|
-
|
|
|
16
|
-
|
|
|
17
|
-
|
|
|
18
|
-
|
|
|
19
|
-
|
|
|
20
|
-
|
|
|
21
|
-
|
|
|
17
|
+
| Browser | Spawns new Chrome | Separate profile | Your Chrome | Your Chrome | **Your Chrome** |
|
|
18
|
+
| Login state | Fresh | Fresh (isolated) | Yours | Yours | **Yours** |
|
|
19
|
+
| Tab access | N/A (new browser) | Managed by agent | Click each tab | Click each tab | **All tabs, automatic** |
|
|
20
|
+
| Autonomous | Yes | Yes | No (manual click) | No (manual click) | **Yes (fully autonomous)** |
|
|
21
|
+
| Context method | Screenshots (100KB+) | Screenshots + snapshots | A11y snapshots (5-20KB) | Screenshots (100KB+) | **A11y snapshots (5-20KB)** |
|
|
22
|
+
| Tools | Many dedicated | 1 `browser` tool | 1 `execute` tool | Built-in | **1 `execute` tool** |
|
|
23
|
+
| Agent support | Any MCP client | OpenClaw only | Any MCP client | Claude only | **Any MCP client** |
|
|
24
|
+
| Playwright API | Partial | No | Full | No | **Full** |
|
|
22
25
|
|
|
23
26
|
## Setup
|
|
24
27
|
|
|
@@ -43,41 +46,44 @@ pnpm install
|
|
|
43
46
|
3. Click **Load unpacked** → select the `extension/` folder
|
|
44
47
|
4. Extension icon appears in your toolbar (gray = disconnected)
|
|
45
48
|
|
|
46
|
-
### 3.
|
|
49
|
+
### 3. Done
|
|
47
50
|
|
|
48
|
-
|
|
49
|
-
browserforce serve
|
|
50
|
-
```
|
|
51
|
+
The relay auto-starts when you run any command or connect via MCP — no manual step needed. Extension icon turns green once connected.
|
|
51
52
|
|
|
52
|
-
|
|
53
|
+
To run the relay manually (optional):
|
|
53
54
|
|
|
54
55
|
```bash
|
|
55
|
-
|
|
56
|
-
```
|
|
57
|
-
|
|
58
|
-
```
|
|
59
|
-
BrowserForce
|
|
60
|
-
────────────────────────────────────────
|
|
61
|
-
Status: http://127.0.0.1:19222/
|
|
62
|
-
CDP: ws://127.0.0.1:19222/cdp?token=<TOKEN>
|
|
63
|
-
────────────────────────────────────────
|
|
56
|
+
browserforce serve
|
|
64
57
|
```
|
|
65
58
|
|
|
66
|
-
Extension icon turns green — you're connected.
|
|
67
|
-
|
|
68
59
|
## Connect Your Agent
|
|
69
60
|
|
|
70
61
|
### OpenClaw
|
|
71
62
|
|
|
72
|
-
|
|
63
|
+
Most OpenClaw users chat with their agent from Telegram or WhatsApp. BrowserForce lets your agent browse the web as you — no login flows, no captchas — even from a messaging app.
|
|
64
|
+
|
|
65
|
+
**Quick setup** (copy-paste into your terminal):
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
npm install -g browserforce && npx -y skills add ivalsaraj/browserforce
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Then start the relay (keep this running):
|
|
73
72
|
|
|
74
73
|
```bash
|
|
75
|
-
|
|
74
|
+
browserforce serve
|
|
76
75
|
```
|
|
77
76
|
|
|
78
|
-
|
|
77
|
+
**Verify it works** — send this to your agent:
|
|
78
|
+
|
|
79
|
+
> Go to https://x.com and give me top tweets
|
|
80
|
+
|
|
81
|
+
If your agent browses to the page and responds with the title, you're all set.
|
|
79
82
|
|
|
80
|
-
|
|
83
|
+
<details>
|
|
84
|
+
<summary><b>Alternative: MCP server</b> (advanced)</summary>
|
|
85
|
+
|
|
86
|
+
If you prefer MCP over the skill, add to `~/.openclaw/openclaw.json`:
|
|
81
87
|
|
|
82
88
|
```json
|
|
83
89
|
{
|
|
@@ -101,6 +107,8 @@ Or add BrowserForce as an MCP server in `~/.openclaw/openclaw.json`:
|
|
|
101
107
|
}
|
|
102
108
|
```
|
|
103
109
|
|
|
110
|
+
</details>
|
|
111
|
+
|
|
104
112
|
### Claude Desktop
|
|
105
113
|
|
|
106
114
|
Add to `~/Library/Application Support/Claude/claude_desktop_config.json`:
|
|
@@ -202,8 +210,39 @@ state.results = await page.evaluate(() => document.title);
|
|
|
202
210
|
| Tool | Description |
|
|
203
211
|
|------|-------------|
|
|
204
212
|
| `execute` | Run Playwright JavaScript in your real Chrome. Access `page`, `context`, `state`, `snapshot()`, `waitForPageLoad()`, `getLogs()`, and Node.js globals. |
|
|
213
|
+
| `screenshot_with_labels` | Take a screenshot with Vimium-style accessibility labels overlaid on interactive elements. |
|
|
205
214
|
| `reset` | Reconnect to the relay and clear state. Use when the connection drops. |
|
|
206
215
|
|
|
216
|
+
## Examples
|
|
217
|
+
|
|
218
|
+
Get started with simple prompts. The AI generates code and does the work.
|
|
219
|
+
|
|
220
|
+
<details>
|
|
221
|
+
<summary><b>Example 1: Read page content (X.com search)</b></summary>
|
|
222
|
+
|
|
223
|
+
**Prompt to AI:**
|
|
224
|
+
> Go to x.com/search and search for "browserforce". Show me the top 5 tweets you find.
|
|
225
|
+
|
|
226
|
+
**What the AI does:** Navigates to X, searches the term, extracts top tweets, returns them to you.
|
|
227
|
+
|
|
228
|
+
**Use case:** Quick research, trend tracking, social listening.
|
|
229
|
+
|
|
230
|
+
</details>
|
|
231
|
+
|
|
232
|
+
<details>
|
|
233
|
+
<summary><b>Example 2: Interact with a form (GitHub search)</b></summary>
|
|
234
|
+
|
|
235
|
+
**Prompt to AI:**
|
|
236
|
+
> Go to GitHub and search for "ai agents". Show me the top 3 repositories and their star counts.
|
|
237
|
+
|
|
238
|
+
**What the AI does:** Fills GitHub search, waits for results, extracts repo names + stars, returns them.
|
|
239
|
+
|
|
240
|
+
**Use case:** Finding libraries, competitive research, project discovery.
|
|
241
|
+
|
|
242
|
+
</details>
|
|
243
|
+
|
|
244
|
+
**8+ more examples** available in the [User Guide](GUIDE.md#examples).
|
|
245
|
+
|
|
207
246
|
## How It Works
|
|
208
247
|
|
|
209
248
|
```
|
package/bin.js
CHANGED
|
@@ -43,7 +43,8 @@ function httpGet(url) {
|
|
|
43
43
|
}
|
|
44
44
|
|
|
45
45
|
async function connectBrowser() {
|
|
46
|
-
const { getCdpUrl } = await import('./mcp/src/exec-engine.js');
|
|
46
|
+
const { getCdpUrl, ensureRelay } = await import('./mcp/src/exec-engine.js');
|
|
47
|
+
await ensureRelay();
|
|
47
48
|
// playwright-core lives in mcp/node_modules (pnpm workspace sub-package).
|
|
48
49
|
// Use createRequire from the mcp package context to locate it, then dynamic-import.
|
|
49
50
|
const { createRequire } = await import('node:module');
|
package/mcp/src/exec-engine.js
CHANGED
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
import { readFileSync } from 'node:fs';
|
|
5
5
|
import { join } from 'node:path';
|
|
6
6
|
import { homedir } from 'node:os';
|
|
7
|
+
import { fileURLToPath } from 'node:url';
|
|
8
|
+
import { spawn } from 'node:child_process';
|
|
7
9
|
import {
|
|
8
10
|
TEST_ID_ATTRS,
|
|
9
11
|
buildSnapshotText, parseSearchPattern, annotateStableAttrs,
|
|
@@ -11,8 +13,10 @@ import {
|
|
|
11
13
|
|
|
12
14
|
// ─── Configuration ───────────────────────────────────────────────────────────
|
|
13
15
|
|
|
16
|
+
const DEFAULT_PORT = 19222;
|
|
14
17
|
export const BF_DIR = join(homedir(), '.browserforce');
|
|
15
18
|
export const CDP_URL_FILE = join(BF_DIR, 'cdp-url');
|
|
19
|
+
const RELAY_SCRIPT = fileURLToPath(new URL('../../relay/src/index.js', import.meta.url));
|
|
16
20
|
|
|
17
21
|
export function getCdpUrl() {
|
|
18
22
|
if (process.env.BF_CDP_URL) return process.env.BF_CDP_URL;
|
|
@@ -34,10 +38,59 @@ export function getRelayHttpUrl() {
|
|
|
34
38
|
const parsed = new URL(cdpUrl);
|
|
35
39
|
return `http://${parsed.hostname}:${parsed.port}`;
|
|
36
40
|
} catch {
|
|
37
|
-
return
|
|
41
|
+
return `http://127.0.0.1:${DEFAULT_PORT}`;
|
|
38
42
|
}
|
|
39
43
|
}
|
|
40
44
|
|
|
45
|
+
// ─── Auto-start relay ───────────────────────────────────────────────────────
|
|
46
|
+
|
|
47
|
+
function getRelayPort() {
|
|
48
|
+
if (process.env.RELAY_PORT) return parseInt(process.env.RELAY_PORT, 10);
|
|
49
|
+
try {
|
|
50
|
+
const url = readFileSync(CDP_URL_FILE, 'utf8').trim();
|
|
51
|
+
if (url) {
|
|
52
|
+
const port = new URL(url).port;
|
|
53
|
+
if (port) return parseInt(port, 10);
|
|
54
|
+
}
|
|
55
|
+
} catch { /* fall through */ }
|
|
56
|
+
return DEFAULT_PORT;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
async function isRelayRunning(port) {
|
|
60
|
+
try {
|
|
61
|
+
const res = await fetch(`http://127.0.0.1:${port}/`, {
|
|
62
|
+
signal: AbortSignal.timeout(500),
|
|
63
|
+
});
|
|
64
|
+
return res.ok;
|
|
65
|
+
} catch { return false; }
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Ensure the relay server is running. If not, spawn it as a detached
|
|
70
|
+
* background process and wait for it to become reachable.
|
|
71
|
+
*/
|
|
72
|
+
export async function ensureRelay() {
|
|
73
|
+
const port = getRelayPort();
|
|
74
|
+
if (await isRelayRunning(port)) return;
|
|
75
|
+
|
|
76
|
+
const child = spawn(process.execPath, [RELAY_SCRIPT], {
|
|
77
|
+
detached: true,
|
|
78
|
+
stdio: 'ignore',
|
|
79
|
+
env: { ...process.env, RELAY_PORT: String(port) },
|
|
80
|
+
});
|
|
81
|
+
child.unref();
|
|
82
|
+
|
|
83
|
+
const deadline = Date.now() + 5000;
|
|
84
|
+
while (Date.now() < deadline) {
|
|
85
|
+
await new Promise(r => setTimeout(r, 200));
|
|
86
|
+
if (await isRelayRunning(port)) {
|
|
87
|
+
process.stderr.write('[browserforce] Relay auto-started\n');
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
throw new Error('Failed to auto-start relay server within 5s');
|
|
92
|
+
}
|
|
93
|
+
|
|
41
94
|
// ─── Smart Page Load Detection ───────────────────────────────────────────────
|
|
42
95
|
// Filters analytics/ad requests that never finish, polls document.readyState +
|
|
43
96
|
// pending resource count.
|
package/mcp/src/index.js
CHANGED
|
@@ -7,7 +7,7 @@ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'
|
|
|
7
7
|
import { z } from 'zod';
|
|
8
8
|
import { chromium } from 'playwright-core';
|
|
9
9
|
import {
|
|
10
|
-
getCdpUrl, CodeExecutionTimeoutError, buildExecContext, runCode, formatResult,
|
|
10
|
+
getCdpUrl, ensureRelay, CodeExecutionTimeoutError, buildExecContext, runCode, formatResult,
|
|
11
11
|
} from './exec-engine.js';
|
|
12
12
|
import { screenshotWithLabels } from './a11y-labels.js';
|
|
13
13
|
|
|
@@ -65,6 +65,7 @@ let browser = null;
|
|
|
65
65
|
|
|
66
66
|
async function ensureBrowser() {
|
|
67
67
|
if (browser?.isConnected()) return;
|
|
68
|
+
await ensureRelay();
|
|
68
69
|
const cdpUrl = getCdpUrl();
|
|
69
70
|
browser = await chromium.connectOverCDP(cdpUrl);
|
|
70
71
|
browser.on('disconnected', () => {
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "browserforce",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.6",
|
|
4
4
|
"type": "module",
|
|
5
|
-
"description": "Give AI agents your real Chrome browser
|
|
5
|
+
"description": "Give AI agents your real Chrome browser with progressive examples: simple reads, form interactions, multi-tab workflows, and state persistence. Search X and GitHub, extract ProductHunt data, test forms, compare A/B variants, monitor status pages. Works with OpenClaw, Claude, and any MCP agent.",
|
|
6
6
|
"homepage": "https://github.com/ivalsaraj/browserforce",
|
|
7
7
|
"repository": {
|
|
8
8
|
"type": "git",
|
|
@@ -19,8 +19,8 @@ cookies, and extensions already active. No headless browser, no fresh profiles.
|
|
|
19
19
|
## Prerequisites
|
|
20
20
|
|
|
21
21
|
The user must have:
|
|
22
|
-
1. BrowserForce
|
|
23
|
-
2.
|
|
22
|
+
1. BrowserForce Chrome extension installed and connected (green icon)
|
|
23
|
+
2. The relay auto-starts on first command — no manual step needed
|
|
24
24
|
|
|
25
25
|
Check with: `browserforce status`
|
|
26
26
|
|