Requirements
- Target platform
- OpenClaw
- Install method
- Manual import
- Extraction
- Extract archive
- Prerequisites
- OpenClaw
- Primary doc
- SKILL.md
Run Node.js scripts using Playwright for full browser automation, including scraping, screenshots, form handling, and dynamic content interaction.
Run Node.js scripts using Playwright for full browser automation, including scraping, screenshots, form handling, and dynamic content interaction.
Hand the extracted package to your coding agent with a concrete install brief instead of figuring it out manually.
I downloaded a skill package from Yavira. Read SKILL.md from the extracted folder and install it by following the included instructions. Tell me what you changed and call out any manual steps you could not complete.
I downloaded an updated skill package from Yavira. Read SKILL.md from the extracted folder, compare it with my current installation, and upgrade it while preserving any custom configuration unless the package docs explicitly say otherwise. Summarize what changed and any follow-up checks I should run.
๐ค Developed together by Kuba + Mahone ยท Feb 2026 Code-first browser automation with Playwright.
ToolUse Whenweb_fetchSimple pages, no JavaScript neededThis skillJavaScript-heavy sites, complex interactions, full controlstealth-browserBot detection / Cloudflare issuesbrowser toolVisual exploration, last resortplaywright-cliInteractive CLI without writing code
# One-time per project npm init -y npm install playwright npx playwright install chromium package.json example: { "name": "my-automation", "type": "module", "dependencies": { "playwright": "^1.40.0" } }
// tmp/example.mjs import { chromium } from 'playwright'; const browser = await chromium.launch(); const page = await browser.newPage(); await page.goto('https://example.com'); console.log('Title:', await page.title()); await browser.close(); node tmp/example.mjs
import { chromium } from 'playwright'; const browser = await chromium.launch(); const page = await browser.newPage(); await page.setViewportSize({ width: 1280, height: 800 }); await page.goto('https://example.com'); await page.screenshot({ path: 'tmp/screenshot.png', fullPage: true }); await browser.close();
import { chromium } from 'playwright'; const browser = await chromium.launch(); const page = await browser.newPage(); await page.goto('https://news.ycombinator.com'); const stories = await page.$$eval('.titleline > a', links => links.slice(0, 5).map(a => ({ title: a.innerText, url: a.href })) ); console.log(JSON.stringify(stories, null, 2)); await browser.close();
await page.goto('https://example.com/login'); await page.fill('input[name="email"]', 'user@example.com'); await page.fill('input[name="password"]', 'password'); await page.click('button[type="submit"]');
// Wait for network idle (SPA) await page.goto(url, { waitUntil: 'networkidle' }); // Wait for specific element await page.waitForSelector('.results', { timeout: 10000 }); // Wait for condition await page.waitForFunction(() => document.querySelectorAll('.item').length > 0 );
import fs from 'fs'; const SESSION_FILE = 'tmp/session.json'; let context; if (fs.existsSync(SESSION_FILE)) { context = await browser.newContext({ storageState: SESSION_FILE }); } else { context = await browser.newContext(); } const page = await context.newPage(); // ... login ... await context.storageState({ path: SESSION_FILE });
// Headless (default, fastest) await chromium.launch({ headless: true }); // Headed (see the browser) await chromium.launch({ headless: false }); // Slow motion (debugging) await chromium.launch({ headless: false, slowMo: 100 });
// CSS await page.click('button.submit'); await page.fill('input#email', 'text'); // Text content await page.click('text=Submit'); await page.click('text=/log\s*in/i'); // regex // XPath await page.click('xpath=//button[@type="submit"]'); // ARIA role await page.click('role=button[name="Submit"]'); // Test ID (most stable) await page.click('[data-testid="submit-btn"]'); // Chain selectors await page.click('nav >> text=Settings'); See references/selectors.md for complete selector guide.
try { await page.goto('https://example.com', { timeout: 30000 }); const hasResults = await page.locator('.results').isVisible().catch(() => false); if (!hasResults) { console.log('No results'); process.exit(0); } } catch (error) { console.error('Error:', error.message); await page.screenshot({ path: 'tmp/error.png' }); process.exit(1); } finally { await browser.close(); }
examples/screenshot.mjs - Full-page screenshots examples/scrape.mjs - Data extraction examples/form-interaction.mjs - Form automation examples/login-session.mjs - Persistent sessions
scripts/minimal-template.mjs - Clean starting point scripts/screenshot-template.mjs - Configurable screenshot scripts/scrape-template.mjs - Data scraping scaffold Copy templates: cp scripts/minimal-template.mjs tmp/my-task.mjs # Edit tmp/my-task.mjs, then run: node tmp/my-task.mjs
# Record interactions to generate code npx playwright codegen https://example.com # Debug selectors npx playwright codegen --target javascript https://example.com # Show trace npx playwright show-trace tmp/trace.zip
references/selectors.md - Complete selector guide (CSS, text, XPath, ARIA, test-id) references/debugging.md - Debugging techniques (headless, slowMo, screenshots) references/troubleshooting.md - Common errors and solutions
Always put scripts in tmp/ โ it's gitignored Use .mjs extension for ES modules (no type: module needed) Add console.log() liberally for debugging Use page.screenshot() when things go wrong For complex sites, add await page.waitForLoadState('networkidle') See references/debugging.md for detailed debugging guide See references/troubleshooting.md for common issues
Code helpers, APIs, CLIs, browser automation, testing, and developer operations.
Largest current source with strong distribution and engagement signals.