Requirements
- Target platform
- OpenClaw
- Install method
- Manual import
- Extraction
- Extract archive
- Prerequisites
- OpenClaw
- Primary doc
- SKILL.md
Browser automation using Playwright API directly. Navigate websites, interact with elements, extract data, take screenshots, generate PDFs, record videos, and automate complex workflows. More reliable than MCP approach.
Browser automation using Playwright API directly. Navigate websites, interact with elements, extract data, take screenshots, generate PDFs, record videos, and automate complex workflows. More reliable than MCP approach.
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.
Direct Playwright API for reliable browser automation without MCP complexity.
# Install Playwright npm install -g playwright # Install browsers (one-time, ~100MB each) npx playwright install chromium # Optional: npx playwright install firefox npx playwright install webkit # For system dependencies on Ubuntu/Debian: sudo npx playwright install-deps chromium
const { chromium } = require('playwright'); (async () => { const browser = await chromium.launch({ headless: true }); const page = await browser.newPage(); await page.goto('https://example.com'); await page.screenshot({ path: 'screenshot.png' }); await browser.close(); })();
// โ GOOD: Uses auto-waiting and retries await page.getByRole('button', { name: 'Submit' }).click(); await page.getByLabel('Username').fill('user'); await page.getByPlaceholder('Search').fill('query'); // โ BAD: May fail if element not ready await page.click('#submit');
// โ GOOD: Resilient to DOM changes await page.getByRole('heading', { name: 'Welcome' }); await page.getByText('Sign in'); await page.getByTestId('login-button'); // โ BAD: Brittle CSS selectors await page.click('.btn-primary > div:nth-child(2)');
// Wait for network idle await page.goto('https://spa-app.com', { waitUntil: 'networkidle' }); // Wait for specific element await page.waitForSelector('.results-loaded'); await page.waitForFunction(() => document.querySelectorAll('.item').length > 0);
// Each context = isolated session (cookies, storage) const context = await browser.newContext(); const page = await context.newPage(); // Multiple pages in one context const page2 = await context.newPage();
// Mock API responses await page.route('**/api/users', route => { route.fulfill({ status: 200, body: JSON.stringify({ users: [] }) }); }); // Block resources await page.route('**/*.{png,jpg,css}', route => route.abort());
// Fill form await page.goto('https://example.com/login'); await page.getByLabel('Username').fill('myuser'); await page.getByLabel('Password').fill('mypass'); await page.getByRole('button', { name: 'Sign in' }).click(); // Wait for navigation/result await page.waitForURL('/dashboard'); await expect(page.getByText('Welcome')).toBeVisible();
// Extract table data const rows = await page.$$eval('table tr', rows => rows.map(row => ({ name: row.querySelector('td:nth-child(1)')?.textContent, price: row.querySelector('td:nth-child(2)')?.textContent })) ); // Extract with JavaScript evaluation const data = await page.evaluate(() => { return Array.from(document.querySelectorAll('.product')).map(p => ({ title: p.querySelector('.title')?.textContent, price: p.querySelector('.price')?.textContent })); });
// Full page screenshot await page.screenshot({ path: 'full.png', fullPage: true }); // Element screenshot await page.locator('.chart').screenshot({ path: 'chart.png' }); // PDF (Chromium only) await page.pdf({ path: 'page.pdf', format: 'A4', printBackground: true });
const context = await browser.newContext({ recordVideo: { dir: './videos/', size: { width: 1920, height: 1080 } } }); const page = await context.newPage(); // ... do stuff ... await context.close(); // Video saved automatically
const context = await browser.newContext({ viewport: { width: 375, height: 667 }, userAgent: 'Mozilla/5.0 (iPhone; CPU iPhone OS 14_0)', isMobile: true, hasTouch: true });
// Method 1: HTTP Basic Auth const context = await browser.newContext({ httpCredentials: { username: 'user', password: 'pass' } }); // Method 2: Cookies await context.addCookies([ { name: 'session', value: 'abc123', domain: '.example.com', path: '/' } ]); // Method 3: Local Storage await page.evaluate(() => { localStorage.setItem('token', 'xyz'); }); // Method 4: Reuse auth state await context.storageState({ path: 'auth.json' }); // Later: await browser.newContext({ storageState: 'auth.json' });
// Upload await page.setInputFiles('input[type="file"]', '/path/to/file.pdf'); // Download const [download] = await Promise.all([ page.waitForEvent('download'), page.click('a[download]') ]); await download.saveAs('/path/to/save/' + download.suggestedFilename());
page.on('dialog', dialog => { if (dialog.type() === 'alert') dialog.accept(); if (dialog.type() === 'confirm') dialog.accept(); if (dialog.type() === 'prompt') dialog.accept('My answer'); });
// Frame by name const frame = page.frame('frame-name'); await frame.click('button'); // Frame by locator const frame = page.frameLocator('iframe').first(); await frame.getByRole('button').click(); // Shadow DOM await page.locator('my-component').locator('button').click();
await context.tracing.start({ screenshots: true, snapshots: true }); // ... run tests ... await context.tracing.stop({ path: 'trace.zip' }); // View at https://trace.playwright.dev
const browser = await chromium.launch({ headless: true, // Run without UI slowMo: 50, // Slow down by 50ms (for debugging) devtools: false, // Open DevTools args: ['--no-sandbox', '--disable-setuid-sandbox'] // Docker/Ubuntu }); const context = await browser.newContext({ viewport: { width: 1920, height: 1080 }, locale: 'ru-RU', timezoneId: 'Europe/Moscow', geolocation: { latitude: 55.7558, longitude: 37.6173 }, permissions: ['geolocation'], userAgent: 'Custom Agent', bypassCSP: true, // Bypass Content Security Policy });
// Retry with timeout try { await page.getByRole('button', { name: 'Load' }).click({ timeout: 10000 }); } catch (e) { console.log('Button not found or not clickable'); } // Check if element exists const hasButton = await page.getByRole('button').count() > 0; // Wait with custom condition await page.waitForFunction(() => document.querySelectorAll('.loaded').length >= 10 );
For Playwright browser installation: # /etc/sudoers.d/playwright username ALL=(root) NOPASSWD: /usr/bin/npx playwright install-deps * username ALL=(root) NOPASSWD: /usr/bin/npx playwright install *
Playwright Docs API Reference Best Practices Locators Guide
Code helpers, APIs, CLIs, browser automation, testing, and developer operations.
Largest current source with strong distribution and engagement signals.