playwright

Playwright Browser Automation

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "playwright" with this command: npx skills add tianqiye/tockstalk-bot/tianqiye-tockstalk-bot-playwright

Playwright Browser Automation

Overview

This skill enables general-purpose browser automation using Playwright. It's designed for one-off automation tasks, interactive testing, and ad-hoc browser scripting. The skill includes intelligent utilities for session persistence, error handling, server detection, and common automation patterns extracted from production bots.

When to Use This Skill

Invoke this skill when the user requests:

  • "Automate logging into this website"

  • "Take screenshots of this page"

  • "Fill out this form automatically"

  • "Test this login flow"

  • "Extract data from this website"

  • "Click through this multi-step process"

  • Any interactive browser automation task

DO NOT use for scheduled monitoring - use the web-monitor-bot skill instead for cron-based periodic checks with analytics.

Quick Start

  1. Installation

Install dependencies in your project or test directory:

npm install playwright playwright-extra puppeteer-extra-plugin-stealth dotenv npx playwright install chromium

  1. Run a Script

Execute automation scripts using the provided runner:

node run.js path/to/your-script.js

Or run inline code:

node run.js "await page.goto('https://example.com'); await page.screenshot({ path: 'screenshot.png' });"

Or pipe code via stdin:

cat script.js | node run.js

  1. Use Helper Utilities

Import the utilities library for advanced patterns:

const utils = require('./lib/utils.js');

// Safe click with retry await utils.safeClick(page, 'button.submit', { retries: 3 });

// Type with human-like delays await utils.humanType(page, '#email', 'user@example.com');

// Session management await utils.saveCookies(context, 'session.json'); await utils.loadCookies(context, 'session.json');

// Screenshot with error handling await utils.captureScreenshot(page, 'step-1.png');

Core Features

Session Persistence

Save and restore browser sessions to avoid repeated logins:

const { saveCookies, loadCookies } = require('./lib/utils.js');

// After successful login await saveCookies(context, 'my-session.json');

// On subsequent runs const hasCookies = await loadCookies(context, 'my-session.json'); if (hasCookies) { console.log('Session restored!'); await page.goto(protectedUrl); } else { // Perform login }

Benefits:

  • Skip login flows on repeated runs

  • Maintain authentication state

  • Avoid rate limiting from frequent logins

  • Faster execution times

Development Server Detection

Automatically detect running development servers before executing scripts:

const { detectDevServers } = require('./lib/utils.js');

const servers = await detectDevServers(); if (servers.length > 0) { console.log('Found servers:', servers); // Use detected server URLs in your automation }

Stealth Mode

Built-in stealth plugin to bypass basic bot detection:

const { chromium } = require('playwright-extra'); const stealth = require('puppeteer-extra-plugin-stealth')();

chromium.use(stealth);

const browser = await chromium.launch({ headless: false, args: ['--no-sandbox', '--disable-setuid-sandbox'] });

Error Handling & Retries

Robust error handling with automatic retries:

const { retryWithBackoff } = require('./lib/utils.js');

// Retry an operation up to 3 times with exponential backoff const result = await retryWithBackoff(async () => { await page.waitForSelector('.dynamic-content', { timeout: 10000 }); return await page.textContent('.dynamic-content'); }, { maxRetries: 3, initialDelay: 1000 });

Common Automation Patterns

Pattern 1: Login Flow Automation

const { chromium } = require('playwright-extra'); const stealth = require('puppeteer-extra-plugin-stealth')(); const { saveCookies, loadCookies, humanType, safeClick } = require('./lib/utils.js');

chromium.use(stealth);

const browser = await chromium.launch({ headless: false }); const context = await browser.newContext(); const page = await context.newPage();

// Try to load saved session const hasCookies = await loadCookies(context, 'session.json');

if (!hasCookies) { // Perform login await page.goto('https://example.com/login'); await humanType(page, '#email', 'user@example.com'); await humanType(page, '#password', 'password123'); await safeClick(page, 'button[type="submit"]');

await page.waitForNavigation();

// Save session for next time await saveCookies(context, 'session.json'); console.log('Login successful, session saved!'); } else { console.log('Using saved session'); await page.goto('https://example.com/dashboard'); }

await browser.close();

Pattern 2: Form Filling & Submission

const { humanType, safeClick, captureScreenshot } = require('./lib/utils.js');

await page.goto('https://example.com/form');

// Fill form fields with human-like typing await humanType(page, '#name', 'John Doe'); await humanType(page, '#email', 'john@example.com', { delay: 50 }); await page.selectOption('#country', 'US'); await page.check('#terms');

// Screenshot before submission await captureScreenshot(page, 'before-submit.png');

// Submit with retry logic await safeClick(page, 'button#submit', { retries: 3 });

// Wait for success await page.waitForSelector('.success-message', { timeout: 15000 }); await captureScreenshot(page, 'after-submit.png');

Pattern 3: Data Extraction

const { retryWithBackoff } = require('./lib/utils.js');

await page.goto('https://example.com/data');

// Extract data with retry logic const data = await retryWithBackoff(async () => { await page.waitForSelector('.data-table', { timeout: 10000 });

const rows = await page.$$('.data-table tr'); const results = [];

for (const row of rows) { const cells = await row.$$('td'); const rowData = await Promise.all(cells.map(cell => cell.textContent())); results.push(rowData); }

return results; }, { maxRetries: 3 });

