browserforce 1.0.5 → 1.0.7

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 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 | Antigravity | BrowserForce |
15
+ | | Playwright MCP | OpenClaw Browser | Playwriter | Claude Extension | BrowserForce |
14
16
  |---|---|---|---|---|---|
15
- | Tab access | N/A (new browser) | Click each tab | Click each tab | Click each tab | **All tabs, automatic** |
16
- | Browser | Spawns new Chrome | Your Chrome | Your Chrome | Your Chrome | **Your Chrome** |
17
- | Autonomous | Yes | No (manual click) | No (manual click) | No (manual click) | **Yes (fully autonomous)** |
18
- | Tools | Many dedicated tools | 1 `execute` tool | Built-in | Many dedicated tools | **1 `execute` tool** |
19
- | Agent support | Any MCP client | Any MCP client | Claude only | Custom | **Any MCP client** |
20
- | Context method | Screenshots | A11y snapshots | Screenshots | Screenshots | **A11y snapshots** |
21
- | Playwright API | Partial | Full | No | No | **Full** |
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. Start the relay
49
+ ### 3. Done
47
50
 
48
- ```bash
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
- Or with pnpm (development):
53
+ To run the relay manually (optional):
53
54
 
54
55
  ```bash
55
- pnpm relay
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
- Install the BrowserForce skill:
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):
73
66
 
74
67
  ```bash
75
- npx -y skills add ivalsaraj/browserforce
68
+ npm install -g browserforce && npx -y skills add ivalsaraj/browserforce
76
69
  ```
77
70
 
78
- The skill teaches your agent to use BrowserForce CLI commands via Bash. Your OpenClaw agent can now browse the web as you — no login flows, no captchas.
71
+ Then start the relay (keep this running):
79
72
 
80
- Or add BrowserForce as an MCP server in `~/.openclaw/openclaw.json`:
73
+ ```bash
74
+ browserforce serve
75
+ ```
76
+
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.
82
+
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,137 @@ 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
+ ### Multi-Tab Workflows
245
+
246
+ <details>
247
+ <summary><b>Example 3: Search → Extract → Return</b></summary>
248
+
249
+ **Prompt to AI:**
250
+ > Search ProductHunt for "AI tools" and give me the top 5 products with their taglines and upvote counts.
251
+
252
+ **What the AI does:** Navigates ProductHunt, searches, extracts product info, returns structured data.
253
+
254
+ **Use case:** Market research, finding tools, competitive analysis.
255
+
256
+ </details>
257
+
258
+ <details>
259
+ <summary><b>Example 4: Open result in new tab, process there</b></summary>
260
+
261
+ **Prompt to AI:**
262
+ > Find the #1 product from your last ProductHunt search, click into it, and read the full description. Tell me what it does.
263
+
264
+ **What the AI does:** Opens the product page from previous results, reads the description, summarizes it.
265
+
266
+ **Use case:** Deep-dive research, understanding competitors, due diligence.
267
+
268
+ </details>
269
+
270
+ <details>
271
+ <summary><b>Example 5: Debugging workflow (inspect + verify)</b></summary>
272
+
273
+ **Prompt to AI:**
274
+ > Go to my staging site at staging.myapp.com/checkout and take a labeled screenshot. Tell me if the "Complete Purchase" button is visible and what's around it.
275
+
276
+ **What the AI does:** Navigates, takes screenshot with interactive labels, analyzes button state and layout.
277
+
278
+ **Use case:** Visual debugging, QA checks, spotting broken elements.
279
+
280
+ </details>
281
+
282
+ <details>
283
+ <summary><b>Example 6: Test form with data</b></summary>
284
+
285
+ **Prompt to AI:**
286
+ > Sign up for Substack using the email test.user@example.com. Tell me if the signup completes successfully.
287
+
288
+ **What the AI does:** Fills the form, submits, waits for confirmation, reports success/failure.
289
+
290
+ **Use case:** Testing sign-up flows, QA automation, form validation.
291
+
292
+ </details>
293
+
294
+ <details>
295
+ <summary><b>Example 7: Content pipeline (search → extract → compare)</b></summary>
296
+
297
+ **Prompt to AI:**
298
+ > Search for "AI regulation" on both X.com and LinkedIn. Give me the top 5 trending posts from each and tell me which topics overlap.
299
+
300
+ **What the AI does:** Searches both platforms, extracts posts, compares content, returns analysis.
301
+
302
+ **Use case:** Multi-source research, trend analysis, market sentiment.
303
+
304
+ </details>
305
+
306
+ <details>
307
+ <summary><b>Example 8: Data extraction → CSV pipeline</b></summary>
308
+
309
+ **Prompt to AI:**
310
+ > Go to Hacker News and extract the top 10 stories with their titles and vote counts. Format as CSV so I can import into a spreadsheet.
311
+
312
+ **What the AI does:** Navigates HN, extracts story data, formats as CSV, returns it ready to paste.
313
+
314
+ **Use case:** Data workflows, trend tracking, content curation.
315
+
316
+ </details>
317
+
318
+ <details>
319
+ <summary><b>Example 9: A/B testing across variants</b></summary>
320
+
321
+ **Prompt to AI:**
322
+ > Visit myapp.com/?variant=red and myapp.com/?variant=blue. Compare the two designs and tell me which button color is more prominent and what other differences exist.
323
+
324
+ **What the AI does:** Opens both variants, compares layouts/colors/text, reports visual differences.
325
+
326
+ **Use case:** Design QA, A/B testing, variant comparison.
327
+
328
+ </details>
329
+
330
+ <details>
331
+ <summary><b>Example 10: Monitor + alert workflow</b></summary>
332
+
333
+ **Prompt to AI:**
334
+ > Check our status page at status.myapp.com every few minutes. Tell me the current status of the API and database. Alert me if anything changes from green to red.
335
+
336
+ **What the AI does:** Monitors status page, reads indicators, alerts on degradation.
337
+
338
+ **Use case:** Uptime monitoring, incident detection, SLA tracking.
339
+
340
+ </details>
341
+
342
+ **More examples** and detailed walkthrough available in the [User Guide](GUIDE.md#examples).
343
+
207
344
  ## How It Works
208
345
 
209
346
  ```
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');
@@ -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 'http://127.0.0.1:19222';
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.5",
3
+ "version": "1.0.7",
4
4
  "type": "module",
5
- "description": "Give AI agents your real Chrome browser your logins, cookies, and tabs. Works with OpenClaw, Claude, and any MCP agent.",
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 relay running: `browserforce serve`
23
- 2. BrowserForce Chrome extension installed and connected (green icon)
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