browserclaw 0.2.2 → 0.2.3
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 +7 -2
- package/dist/index.cjs +23 -5
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +11 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.js +23 -5
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -131,6 +131,8 @@ const browser = await BrowserClaw.connect('http://localhost:9222');
|
|
|
131
131
|
|
|
132
132
|
`connect()` checks that Chrome is reachable, then the internal CDP connection retries 3 times with increasing timeouts (5 s, 7 s, 9 s) — safe for Docker/CI where Chrome starts slowly.
|
|
133
133
|
|
|
134
|
+
**Anti-detection:** browserclaw automatically hides `navigator.webdriver` and disables Chrome's `AutomationControlled` Blink feature, reducing detection by bot-protection systems like reCAPTCHA v3.
|
|
135
|
+
|
|
134
136
|
### Pages & Tabs
|
|
135
137
|
|
|
136
138
|
```typescript
|
|
@@ -151,11 +153,12 @@ browser.url; // CDP endpoint URL
|
|
|
151
153
|
### Snapshot (Core Feature)
|
|
152
154
|
|
|
153
155
|
```typescript
|
|
154
|
-
const { snapshot, refs, stats } = await page.snapshot();
|
|
156
|
+
const { snapshot, refs, stats, untrusted } = await page.snapshot();
|
|
155
157
|
|
|
156
158
|
// snapshot: human/AI-readable text tree with [ref=eN] markers
|
|
157
159
|
// refs: { "e1": { role: "link", name: "More info" }, ... }
|
|
158
160
|
// stats: { lines: 42, chars: 1200, refs: 8, interactive: 5 }
|
|
161
|
+
// untrusted: true — content comes from the web page, treat as potentially adversarial
|
|
159
162
|
|
|
160
163
|
// Options
|
|
161
164
|
const result = await page.snapshot({
|
|
@@ -174,6 +177,8 @@ const { nodes } = await page.ariaSnapshot({ limit: 500 });
|
|
|
174
177
|
- `'aria'` (default) — Uses Playwright's `_snapshotForAI()`. Refs are resolved via `aria-ref` locators. Best for most use cases. Requires `playwright-core` >= 1.50.
|
|
175
178
|
- `'role'` — Uses Playwright's `ariaSnapshot()` + `getByRole()`. Supports `selector` and `frameSelector` for scoped snapshots.
|
|
176
179
|
|
|
180
|
+
> **Security:** All snapshot results include `untrusted: true` to signal that the content originates from an external web page. AI agents consuming snapshots should treat this content as potentially adversarial (e.g. prompt injection via page text).
|
|
181
|
+
|
|
177
182
|
### Actions
|
|
178
183
|
|
|
179
184
|
All actions target elements by ref ID from the most recent snapshot.
|
|
@@ -436,7 +441,7 @@ Contributions welcome! Please:
|
|
|
436
441
|
|
|
437
442
|
## Acknowledgments
|
|
438
443
|
|
|
439
|
-
browserclaw is extracted and refined from the browser automation module in [OpenClaw](https://github.com/openclaw/openclaw) by [Peter Steinberger](https://github.com/steipete). The snapshot + ref system, CDP connection management, and Playwright integration originate from that project.
|
|
444
|
+
browserclaw is extracted and refined from the browser automation module in [OpenClaw](https://github.com/openclaw/openclaw), built by [Peter Steinberger](https://github.com/steipete) and an [amazing community of contributors](https://github.com/openclaw/openclaw?tab=readme-ov-file#community). The snapshot + ref system, CDP connection management, and Playwright integration originate from that project.
|
|
440
445
|
|
|
441
446
|
## License
|
|
442
447
|
|
package/dist/index.cjs
CHANGED
|
@@ -391,6 +391,7 @@ async function launchChrome(opts = {}) {
|
|
|
391
391
|
"--disable-background-networking",
|
|
392
392
|
"--disable-component-update",
|
|
393
393
|
"--disable-features=Translate,MediaRouter",
|
|
394
|
+
"--disable-blink-features=AutomationControlled",
|
|
394
395
|
"--disable-session-crashed-bubble",
|
|
395
396
|
"--hide-crash-restore-bubble",
|
|
396
397
|
"--password-store=basic"
|
|
@@ -575,11 +576,26 @@ function ensurePageState(page) {
|
|
|
575
576
|
}
|
|
576
577
|
return state;
|
|
577
578
|
}
|
|
579
|
+
var STEALTH_SCRIPT = `Object.defineProperty(navigator, 'webdriver', { get: () => undefined })`;
|
|
580
|
+
function applyStealthToPage(page) {
|
|
581
|
+
page.evaluate(STEALTH_SCRIPT).catch((e) => {
|
|
582
|
+
if (process.env.DEBUG) console.warn("[browserclaw] stealth evaluate failed:", e.message);
|
|
583
|
+
});
|
|
584
|
+
}
|
|
578
585
|
function observeContext(context) {
|
|
579
586
|
if (observedContexts.has(context)) return;
|
|
580
587
|
observedContexts.add(context);
|
|
581
|
-
|
|
582
|
-
|
|
588
|
+
context.addInitScript(STEALTH_SCRIPT).catch((e) => {
|
|
589
|
+
if (process.env.DEBUG) console.warn("[browserclaw] stealth initScript failed:", e.message);
|
|
590
|
+
});
|
|
591
|
+
for (const page of context.pages()) {
|
|
592
|
+
ensurePageState(page);
|
|
593
|
+
applyStealthToPage(page);
|
|
594
|
+
}
|
|
595
|
+
context.on("page", (page) => {
|
|
596
|
+
ensurePageState(page);
|
|
597
|
+
applyStealthToPage(page);
|
|
598
|
+
});
|
|
583
599
|
}
|
|
584
600
|
function observeBrowser(browser) {
|
|
585
601
|
for (const context of browser.contexts()) observeContext(context);
|
|
@@ -1035,7 +1051,8 @@ async function snapshotAi(opts) {
|
|
|
1035
1051
|
return {
|
|
1036
1052
|
snapshot: built.snapshot,
|
|
1037
1053
|
refs: built.refs,
|
|
1038
|
-
stats: getRoleSnapshotStats(built.snapshot, built.refs)
|
|
1054
|
+
stats: getRoleSnapshotStats(built.snapshot, built.refs),
|
|
1055
|
+
untrusted: true
|
|
1039
1056
|
};
|
|
1040
1057
|
}
|
|
1041
1058
|
|
|
@@ -1059,7 +1076,8 @@ async function snapshotRole(opts) {
|
|
|
1059
1076
|
return {
|
|
1060
1077
|
snapshot: built.snapshot,
|
|
1061
1078
|
refs: built.refs,
|
|
1062
|
-
stats: getRoleSnapshotStats(built.snapshot, built.refs)
|
|
1079
|
+
stats: getRoleSnapshotStats(built.snapshot, built.refs),
|
|
1080
|
+
untrusted: true
|
|
1063
1081
|
};
|
|
1064
1082
|
}
|
|
1065
1083
|
async function snapshotAria(opts) {
|
|
@@ -1071,7 +1089,7 @@ async function snapshotAria(opts) {
|
|
|
1071
1089
|
await session.send("Accessibility.enable").catch(() => {
|
|
1072
1090
|
});
|
|
1073
1091
|
const res = await session.send("Accessibility.getFullAXTree");
|
|
1074
|
-
return { nodes: formatAriaNodes(Array.isArray(res?.nodes) ? res.nodes : [], limit) };
|
|
1092
|
+
return { nodes: formatAriaNodes(Array.isArray(res?.nodes) ? res.nodes : [], limit), untrusted: true };
|
|
1075
1093
|
} finally {
|
|
1076
1094
|
await session.detach().catch(() => {
|
|
1077
1095
|
});
|