console.log('Extracted data:', data);

Pattern 4: Multi-Step Workflow

const { safeClick, humanType, captureScreenshot } = require('./lib/utils.js');

// Step 1: Search await page.goto('https://example.com'); await humanType(page, '#search', 'playwright automation'); await safeClick(page, 'button.search'); await page.waitForTimeout(2000); await captureScreenshot(page, 'step-1-search.png');

// Step 2: Filter results await safeClick(page, '.filter-option[data-filter="recent"]'); await page.waitForTimeout(1000); await captureScreenshot(page, 'step-2-filtered.png');

// Step 3: Select item await safeClick(page, '.result-item:first-child'); await page.waitForNavigation(); await captureScreenshot(page, 'step-3-details.png');

// Step 4: Complete action await safeClick(page, 'button.add-to-cart'); await page.waitForSelector('.cart-notification', { timeout: 5000 }); await captureScreenshot(page, 'step-4-added.png');

Pattern 5: Screenshot Capture with Responsive Testing

const { captureScreenshot } = require('./lib/utils.js');

const viewports = [ { width: 1920, height: 1080, name: 'desktop' }, { width: 768, height: 1024, name: 'tablet' }, { width: 375, height: 667, name: 'mobile' } ];

for (const viewport of viewports) { await page.setViewportSize({ width: viewport.width, height: viewport.height }); await page.goto('https://example.com'); await captureScreenshot(page, screenshot-${viewport.name}.png); }

Pattern 6: Cloudflare Challenge Handling (Production-Ready)

const { detectCloudflare, saveCookies } = require('./lib/utils.js');

await page.goto('https://protected-site.com');

// Intelligent Cloudflare detection with 90s polling try { const wasBlocked = await detectCloudflare(page, context, 'initial page load', { maxWaitSeconds: 90, // Poll for up to 90 seconds pollIntervalSeconds: 10, // Check every 10 seconds cookiePath: 'session.json' // Save cookies immediately after solve });

if (wasBlocked) { console.log('Cloudflare challenge auto-solved! Proceeding...'); } else { console.log('No Cloudflare challenge detected'); }

