{"slug":"playwright-browser-automation","title":"Playwright Browser Automation: CLI, Scripting, and Agent Integration","tags":["playwright","browser-automation","testing","scraping","screenshots"],"agent_summary":"Playwright CLI quick reference and scripting patterns — navigation, clicks, form fills, screenshots, PDF capture, session state persistence, auth replay, and multi-session parallel automation.","trigger_phrases":["Playwright","browser automation","take screenshot","fill form","Playwright CLI","headless browser","playwright screenshot","playwright goto"],"runnable":false,"markdown":"\n## Overview\n\nPlaywright is the default browser automation tool for agent workflows. Use it for screenshots, form automation, auth state capture, and UI regression verification.\n\n## Tool Selection\n\n| Task | Tool |\n|------|------|\n| Local screenshots / UI reproduction | Playwright (local, free, default) |\n| Headless automation with annotated snapshots | playwright-cli agent tool |\n| Site blocks headless / anti-bot needed | Steel.dev |\n| Need video proof of state | Hyperbrowser |\n| Just need page content, no browser | Firecrawl |\n\nDefault to local Playwright. Only escalate to cloud tools when the site blocks headless.\n\n## playwright-cli Quick Reference\n\n```bash\n# Open browser\nplaywright-cli open\n\n# Navigate\nplaywright-cli goto https://example.com\n\n# Interact using snapshot refs\nplaywright-cli click e15\nplaywright-cli type \"search query\"\nplaywright-cli press Enter\n\n# Screenshot\nplaywright-cli screenshot\n\n# Close\nplaywright-cli close\n```\n\n## npx playwright Commands\n\n```bash\n# Viewport screenshot\nnpx playwright screenshot https://example.com out.png\n\n# Full-page screenshot\nnpx playwright screenshot --full-page https://example.com out.png\n\n# PDF capture\nnpx playwright pdf https://example.com out.pdf\n\n# Save auth state\nnpx playwright open --save-storage=auth.json https://example.com\n\n# Reuse auth state\nnpx playwright open --load-storage=auth.json https://example.com\n```\n\n## Browser Selection\n\n```bash\nplaywright-cli open --browser=chrome\nplaywright-cli open --browser=firefox\nplaywright-cli open --browser=webkit\nplaywright-cli open --browser=msedge\n```\n\n## Session Management\n\n```bash\n# Named persistent session\nplaywright-cli -s=mysession open https://example.com --persistent\n\n# Continue in same session\nplaywright-cli -s=mysession click e6\n\n# Close named session\nplaywright-cli -s=mysession close\n```\n\n## Scripted Auth Capture\n\nCapture a logged-in session for reuse across automation runs:\n\n```python\nfrom playwright.sync_api import sync_playwright\n\nwith sync_playwright() as p:\n    browser = p.chromium.launch(headless=False)\n    ctx = browser.new_context()\n    page = ctx.new_page()\n    page.goto(\"https://app.example.com/login\")\n    input(\"Log in manually, then press Enter...\")\n    ctx.storage_state(path=\"auth.json\")\n    browser.close()\n```\n\nThen replay in automation:\n\n```python\nwith sync_playwright() as p:\n    browser = p.chromium.launch(headless=True)\n    ctx = browser.new_context(storage_state=\"auth.json\")\n    page = ctx.new_page()\n    page.goto(\"https://app.example.com/dashboard\")\n    page.screenshot(path=\"dashboard.png\")\n```\n\n## Parallel Sessions\n\n```python\nfrom playwright.sync_api import sync_playwright\nfrom concurrent.futures import ThreadPoolExecutor\n\ndef capture(url):\n    with sync_playwright() as p:\n        browser = p.chromium.launch(headless=True)\n        page = browser.new_page()\n        page.goto(url)\n        page.screenshot(path=f\"{url.split('//')[1].replace('/', '_')}.png\")\n        browser.close()\n\nurls = [\"https://site1.com\", \"https://site2.com\", \"https://site3.com\"]\nwith ThreadPoolExecutor(max_workers=3) as executor:\n    executor.map(capture, urls)\n```\n\n## Form Automation Pattern\n\n```python\npage.fill(\"input[name='email']\", \"user@example.com\")\npage.fill(\"input[name='password']\", \"secret\")\npage.click(\"button[type='submit']\")\npage.wait_for_url(\"**/dashboard\")\npage.screenshot(path=\"post-login.png\")\n```\n\n## Waiting Strategies\n\n```python\n# Wait for network idle\npage.goto(url, wait_until=\"networkidle\")\n\n# Wait for specific element\npage.wait_for_selector(\".dashboard-loaded\")\n\n# Wait for navigation\npage.wait_for_url(\"**/success\")\n\n# Wait for response\nwith page.expect_response(\"**/api/data\") as resp:\n    page.click(\"#load-data\")\n```\n\n## Snapshot-Based Navigation\n\nAfter any playwright-cli command, a snapshot file is generated describing interactive elements with reference IDs (e.g., `e15`, `e22`). Reference these IDs for subsequent actions instead of CSS selectors.\n\n```bash\nplaywright-cli goto https://app.example.com\n# Snapshot shows: e15 = \"Login button\", e22 = \"Email input\"\nplaywright-cli click e22\nplaywright-cli type \"user@example.com\"\nplaywright-cli click e15\n```\n\n## Proof of Work Pattern\n\nFor agent QA deliveries, screenshot every key state:\n\n```python\nstates = [\n    (\"https://app.example.com\", \"proof-landing.png\"),\n    (\"https://app.example.com/login\", \"proof-login.png\"),\n    (\"https://app.example.com/dashboard\", \"proof-dashboard.png\"),\n]\nfor url, filename in states:\n    page.goto(url)\n    page.screenshot(path=filename, full_page=True)\n```\n","html":"<h2>Overview</h2>\n<p>Playwright is the default browser automation tool for agent workflows. Use it for screenshots, form automation, auth state capture, and UI regression verification.</p>\n<h2>Tool Selection</h2>\n<p>| Task | Tool |\n|------|------|\n| Local screenshots / UI reproduction | Playwright (local, free, default) |\n| Headless automation with annotated snapshots | playwright-cli agent tool |\n| Site blocks headless / anti-bot needed | Steel.dev |\n| Need video proof of state | Hyperbrowser |\n| Just need page content, no browser | Firecrawl |</p>\n<p>Default to local Playwright. Only escalate to cloud tools when the site blocks headless.</p>\n<h2>playwright-cli Quick Reference</h2>\n<pre><code class=\"language-bash\"># Open browser\nplaywright-cli open\n\n# Navigate\nplaywright-cli goto https://example.com\n\n# Interact using snapshot refs\nplaywright-cli click e15\nplaywright-cli type \"search query\"\nplaywright-cli press Enter\n\n# Screenshot\nplaywright-cli screenshot\n\n# Close\nplaywright-cli close\n</code></pre>\n<h2>npx playwright Commands</h2>\n<pre><code class=\"language-bash\"># Viewport screenshot\nnpx playwright screenshot https://example.com out.png\n\n# Full-page screenshot\nnpx playwright screenshot --full-page https://example.com out.png\n\n# PDF capture\nnpx playwright pdf https://example.com out.pdf\n\n# Save auth state\nnpx playwright open --save-storage=auth.json https://example.com\n\n# Reuse auth state\nnpx playwright open --load-storage=auth.json https://example.com\n</code></pre>\n<h2>Browser Selection</h2>\n<pre><code class=\"language-bash\">playwright-cli open --browser=chrome\nplaywright-cli open --browser=firefox\nplaywright-cli open --browser=webkit\nplaywright-cli open --browser=msedge\n</code></pre>\n<h2>Session Management</h2>\n<pre><code class=\"language-bash\"># Named persistent session\nplaywright-cli -s=mysession open https://example.com --persistent\n\n# Continue in same session\nplaywright-cli -s=mysession click e6\n\n# Close named session\nplaywright-cli -s=mysession close\n</code></pre>\n<h2>Scripted Auth Capture</h2>\n<p>Capture a logged-in session for reuse across automation runs:</p>\n<pre><code class=\"language-python\">from playwright.sync_api import sync_playwright\n\nwith sync_playwright() as p:\n    browser = p.chromium.launch(headless=False)\n    ctx = browser.new_context()\n    page = ctx.new_page()\n    page.goto(\"https://app.example.com/login\")\n    input(\"Log in manually, then press Enter...\")\n    ctx.storage_state(path=\"auth.json\")\n    browser.close()\n</code></pre>\n<p>Then replay in automation:</p>\n<pre><code class=\"language-python\">with sync_playwright() as p:\n    browser = p.chromium.launch(headless=True)\n    ctx = browser.new_context(storage_state=\"auth.json\")\n    page = ctx.new_page()\n    page.goto(\"https://app.example.com/dashboard\")\n    page.screenshot(path=\"dashboard.png\")\n</code></pre>\n<h2>Parallel Sessions</h2>\n<pre><code class=\"language-python\">from playwright.sync_api import sync_playwright\nfrom concurrent.futures import ThreadPoolExecutor\n\ndef capture(url):\n    with sync_playwright() as p:\n        browser = p.chromium.launch(headless=True)\n        page = browser.new_page()\n        page.goto(url)\n        page.screenshot(path=f\"{url.split('//')[1].replace('/', '_')}.png\")\n        browser.close()\n\nurls = [\"https://site1.com\", \"https://site2.com\", \"https://site3.com\"]\nwith ThreadPoolExecutor(max_workers=3) as executor:\n    executor.map(capture, urls)\n</code></pre>\n<h2>Form Automation Pattern</h2>\n<pre><code class=\"language-python\">page.fill(\"input[name='email']\", \"user@example.com\")\npage.fill(\"input[name='password']\", \"secret\")\npage.click(\"button[type='submit']\")\npage.wait_for_url(\"**/dashboard\")\npage.screenshot(path=\"post-login.png\")\n</code></pre>\n<h2>Waiting Strategies</h2>\n<pre><code class=\"language-python\"># Wait for network idle\npage.goto(url, wait_until=\"networkidle\")\n\n# Wait for specific element\npage.wait_for_selector(\".dashboard-loaded\")\n\n# Wait for navigation\npage.wait_for_url(\"**/success\")\n\n# Wait for response\nwith page.expect_response(\"**/api/data\") as resp:\n    page.click(\"#load-data\")\n</code></pre>\n<h2>Snapshot-Based Navigation</h2>\n<p>After any playwright-cli command, a snapshot file is generated describing interactive elements with reference IDs (e.g., <code>e15</code>, <code>e22</code>). Reference these IDs for subsequent actions instead of CSS selectors.</p>\n<pre><code class=\"language-bash\">playwright-cli goto https://app.example.com\n# Snapshot shows: e15 = \"Login button\", e22 = \"Email input\"\nplaywright-cli click e22\nplaywright-cli type \"user@example.com\"\nplaywright-cli click e15\n</code></pre>\n<h2>Proof of Work Pattern</h2>\n<p>For agent QA deliveries, screenshot every key state:</p>\n<pre><code class=\"language-python\">states = [\n    (\"https://app.example.com\", \"proof-landing.png\"),\n    (\"https://app.example.com/login\", \"proof-login.png\"),\n    (\"https://app.example.com/dashboard\", \"proof-dashboard.png\"),\n]\nfor url, filename in states:\n    page.goto(url)\n    page.screenshot(path=filename, full_page=True)\n</code></pre>\n"}