playwright-automation
Execute complex browser automation using Playwright Python. Use for video recording, multi-page navigation, data extraction. Triggers on "browser script", "record video of website", "extract data from webpage".
allowed_tools: Read, Write, Edit, Bash, Glob, Grep
$ Installieren
git clone https://github.com/brianclaridge/.claude /tmp/.claude && cp -r /tmp/.claude/skills/playwright-automation ~/.claude/skills/-claude// tip: Run this command in your terminal to install the skill
SKILL.md
name: playwright-automation description: Execute complex browser automation using Playwright Python. Use for video recording, multi-page navigation, data extraction. Triggers on "browser script", "record video of website", "extract data from webpage". allowed-tools: Read, Write, Edit, Bash, Glob, Grep
Playwright Automation Skill
Python-based browser automation for complex workflows requiring video recording, multi-page navigation, or data extraction.
When to Use
- Video recording of browser interactions
- Multi-page navigation sequences
- Data extraction with post-processing
- Form filling with validation
- Screenshot sequences or comparisons
- Any automation requiring Python logic
Output Directories
${CLAUDE_PATH}/.data/playwright/
âââ screencaps/ # Screenshots (.png, .jpg)
âââ videos/ # Recordings (.webm)
âââ pdfs/ # Generated PDFs
âââ traces/ # Debug traces (.zip)
âââ data/ # Extracted data (.json, .csv)
Wait Strategy Guide
| Strategy | Use Case | Speed | Reliability |
|---|---|---|---|
domcontentloaded | General web pages (default) | Fast (1-3s) | High |
load | Media-heavy sites, SPAs | Medium (2-5s) | High |
networkidle | Static sites that fully settle | Slow (5-30s+) | Variable |
Recommendation: Use domcontentloaded (default) for most sites. Only use networkidle for static pages where you need all resources loaded.
Utility Scripts
Screenshot Utility
uv run --directory ${CLAUDE_PATH} python \
apps/src/claude_apps/skills/playwright_automation/screenshot.py <url> \
[--full-page] \
[--wait-until domcontentloaded|load|networkidle] \
[--timeout 30000] \
[--output filename.png]
Video Recorder
uv run --directory ${CLAUDE_PATH} python \
apps/src/claude_apps/skills/playwright_automation/video_recorder.py <url> \
[--duration 10] \
[--wait-until domcontentloaded|load|networkidle] \
[--timeout 30000] \
[--output filename.webm]
Script Template
Use this template for custom automation scripts:
#!/usr/bin/env python3
"""
Browser automation script: [DESCRIPTION]
Output: ${CLAUDE_PATH}/.data/playwright/[TYPE]/[FILENAME]
"""
import os
from datetime import datetime
import structlog
from playwright.sync_api import sync_playwright, TimeoutError as PlaywrightTimeoutError
# Use CLAUDE_PATH environment variable with fallback
CLAUDE_PATH = os.environ.get("CLAUDE_PATH", "/workspace/.claude")
SCREENCAP_DIR = os.path.join(CLAUDE_PATH, ".data/playwright/screencaps")
VIDEO_DIR = os.path.join(CLAUDE_PATH, ".data/playwright/videos")
DATA_DIR = os.path.join(CLAUDE_PATH, ".data/playwright/data")
LOG_DIR = os.path.join(CLAUDE_PATH, ".data/logs/playwright")
os.makedirs(SCREENCAP_DIR, exist_ok=True)
os.makedirs(VIDEO_DIR, exist_ok=True)
os.makedirs(DATA_DIR, exist_ok=True)
os.makedirs(LOG_DIR, exist_ok=True)
# Configure structlog
structlog.configure(
processors=[
structlog.processors.add_log_level,
structlog.processors.TimeStamper(fmt="iso"),
structlog.dev.ConsoleRenderer(),
],
wrapper_class=structlog.make_filtering_bound_logger(20), # INFO+
)
logger = structlog.get_logger()
def main():
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
with sync_playwright() as p:
browser = p.chromium.launch(headless=True)
context = browser.new_context(
viewport={"width": 1920, "height": 1080},
record_video_dir=VIDEO_DIR,
record_video_size={"width": 1280, "height": 720}
)
page = context.new_page()
try:
# Navigate with fallback
page.goto("https://example.com", wait_until="domcontentloaded", timeout=30000)
page.wait_for_timeout(2000) # Allow dynamic content to load
# Your automation code here
page.screenshot(path=f"{SCREENCAP_DIR}/example_{timestamp}.png", full_page=True)
except PlaywrightTimeoutError:
logger.error("Navigation timeout")
raise
finally:
# Get video path BEFORE closing page
video = page.video
video_path = video.path() if video else None
page.close()
if video_path:
print(f"Video saved: {video_path}")
context.close()
browser.close()
if __name__ == "__main__":
main()
Common Patterns
Screenshot Capture
SCREENCAP_DIR = "${CLAUDE_PATH}/.data/playwright/screencaps"
# Full page
page.screenshot(path=f"{SCREENCAP_DIR}/full.png", full_page=True)
# Viewport only
page.screenshot(path=f"{SCREENCAP_DIR}/viewport.png")
# Specific element
page.locator("#element").screenshot(path=f"{SCREENCAP_DIR}/element.png")
# With options
page.screenshot(
path=f"{SCREENCAP_DIR}/custom.jpg",
type="jpeg",
quality=80,
clip={"x": 0, "y": 0, "width": 800, "height": 600}
)
Video Recording
VIDEO_DIR = "${CLAUDE_PATH}/.data/playwright/videos"
# Enable in context creation
context = browser.new_context(
record_video_dir=VIDEO_DIR,
record_video_size={"width": 1280, "height": 720}
)
page = context.new_page()
# ... perform actions ...
# CRITICAL: Get path BEFORE closing
video = page.video
video_path = video.path() if video else None
page.close() # Video finalized here
Form Interaction
page.fill("#username", "testuser")
page.fill("#password", "testpass")
page.click("button[type='submit']")
page.select_option("#country", "US")
page.check("#agree-terms")
page.set_input_files("#file-upload", "/path/to/file.pdf")
Data Extraction
import json
DATA_DIR = "${CLAUDE_PATH}/.data/playwright/data"
title = page.locator("h1").text_content()
items = page.locator(".item").all()
data = [item.text_content() for item in items]
with open(f"{DATA_DIR}/extracted.json", "w") as f:
json.dump({"title": title, "items": data}, f, indent=2)
Wait Strategies
# Wait for specific element
page.wait_for_selector("#dynamic-content")
# Wait for URL change
page.wait_for_url("**/success")
# Wait for load state (use sparingly)
page.wait_for_load_state("networkidle")
# Custom timeout
page.wait_for_selector("#slow-element", timeout=60000)
# Fixed delay for dynamic content
page.wait_for_timeout(2000)
Error Handling with Fallback
from playwright.sync_api import TimeoutError as PlaywrightTimeoutError
try:
page.goto(url, wait_until="networkidle", timeout=30000)
except PlaywrightTimeoutError:
# Fallback to faster strategy
page.goto(url, wait_until="domcontentloaded", timeout=30000)
Tracing for Debug
DATA_DIR = "${CLAUDE_PATH}/.data/playwright/data"
context.tracing.start(screenshots=True, snapshots=True, sources=True)
# ... perform actions ...
context.tracing.stop(path=f"{DATA_DIR}/trace.zip")
# View with: playwright show-trace trace.zip
Execution
Run scripts using uv from the Claude root:
uv run --directory ${CLAUDE_PATH} python apps/src/claude_apps/skills/playwright_automation/<script>.py
Or for custom scripts in other locations:
uv run --directory ${CLAUDE_PATH} python /path/to/custom_script.py
Troubleshooting
| Issue | Solution |
|---|---|
| Browser launch fails | Ensure headless=True in container |
| Element not found | Use wait_for_selector() before interaction |
| Video not saved | Get page.video.path() BEFORE page.close() |
| Permission denied | Check output directory permissions |
| Timeout errors | Use domcontentloaded instead of networkidle |
| Streaming sites timeout | Add page.wait_for_timeout(3000) after navigation |
Repository

brianclaridge
Author
brianclaridge/.claude/skills/playwright-automation
2
Stars
1
Forks
Updated1d ago
Added6d ago