Skip to main content

playwright-webdriver-py

Run existing Selenium WebDriver Python scripts using Playwright as the browser backend — no ChromeDriver or browser binary installation required.

playwright-webdriver-py is a drop-in compatibility layer that implements the Selenium WebDriver Python API over Playwright's synchronous API. Drop it in and your existing webdriver.Chrome() scripts run backed by Playwright; faster, more reliable, and without the ChromeDriver version-matching headache.


Features

  • Zero script changes — existing Selenium scripts run as-is
  • No ChromeDriver — Playwright manages its own browser binaries
  • Full WebDriverWait / expected_conditions support — unchanged from Selenium
  • Chromium, Firefox, and WebKit backends via PlaywrightBrowserType
  • CLI runner — execute any .py Selenium script directly from the command line
  • PlaywrightBy — opt-in raw Playwright selector strings for power users

Installation

pip install playwright-webdriver-py
playwright install  # downloads browser binaries (first time only)

Or with Poetry:

poetry add playwright-webdriver-py
playwright install

Requirements: Python 3.12+


Quick Start

Run an existing Selenium script unchanged

# my_existing_script.py  — written for standard Selenium, runs on Playwright
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

driver = webdriver.Chrome()
wait = WebDriverWait(driver, 10)

driver.get("https://www.wikipedia.org")
search = wait.until(EC.presence_of_element_located((By.ID, "searchInput")))
search.send_keys("Playwright (software)")
search.submit()

heading = wait.until(EC.presence_of_element_located((By.ID, "firstHeading")))
print(heading.text)

driver.quit()

Via the CLI runner (intercepts webdriver.Chrome() transparently):

python -m playwright_webdriver.runner my_existing_script.py
python -m playwright_webdriver.runner my_existing_script.py --headless

Via the Python API (same interception, callable from your own code):

from playwright_webdriver.runner import run_selenium_script

run_selenium_script("my_existing_script.py", headless=True)

Use PlaywrightWebDriver directly

from playwright_webdriver import PlaywrightWebDriver, PlaywrightBrowserType
from selenium.webdriver.common.by import By

with PlaywrightWebDriver.create(
    browser_type=PlaywrightBrowserType.CHROMIUM,
    launch_options={"headless": True},
) as driver:
    driver.get("https://example.com")
    heading = driver.find_element(By.TAG_NAME, "h1")
    print(heading.text)  # "Example Domain"

Supported Selenium API

PlaywrightWebDriver

Method / Property Notes
driver.get(url) Navigates to URL
driver.find_element(by, value) Returns PlaywrightWebElement
driver.find_elements(by, value) Returns list[PlaywrightWebElement]
driver.execute_script(script, *args) Full JS execution; arguments[N] supported
driver.current_url Current page URL
driver.title Page title
driver.page_source Full HTML source
driver.maximize_window() Sets viewport to 1920×1080
driver.close() Closes current tab
driver.quit() Closes browser and releases all resources
driver.navigate() Returns navigation object (back, forward, refresh, to)
driver.switch_to() Returns target locator (frame, window, alert, default_content)
driver.manage() Returns options object (cookies, timeouts, window)
driver.current_window_handle Handle for the current window/tab
driver.window_handles All open window/tab handles

PlaywrightWebElement

Method / Property Notes
element.click() Clicks the element
element.send_keys(*value) Text input; Selenium Keys constants supported
element.clear() Clears a text field
element.submit() Submits the form containing the element
element.find_element(by, value) Scoped element search
element.find_elements(by, value) Scoped element list
element.get_attribute(name) HTML attribute value
element.get_property(name) DOM property value
element.get_dom_attribute(name) DOM attribute (no fallback to property)
element.text Visible text content
element.tag_name Element tag name
element.is_displayed() True if the element is visible
element.is_enabled() True if the element is enabled
element.is_selected() True if a checkbox/radio is checked

Locator strategies

All standard Selenium By strategies are supported:

By constant Playwright selector
By.ID #value
By.NAME [name='value']
By.CLASS_NAME .value
By.CSS_SELECTOR css=value
By.XPATH xpath=value
By.TAG_NAME bare tag selector
By.LINK_TEXT a:visible:text-is("value") (visible only, matching Selenium semantics)
By.PARTIAL_LINK_TEXT a:visible:has-text("value") (visible only, matching Selenium semantics)

In addition, PlaywrightBy.selector(string) passes a raw Playwright selector string through unchanged, giving you access to Playwright-specific features like role=, text=, and :visible filters:

from playwright_webdriver import PlaywrightBy

btn = driver.find_element(PlaywrightBy.selector("role=button[name='Submit']"))

Running Tests

The test suite is a Python port of the original C# NUnit test suite from Selenium.PlaywrightDriver.

# Install dev dependencies
poetry install

# Run the full suite (19 tests, all headless)
pytest tests/

All tests use local HTML fixtures and an ephemeral HTTP server — no internet connection required.


Examples

The examples/ directory contains real-world Selenium scripts that run unmodified through the CLI runner:

python -m playwright_webdriver.runner examples/wikipedia_smoke_test.py
python -m playwright_webdriver.runner examples/apple_homepod_test.py
python -m playwright_webdriver.runner examples/skyscanner_one_way_search_test.py

How It Works

The CLI runner monkey-patches selenium.webdriver.Chrome (and Firefox, Edge, Remote, etc.) on the real selenium.webdriver module before exec()-ing the script. This means:

  • WebDriverWait, expected_conditions, Keys, and all other Selenium helpers continue to import from the real Selenium package — nothing breaks.
  • The only substitution is the browser factory: webdriver.Chrome() returns a PlaywrightWebDriver instance backed by Playwright's Chromium.
  • All patches are restored in a finally block, so running multiple scripts in the same process is safe.

License

MIT © 2026 HappyPath. See LICENSE for details.

Metadata

Release files for playwright-webdriver-py 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for playwright-webdriver-py 0.1.0
File Size Uploaded Provenance Actions
playwright_webdriver_py-0.1.0.tar.gz 20.0 kB With provenance Details for playwright_webdriver_py-0.1.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for playwright-webdriver-py 0.1.0
File Interpreter ABI Platform Actions
playwright_webdriver_py-0.1.0-py3-none-any.whl Python 3 none any Details for playwright_webdriver_py-0.1.0-py3-none-any.whl

Total release size: 41.3 kB

Release files / playwright_webdriver_py-0.1.0.tar.gz

Download URL playwright_webdriver_py-0.1.0.tar.gz
Size 20.0 kB
Tags Source
SHA-256 checksum
How to use checksums
3c063642677e327aa9f2949da4bcc6c92fc83779837b4dc197663a88e0a396cd
BLAKE2b-256 checksum
How to use checksums
a4c571a1216a0b2383f9c0ccbb7168d6765c8b88a491396f7b3c02468dbec52c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.7

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Mar 4, 2026.

Transparency log

Release files / playwright_webdriver_py-0.1.0-py3-none-any.whl

Download URL playwright_webdriver_py-0.1.0-py3-none-any.whl
Size 21.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
eedbf26ab41c8a10df08b0b2f90f2ca39764338ae8851cd845dda2aaed3f5c09
BLAKE2b-256 checksum
How to use checksums
e76c0c21f80642ce4d09c9bd60837ea4d1177612d408a7941c84c4c4e85361f2
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.7

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Mar 4, 2026.

Transparency log

Security for playwright-webdriver-py 0.1.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

Both files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for playwright_webdriver_py-0.1.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Mar 4, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files Full provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page