Playwright
Microsoft's browser automation library for Python. Automates Chromium, Firefox, and WebKit. Current version is 1.58.0 (Jan 2026). Requires Python >=3.9. Critical two-step install: pip install playwright followed by playwright install to download browser binaries — omitting the second step causes BrowserType.launch: Executable doesn't exist error.
Warnings
- breaking Browser binaries are NOT included in the pip package. After pip install playwright, you must run playwright install (or playwright install chromium) to download browsers. Omitting this raises: BrowserType.launch: Executable doesn't exist at [path].
- breaking Python 3.8 support dropped in 1.51. Minimum is now Python 3.9.
- breaking page.accessibility was removed in 1.57 after 3 years of deprecation. Code using page.accessibility raises AttributeError.
- breaking Docker image mcr.microsoft.com/playwright no longer contains Python. Use mcr.microsoft.com/playwright/python for Python-based automation in Docker.
- gotcha Mixing sync and async APIs causes cryptic errors. Using await on sync_playwright methods raises TypeError. Using sync methods inside async functions can deadlock.
- gotcha Locators are strongly preferred over raw CSS/XPath selectors. page.query_selector() and page.click('#some-id') work but are fragile. Locators (get_by_role, get_by_label, get_by_text) are auto-retrying and test-ID based.
- gotcha playwright install downloads browsers to a version-specific cache path. Upgrading playwright without re-running playwright install uses stale binaries and may cause browser launch failures.
Install
-
pip install playwright -
playwright install -
playwright install chromium -
playwright install --with-deps
Imports
- sync_playwright
from playwright.sync_api import sync_playwright with sync_playwright() as p: browser = p.chromium.launch(headless=True) page = browser.new_page() page.goto('https://example.com') print(page.title()) browser.close() - async_playwright
import asyncio from playwright.async_api import async_playwright async def main(): async with async_playwright() as p: browser = await p.chromium.launch() page = await browser.new_page() await page.goto('https://example.com') await browser.close() asyncio.run(main())
Quickstart
from playwright.sync_api import sync_playwright
with sync_playwright() as p:
# Launch browser
browser = p.chromium.launch(headless=True)
context = browser.new_context()
page = context.new_page()
# Navigate and interact
page.goto('https://example.com')
print('Title:', page.title())
# Use locators (preferred over selectors)
page.get_by_role('button', name='Submit').click()
page.get_by_label('Email').fill('user@example.com')
# Wait for navigation
page.wait_for_load_state('networkidle')
# Screenshot
page.screenshot(path='screenshot.png')
browser.close()