Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.

Playwright for Python is both a browser-automation library and an end-to-end testing framework. Install the Python package, install its matching Chromium, Firefox, and WebKit binaries, then choose either direct scripts or the pytest-playwright plugin. The examples below follow the current official documentation and show reliable locators, auto-waiting, browser matrices, debugging, CI practices, and common fixes.

What Playwright for Python provides

Playwright exposes synchronous and asynchronous Python APIs for automating web applications. It supports Chromium, Firefox, and WebKit, so a test can run against multiple browser engines instead of only the browser installed on a developer’s computer. The project was created specifically for end-to-end testing, but the library is also suitable for general browser automation.

Use the direct library when you need a script, crawler, data-entry job, or a small focused check. Use pytest-playwright when you need test discovery, fixtures, isolated browser contexts, assertions, and a repeatable multi-browser command.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Check Python and operating-system requirements

The current documentation lists Python 3.8 or higher. Supported systems documented for the current release line are Windows 11 or Windows Server 2019 and newer, macOS 14 and newer, and Debian 12/13 or Ubuntu 22.04/24.04/26.04 on x86-64 or arm64. A newer Playwright package can require newer browser binaries, so keep the package and browser installation in sync.

  • Use a virtual environment for each project.
  • Confirm your interpreter with python --version (or python3 --version).
  • On CI, use an operating-system image covered by the documented requirements.

Read the official installation overview at playwright.dev/python/docs/intro when a release changes its supported matrix.

Install Playwright

For pytest end-to-end tests

  1. Create and activate a virtual environment.
  2. Install the plugin: pip install pytest-playwright.
  3. Download the browser binaries: playwright install.
python -m venv .venv
# macOS/Linux
source .venv/bin/activate
# Windows PowerShell
.venvScriptsActivate.ps1
pip install pytest-playwright
playwright install

The plugin supplies browser and context fixtures, including the page fixture used in the standard examples. It also lets you select Chromium, Firefox, WebKit, branded Chrome or Edge channels, and device profiles from the command line.

For a library-only script

pip install playwright
playwright install

The two installation commands are separate by design: the package installs Python bindings and the CLI downloads browser binaries that match the installed Playwright release.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Install one browser or operating-system dependencies

To install only one engine, name it explicitly:

playwright install chromium
playwright install firefox
playwright install webkit

On Linux, playwright install --with-deps chromium installs Chromium and the system packages required by it. The browser-management guide also documents listing installed browsers, uninstalling them, and changing the cache location with PLAYWRIGHT_BROWSERS_PATH. Consult the browser guide for the exact command available in your release.

Run playwright install again after upgrading Playwright when the release notes or CLI indicate that new browser binaries are required. Each Playwright version expects specific browser versions; mixing an old cache with a new package is a common source of launch failures.

Write your first Python script

This synchronous example launches headless Chromium, navigates, prints the title, and closes every resource deterministically:

from playwright.sync_api import sync_playwright

with sync_playwright() as p:
    browser = p.chromium.launch()
    page = browser.new_page()
    page.goto("https://playwright.dev")
    print(page.title())
    browser.close()

page.goto waits for navigation to reach its normal completion criteria, while actions and assertions add their own actionability and web-first waiting. You generally do not need a manual time.sleep; fixed sleeps make tests slower and still fail when a page takes longer than the chosen delay.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Asynchronous API

Use the async API when your application already uses asyncio or must coordinate many I/O operations:

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://playwright.dev")
        print(await page.title())
        await browser.close()

asyncio.run(main())

On Windows, the Playwright driver subprocess requires a compatible Proactor event loop for async usage. Configure the event loop before starting Playwright if another framework has selected an incompatible policy.

Create a first pytest test

Name test files with the test_ prefix so pytest discovers them. The official pattern uses the Page fixture, role-based locators, and expect assertions:

from playwright.sync_api import Page, expect

def test_playwright_homepage(page: Page):
    page.goto("https://playwright.dev/")
    expect(page).to_have_title("Playwright")
    page.get_by_role("link", name="Get started").click()
    expect(page.get_by_role("heading", name="Installation")).to_be_visible()

