agentic-browser-automation — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited agentic-browser-automation (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Tier: POWERFUL Category: AI Agents Domain: Browser Automation / Web Scraping / Agentic Workflows
Build autonomous browser agents that use LLMs to reason about web pages and perform multi-step tasks — navigating, clicking, filling forms, extracting data, and recovering from failures — without hardcoded selectors. This replaces brittle CSS/XPath scraping with intent-driven, self-healing automation.
┌─────────────────────────────────────┐
│ Orchestrator │
│ (Breaks goal into browser steps) │
├─────────────────────────────────────┤
│ LLM Reasoning Layer │
│ • Page understanding (DOM→action) │
│ • Selector generation (NL→CSS) │
│ • Error recovery (failure→retry) │
│ • Data extraction (page→JSON) │
├─────────────────────────────────────┤
│ Browser Control Layer │
│ Playwright / Puppeteer │
│ • Navigation, clicks, typing │
│ • Screenshot + accessibility tree │
│ • Network interception (API disc.) │
│ • Stealth mode (anti-bot evasion) │
├─────────────────────────────────────┤
│ Output Layer │
│ Structured JSON / CSV / DB │
└─────────────────────────────────────┘Describe what you want in natural language instead of hardcoding selectors:
async function extractWithIntent(url: string, intent: string, llm: LLMClient) {
const browser = await chromium.launch({ headless: true });
const page = await browser.newPage();
await page.goto(url, { waitUntil: 'networkidle' });
// Use accessibility tree — much smaller than raw DOM
const snapshot = await page.accessibility.snapshot();
const result = await llm.complete(`
Extract data matching: "${intent}"
Page structure: ${JSON.stringify(snapshot)}
Return only valid JSON array.
`);
await browser.close();
return JSON.parse(result);
}async function agentLoop(goal: string, page: Page, llm: LLMClient) {
const history: ActionResult[] = [];
for (let i = 0; i < 20; i++) { // max 20 steps
const tree = await page.accessibility.snapshot();
const action = await llm.complete(`
Goal: ${goal}
Current URL: ${page.url()}
History: ${JSON.stringify(history.slice(-5))}
Page: ${JSON.stringify(tree)}
Return JSON: { type, selector?, value?, reason }
Types: click | type | navigate | scroll | extract | done
`);
const parsed = JSON.parse(action);
if (parsed.type === 'done') return parsed.data;
try {
await executeAction(page, parsed);
history.push({ ...parsed, success: true });
} catch (e) {
history.push({ ...parsed, success: false, error: e.message });
}
}
}async function findElementAdaptive(page: Page, description: string, llm: LLMClient) {
// Strategy 1: Accessibility role
const byRole = await page.$(`role=${guessRole(description)}`).catch(() => null);
if (byRole) return byRole;
// Strategy 2: Text content
const byText = await page.getByText(extractText(description)).first();
if (byText) return byText;
// Strategy 3: LLM generates selector from simplified DOM
const dom = await getSimplifiedDOM(page);
const selector = await llm.complete(
`CSS selector for "${description}" in: ${dom}. Return selector only.`
);
return await page.$(selector.trim());
}Before scraping DOM, check if there's a hidden JSON API:
async function discoverAPIs(page: Page, url: string) {
const apis: any[] = [];
page.on('response', async (r) => {
if ((r.headers()['content-type'] || '').includes('json')) {
apis.push({ url: r.url(), method: r.request().method() });
}
});
await page.goto(url, { waitUntil: 'networkidle' });
await autoScroll(page);
return apis;
}const context = await browser.newContext({
userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) ...',
viewport: { width: 1920, height: 1080 },
locale: 'en-US',
timezoneId: 'America/New_York',
});
await context.addInitScript(() => {
Object.defineProperty(navigator, 'webdriver', { get: () => false });
});| Component | Recommended | Alternatives |
|---|---|---|
| Browser Engine | Playwright | Puppeteer, Selenium |
| LLM | Claude 3.5 Sonnet | GPT-4o, Gemini 2.0 |
| Extraction | Crawl4AI | Firecrawl, Scrapling |
| Agent Framework | Browser-Use | Skyvern, Agent-E |
| Validation | Zod | Pydantic (Python) |
robots.txt and rate limit (max 1 req/sec default)User-Agent identifying your bot~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.