Programmatic web automation using Playwright Python — data extraction, form filling, multi-step workflows, auth session management, screenshot/PDF capture, and anti-detection patterns. Use for scripted automation tasks, not interactive MCP-based browser control.
pip install playwright && playwright install chromium
pip install playwright-stealth # optional, for anti-detection
| Skill | Use Case |
|---|---|
browser-automation | Scripted automation, data pipelines, form bots |
webapp-testing | QA assertions, visual regression, test suites |
chrome-browser | Interactive MCP DevTools control |
NEVER USE time.sleep() — use page.wait_for_selector() or wait_for_load_state()
with sync_playwright() as p:
context = p.chromium.launch(headless=True).new_context(
user_agent="Mozilla/5.0 ...", viewport={"width": 1280, "height": 720})
page = context.new_page()
page.goto(url); page.wait_for_load_state("networkidle")
items = [i.inner_text() for i in page.get_by_role("listitem").all()]
page.get_by_label("Email").fill("[email protected]")
page.get_by_label("Password").fill("secret")
with page.expect_navigation():
page.get_by_role("button", name="Submit").click()
page.screenshot(path="full.png", full_page=True)
page.pdf(path="page.pdf", format="A4", print_background=True)
# Save session
context.storage_state(path="auth-state.json")
# Reuse session
context = browser.new_context(storage_state="auth-state.json")
browser = p.chromium.launch(args=["--disable-blink-features=AutomationControlled"])
context = browser.new_context(user_agent="...", locale="en-US", timezone_id="America/New_York")
page.add_init_script("Object.defineProperty(navigator, 'webdriver', {get: () => undefined})")
.claude/context/tmp/ as structured JSON.claude/context/artifacts/auth-state.json — add to .gitignore| Anti-Pattern | Correct Approach |
|---|---|
time.sleep() for waits | page.wait_for_selector() / wait_for_load_state() |
| CSS selectors for forms | get_by_label(), get_by_role() |
| Re-login each run | context.storage_state() persistence |
| Committing auth state | Add auth-state.json to .gitignore |
Before starting: Read .claude/context/memory/learnings.md
After completing:
.claude/context/memory/learnings.md.claude/context/memory/issues.mdASSUME INTERRUPTION: If it's not in memory, it didn't happen.