Run the default headless Chromium test suite with:

pytest

Run another engine or all three engines with the plugin’s browser option:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
pytest --browser firefox
pytest --browser webkit
pytest --browser chromium --browser firefox --browser webkit

Use the running-tests documentation at playwright.dev/python/docs/running-tests for the current options, device emulation, headed mode, and debugger integration.

Choose locators that survive UI changes

Locators should describe how a user identifies an element, not how it happens to be implemented today. Prefer, in order appropriate to the page, accessible roles and names, labels, visible text, and explicit test IDs:

  • page.get_by_role("button", name="Save")
  • page.get_by_label("Email")
  • page.get_by_text("Order complete")
  • page.get_by_test_id("checkout-submit")

Role locators force accessible names to be correct and usually remain stable through CSS refactors. CSS or XPath selectors are still useful for a component with no meaningful user-facing identity, but avoid long chains of classes and DOM positions. If multiple elements match, narrow the locator with .filter, .first, or a more specific role/name rather than adding an arbitrary delay.

Rely on auto-waiting and web-first assertions

Playwright waits for an element to be actionable before clicking, filling, checking, or selecting it. Assertions such as to_be_visible, to_have_text, and to_have_title retry until the expected state is reached or the assertion timeout expires.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
from playwright.sync_api import expect

def test_checkout(page):
    page.goto("https://example.com/checkout")
    page.get_by_label("Card number").fill("4242424242424242")
    page.get_by_role("button", name="Pay").click()
    expect(page.get_by_role("status")).to_have_text("Payment submitted")

Wait for a meaningful condition when navigation or an application task has several phases. For example, wait for a selector that represents completed rendering, or use a web-first assertion on the final state. A network-idle condition can be useful for a page that finishes loading resources late, but it is not a substitute for asserting that the user-visible result is ready.

Control browsers, contexts, and devices

A browser process can contain multiple isolated contexts. The pytest plugin creates an isolated context for each test, preventing cookies and local storage from leaking between tests. In a direct script, create contexts explicitly when you need separate users:

from playwright.sync_api import sync_playwright

with sync_playwright() as p:
    browser = p.chromium.launch()
    admin = browser.new_context()
    visitor = browser.new_context()
    admin_page = admin.new_page()
    visitor_page = visitor.new_page()
    # use independent cookies and storage
    admin.close()
    visitor.close()
    browser.close()

Use pytest’s browser options for a Chromium/Firefox/WebKit matrix. The same configuration supports branded Chrome and Edge channels and documented mobile or tablet device emulation. Headless mode is the default; headed mode is useful while diagnosing a failure.

Debug a failing test

Inspector and headed execution

Launch a test in headed mode and pause it to inspect actionability logs, locators, and page state:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
PWDEBUG=1 pytest tests/test_home.py
pytest --headed --slowmo 250

On Windows PowerShell, set the environment variable with $env:PWDEBUG="1". The Playwright Inspector can step through API calls and help you explore a locator that does not match.

Codegen for a starting point

Use Codegen to record browser actions and generate initial locator code:

playwright codegen https://playwright.dev

Treat generated code as a draft. Replace fragile selectors with role or label locators, remove incidental actions, and add assertions that verify the outcome.

Trace Viewer for CI failures

Tracing records screenshots, actions, timing, and page information for later inspection. Configure tracing around the test or use the pytest plugin’s trace options, then open the resulting trace with the documented Trace Viewer workflow. It shows what happened immediately before a failure without requiring a rerun. The debugging guide is at playwright.dev/python/docs/debug.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Run reliably in CI and parallel jobs

  • Install the exact Python dependencies from your lock file, then run playwright install (or --with-deps on Linux).
  • Cache browser binaries only when the cache key includes the Playwright package version and operating-system image.
  • Keep tests isolated with separate contexts and independent test data.
  • Collect traces, screenshots, and video for failed tests rather than rerunning indefinitely.
  • Use the same browser matrix locally and in CI when a defect may be engine-specific.