// Continue with automation await page.click('.protected-button');

} catch (error) { // Challenge not solved after 90s console.error('Cloudflare blocked:', error.message); // Screenshots auto-saved: cloudflare-detected.png, cloudflare-timeout.png process.exit(1); }

Features:

  • Smart polling: Checks every 10s for up to 90s (not single wait)

  • Block tracking: Tracks consecutive/total blocks in cloudflare-blocks.json

  • Auto-screenshots: cloudflare-detected.png (when detected), cloudflare-cleared.png (when solved), cloudflare-timeout.png (if fails)

  • Cookie persistence: Saves session immediately after challenge clears

  • Progress updates: Console logs every 30s during wait

Block Tracking:

const { getCloudflareBlocks } = require('./lib/utils.js');

const blocks = getCloudflareBlocks(); console.log(Consecutive blocks: ${blocks.consecutive}); console.log(Total blocks: ${blocks.total}); console.log(Last 10 events:, blocks.history.slice(-10));

Utility Functions Reference

Session Management

// Save browser cookies to file await saveCookies(context, filepath);

// Load browser cookies from file const restored = await loadCookies(context, filepath); // Returns: true if cookies were loaded, false if file doesn't exist

Safe Interactions

// Click with automatic retry and error handling await safeClick(page, selector, { retries: 3, timeout: 10000 });

// Click with human-like mouse movement (curved path + random position) await humanClick(page, selector, { timeout: 10000 });

// Type with human-like delays (randomized between chars) await humanType(page, selector, text, { delay: 100 });

// Generate random delay for timing variation const delay = randomDelay(1000, 2500); // Returns random ms between 1000-2500 await page.waitForTimeout(delay);

Screenshots

// Capture screenshot with automatic error handling await captureScreenshot(page, filepath);

Retry Logic

// Retry async operation with exponential backoff const result = await retryWithBackoff(asyncFunction, { maxRetries: 3, initialDelay: 1000, backoffMultiplier: 2 });

Server Detection

// Detect running development servers on localhost const servers = await detectDevServers(); // Returns: Array of { port, url } objects

Advanced Configuration

Timeout Strategies

Implement dynamic timeouts based on conditions:

const isPeakTime = new Date().getHours() === 17; // 5 PM const timeout = isPeakTime ? 60000 : 30000;

await page.goto(url, { timeout }); await page.waitForSelector(selector, { timeout });

Headless vs. Headed Mode

// Headed (visible browser) - useful for debugging const browser = await chromium.launch({ headless: false });

// Headless (background) - useful for production/CI const browser = await chromium.launch({ headless: true });

Custom User Agents

const context = await browser.newContext({ userAgent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36' });

Browser Arguments

const browser = await chromium.launch({ headless: false, args: [ '--no-sandbox', '--disable-setuid-sandbox', '--disable-dev-shm-usage', '--disable-blink-features=AutomationControlled' ] });

Best Practices

  1. Use Session Persistence

Always save cookies after authentication to speed up subsequent runs:

// After login await saveCookies(context, 'session.json');

// Before automation const hasCookies = await loadCookies(context, 'session.json');

  1. Implement Retry Logic

Use retries for flaky network requests or dynamic content:

await retryWithBackoff(async () => { await page.waitForSelector('.dynamic-element', { timeout: 10000 }); return await page.textContent('.dynamic-element'); }, { maxRetries: 3 });

  1. Capture Screenshots on Errors

Always save evidence when things go wrong:

try { await page.click('.submit-button'); } catch (error) { await captureScreenshot(page, 'error.png'); throw error; }

  1. Use Human-Like Interactions

Avoid detection by simulating natural human behavior:

const { humanClick, humanType, randomDelay } = require('./lib/utils.js');

// Bad: Instant, robotic interactions await page.fill('#input', text); await page.click('button');

// Good: Human-like behavior await humanType(page, '#input', text, { delay: 50 }); await page.waitForTimeout(randomDelay(500, 1500)); // Random pause await humanClick(page, 'button'); // Mouse movement + random click position

Anti-Detection Checklist:

  • ✅ Use humanClick() instead of .click() (adds mouse movement)

  • ✅ Use humanType() instead of .fill() (adds typing delays)

  • ✅ Use randomDelay() for all waitForTimeout() calls (avoid fixed timing)

  • ✅ Add random pauses between actions (humans don't act instantly)

  • ✅ Handle Cloudflare with detectCloudflare() (smart polling + tracking)

  1. Clean Up Resources

Always close browsers and remove temporary files:

try { // ... automation code ... } finally { await browser.close(); // Clean up lock files, temp files, etc. }

File Organization

Recommended structure for automation projects:

my-automation/ ├── run.js # Script runner ├── lib/ │ └── utils.js # Utility functions ├── scripts/ │ ├── login.js # Login automation │ ├── scrape.js # Data extraction │ └── test-flow.js # Test workflows ├── sessions/ │ └── cookies.json # Saved sessions ├── screenshots/ # Captured images ├── .env # Environment variables └── package.json

Environment Variables

Use .env files for configuration:

.env

TARGET_URL=https://example.com LOGIN_EMAIL=user@example.com LOGIN_PASSWORD=secretpass HEADLESS=false TIMEOUT=30000

Load in scripts:

require('dotenv').config();

const targetUrl = process.env.TARGET_URL; const headless = process.env.HEADLESS === 'true'; const timeout = parseInt(process.env.TIMEOUT) || 30000;

Troubleshooting

Script not finding elements

  • Use page.waitForSelector() before interactions

  • Increase timeout values for slow-loading pages

  • Verify selectors in browser DevTools

  • Use captureScreenshot() to see page state

Bot detection issues

  • Enable stealth mode with playwright-extra

  • Use humanType() instead of fill()

  • Add random delays: await page.waitForTimeout(Math.random() * 2000 + 1000)

  • Use realistic user agents

  • Handle Cloudflare challenges with manual intervention pattern

Session not persisting

  • Ensure cookies are saved after successful login

  • Check file permissions on cookie file

  • Verify cookie expiration times

  • Re-login and save fresh cookies

Timeouts on slow pages

  • Increase timeout values: { timeout: 60000 }

  • Use waitUntil: 'domcontentloaded' instead of 'load'

  • Implement retry logic with backoff

  • Check network tab for slow requests

Comparison with web-monitor-bot

Feature playwright (this skill) web-monitor-bot

Use Case One-off automation tasks Scheduled monitoring

Execution Manual/on-demand Cron-based periodic

Analytics No Yes (built-in dashboard)

Notifications Manual implementation Slack/webhook integration

Session Management Yes (utilities) Yes (built-in)

Concurrency Control Manual Lock files (built-in)

Best For Testing, scraping, workflows Availability tracking, alerts

Examples

See the examples/ directory for complete working scripts:

  • examples/login-flow.js

  • Full login automation with session persistence

  • examples/form-submission.js

  • Multi-step form filling

  • examples/data-extraction.js

  • Scraping with retry logic

  • examples/screenshot-tool.js

  • Responsive screenshot capture

  • examples/cloudflare-handler.js

  • Handling bot protection

Resources

Dependencies

  • Playwright - Browser automation framework

  • playwright-extra - Plugin support

  • puppeteer-extra-plugin-stealth - Bot detection bypass

Documentation

  • Playwright API Docs

  • Selectors Guide

  • Best Practices

License

MIT

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

Automation

web-monitor-bot

No summary provided by upstream source.

Repository SourceNeeds Review
Automation

playwright

No summary provided by upstream source.

Repository SourceNeeds Review
100-oakoss
Automation

playwright

No summary provided by upstream source.

Repository SourceNeeds Review
Automation

playwright

No summary provided by upstream source.

Repository SourceNeeds Review