Playwright’s Python API is not thread-safe. In a multithreaded program, create one Playwright instance per thread; do not share a single instance, browser page, or context across threads. For concurrency, prefer separate contexts or processes designed around your test runner’s isolation model.

Capture screenshots with Playwright

For a test artifact, capture the page after asserting the relevant state:

def test_receipt(page):
    page.goto("https://example.com/receipt")
    expect(page.get_by_role("heading", name="Receipt")).to_be_visible()
    page.screenshot(path="artifacts/receipt.png", full_page=True)

Playwright can also capture an element, use a viewport configured for a device, and run headed or headless. Screenshot output is local to the test process, so you must manage storage, retries, browser installation, and page readiness yourself.

Or skip the browser setup

When the job is simply to obtain a clean website image or PDF, ScreenshotNeo provides a one-call screenshot API and an MCP server for Claude, Cursor, and other MCP clients. It accepts cookie or consent banners like a visitor and removes more than 60 known consent platforms, newsletter popups, and chat widgets before capture; each cleanup step can be disabled. Bot checks, CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and the response identifies the result with X-Page-Verdict and X-Billed headers.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

Python:

import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)

Node.js:

const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);

See the parameter reference and response details in the ScreenshotNeo documentation. Its 63 options include full-page lazy-image loading, CSS-selector element capture, dark mode, 12 device presets or custom viewports, retina scale, PDF paper settings and page ranges, custom CSS or JavaScript, clicks, selector/delay/network-idle waits, request blocking, headers, cookies, user-agent and authorization, timezone, geolocation, transparent backgrounds, resizing, chosen-TTL caching, signed image links, asynchronous jobs with signed webhooks, bulk capture for 100 URLs per call, a usage API, an OpenAPI specification, and familiar parameter names for easier migration. Every feature is on every plan: 1,000 shots per month free with no card; paid plans start at $5 for 3,000 shots. Create a free ScreenshotNeo account to get started.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Troubleshoot common failures

Browser executable is missing

Symptom: launch fails with a message that a browser executable cannot be found. Fix: run playwright install in the same environment as the Python package. If Linux dependencies are missing, use playwright install --with-deps chromium or install the selected engine’s dependencies.

Package and browser versions do not match

Symptom: a browser starts and immediately exits after an upgrade. Fix: rerun the browser install command after upgrading Playwright and clear or refresh a cache keyed to the old package version.

Locator strictness or timeout error

Symptom: a click times out or a locator matches several nodes. Fix: inspect the page with Inspector or Codegen, choose a role/label/test ID, and narrow the locator. Replace sleeps with an assertion for the expected visible or enabled state.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Works headed, fails headless

Symptom: a test passes with a visible browser but fails in CI. Fix: capture a trace, screenshot, and console output; check viewport, fonts, permissions, authentication state, and missing Linux dependencies. Reproduce with the same browser engine and operating-system image.

Async code hangs on Windows

Symptom: an async test cannot communicate with the driver. Fix: use a compatible Proactor event loop before starting Playwright, and avoid sharing the instance across threads.

Keep the installation current

Playwright’s release notes record changes that can affect browser versions, supported systems, and test behavior. Review the release notes when upgrading, then update the Python package and browser binaries together. For API details on direct scripting and concurrency, see the Python library guide.

Frequently Asked Questions

Can I use Playwright without pytest?

Yes. Install the playwright package and use either sync_playwright or async_playwright directly; pytest is an optional testing layer.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Which browser runs when I type pytest?

The pytest plugin’s default is headless Chromium. Add one or more --browser options to run Firefox, WebKit, or a matrix.

Where are Playwright browser files stored?

They are stored in Playwright’s browser cache. Set PLAYWRIGHT_BROWSERS_PATH to relocate that cache, as documented in the browser guide.

Is Playwright safe to share between Python threads?

No. The API is not thread-safe; create a separate Playwright instance for each thread.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.