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.

For Python browser automation, start with Playwright if you want one API for Chromium, Firefox, and WebKit, with synchronous and asynchronous interfaces and browser binaries installed for the Playwright version you use. Choose Selenium when WebDriver sessions and browser-specific driver integrations suit your project; modern Selenium commonly uses Selenium Manager to handle driver setup. Both can automate real browsers. Your choice should follow the browsers you must test, the way your tests wait for page changes, and how much browser setup your continuous-integration environment can maintain.

Playwright or Selenium: which should you choose?

These are the two central Python options. Neither is universally better: Playwright gives you a cohesive high-level API and an explicit browser-install workflow, while Selenium is built around WebDriver, a W3C Recommendation, and browser-specific implementations. Select based on the behavior and environments you need to automate, not on a claim that one tool is always faster or more reliable; the available documentation does not establish a general benchmark.

Decision point Playwright Selenium
Python API Synchronous and asynchronous APIs. Python bindings that create WebDriver browser sessions.
Browser coverage Installs Chromium, Firefox, and WebKit; documents Chrome and Edge channels as well. Browser-specific WebDriver implementations for Chrome, Edge, Firefox, Safari, WebKitGTK, and WPEWebKit are listed in its Python API documentation.
Setup model Install the package, then install the browser binaries required by that Playwright version. Install the Python package and have the target browser available; Selenium Manager commonly takes care of driver setup when a driver is instantiated.
Protocol and events A high-level browser automation API. WebDriver is a W3C Recommendation. WebDriver BiDi adds bidirectional event streaming, including network requests, console messages, and JavaScript errors.
Good fit when You want the same Playwright workflow across its supported engines, or prefer its sync or async API. You need WebDriver-based browser sessions, or WebDriver and BiDi capabilities are a central part of your approach.

Both require maintenance in CI: pin the Python dependencies, keep browser and driver compatibility under observation, and run the same critical flows in the environments that matter to you. Playwright recommends its Pytest plugin for Python testing; it can also be run locally or in CI. Selenium can be integrated into Python test suites, but the exact test-runner arrangement is project-specific.

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

Install Playwright and run your first browser

Playwright’s browser binaries are tied to the installed Playwright version. Installing the Python package alone is not the complete setup: run its CLI installation command too. These commands install the package in the active Python environment and fetch supported browser binaries.

python -m pip install playwright
playwright install

If your environment is missing operating-system libraries needed by a browser, Playwright also documents an optional playwright install-deps command. Whether you need it depends on the host system and how that system is provisioned.

Synchronous example

Save this as title.py and run python title.py. It launches Chromium, opens a page, prints the title, and closes the browser even if an exception occurs.

from playwright.sync_api import sync_playwright

with sync_playwright() as p:
    browser = p.chromium.launch()
    try:
        page = browser.new_page()
        page.goto("https://example.com")
        print(page.title())
    finally:
        browser.close()

For an explicit headless run, set headless=True in the launch call: p.chromium.launch(headless=True). Headless describes running the browser without a visible browser window; it does not change the need to install the matching browser binary or handle page readiness appropriately.

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

Asynchronous example

Use the async API when it fits an asyncio application or test structure. The following program has the same basic lifecycle, using Playwright’s asynchronous Python package surface.

import asyncio
from playwright.async_api import async_playwright

async def main():
    async with async_playwright() as p:
        browser = await p.chromium.launch(headless=True)
        try:
            page = await browser.new_page()
            await page.goto("https://example.com")
            print(await page.title())
        finally:
            await browser.close()

asyncio.run(main())

Playwright’s CLI can install Chromium, Firefox, and WebKit. If a test must exercise Chrome or Edge specifically rather than Playwright’s bundled Chromium, consult the supported browser-channel options for the Playwright version in your environment. Use the matching Playwright browser installation instructions when upgrading: a package upgrade can require different browser binaries.

Install Selenium and create a WebDriver session

Selenium’s Python package provides WebDriver bindings. A modern Selenium setup commonly uses Selenium Manager when the driver is instantiated, reducing the need to download and wire up a driver manually. It is not a guarantee that every host is ready: the chosen browser must be available, and network, permissions, or version-compatibility problems can still prevent session creation.

python -m pip install selenium

Save the following as selenium_title.py. The quit() call ends the session and releases its browser resources.

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.
from selenium import webdriver

 driver = webdriver.Chrome()
try:
    driver.get("https://selenium.dev")
    print(driver.title)
finally:
    driver.quit()

Remove the single leading space before driver = webdriver.Chrome() if copying the displayed code into a file; the executable version is:

from selenium import webdriver

driver = webdriver.Chrome()
try:
    driver.get("https://selenium.dev")
    print(driver.title)
finally:
    driver.quit()

To request headless Chrome, configure browser options before creating the session:

from selenium import webdriver

options = webdriver.ChromeOptions()
options.add_argument("--headless")
driver = webdriver.Chrome(options=options)
try:
    driver.get("https://example.com")
    print(driver.title)
finally:
    driver.quit()

Headless support and launch details can vary with the installed browser and execution environment. If a headless session fails while a visible local session works, check the browser installation, runtime dependencies, and the options supported by that browser version rather than assuming the page itself is broken.

Wait for the page condition you need

Waiting is a correctness issue, not merely a speed setting. A navigation can finish before an application has rendered the particular result your script needs. Prefer waiting for a meaningful element or state over inserting a long fixed sleep: a fixed delay can waste time on a fast run and still be too short on a slow one.

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

Playwright: wait for a locator

Playwright locators are the natural unit for finding and acting on page elements. For a known result element, wait for it to become visible before reading or interacting with it:

from playwright.sync_api import sync_playwright

with sync_playwright() as p:
    browser = p.chromium.launch()
    try:
        page = browser.new_page()
        page.goto("https://example.com")
        heading = page.get_by_role("heading", name="Example Domain")
        heading.wait_for(state="visible")
        print(heading.inner_text())
    finally:
        browser.close()

Use a locator that reflects the user-visible control or stable application structure when possible. A selector that depends on an implementation detail can break after a site redesign. If the expected element never appears, check the locator, whether the page reached the intended route, and whether an error, consent overlay, or authentication wall changed the page.

Selenium: use an explicit wait

With Selenium, use WebDriverWait and an expected condition for the condition your next step requires. For example, this waits for a page title to contain expected text rather than assuming navigation alone means the page is ready:

from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

 driver = webdriver.Chrome()
try:
    driver.get("https://example.com")
    WebDriverWait(driver, 10).until(EC.title_contains("Example"))
    print(driver.title)
finally:
    driver.quit()

As above, remove the accidental leading space before driver = webdriver.Chrome() when copying. A clean executable version is:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

driver = webdriver.Chrome()
try:
    driver.get("https://example.com")
    WebDriverWait(driver, 10).until(EC.title_contains("Example"))
    print(driver.title)
finally:
    driver.quit()

The timeout is an upper bound for this wait, not a promise that the page will become ready. Choose conditions that match the actual next action, and make failures report the missing condition clearly.

Run cross-browser checks without multiplying surprises

Cross-browser testing means exercising the relevant application behavior in each required browser, not just changing a browser name in one script and assuming equivalence. Playwright explicitly supports Chromium, Firefox, and WebKit installations. Selenium exposes browser-specific WebDriver implementations across major browsers; exact availability depends on the operating system and browser distribution, particularly for Safari and the listed WebKit variants.

  1. Choose the required browser engines first. Map user impact or product support to the engines you intend to test. Do not describe a Chromium run as proof that Firefox, WebKit, or Safari works.
  2. Pin the automation dependency. For Playwright, install the browser versions associated with that installed Playwright version. In CI, update the package and browser binaries together.
  3. Make browser setup explicit in the environment. Use playwright install for Playwright binaries; for Selenium, verify the target browser is installed and let Selenium Manager manage the driver where appropriate.
  4. Wait on application outcomes. Use an element, title, or other relevant condition so that differences in rendering and timing do not become arbitrary sleeps.
  5. Run the same critical scenarios per target. Keep tests focused on user-visible outcomes and inspect browser-specific failures separately instead of suppressing them as flaky.

WebDriver’s standards-based protocol and WebDriver BiDi’s event-streaming capabilities matter if your tooling needs browser events such as network requests, console messages, or JavaScript errors. Playwright offers a different, high-level API model. Compare the specific API capability your project needs; do not infer that the presence of a standard makes the tools interchangeable at every interface.

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

Or skip the browser setup

If the task is simply to capture a website screenshot or PDF, browser automation may be more machinery than you need. ScreenshotNeo is a screenshot API and MCP server for developers, not a replacement for Playwright or Selenium when you need to click through an application, inspect arbitrary page state, or run interactive browser tests. It can return a PNG, JPEG, WebP, or PDF from a GET request. Its API accepts a URL and an access key; use the ScreenshotNeo API documentation for access-key setup and request options.

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

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

The supplied example writes a WebP file. For a shell-based request, the cURL form is:

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://example.com -o shot.webp

Node.js can make the same GET request with the provided fetch pattern:

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

ScreenshotNeo can accept cookie or consent banners as a visitor and remove more than 60 known consent platforms, newsletter popups, and chat widgets before the capture; each of those steps can be turned off. Bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers identify the page verdict and billing status. Its MCP server exposes take_screenshot, get_page_info, and capture_pdf for Claude, Cursor, and other MCP clients. The Free plan includes 1,000 shots per month with no card; paid plans start at $5 for 3,000 shots, and yearly billing gives two months free. Every feature is on every plan.

Sign up for ScreenshotNeo’s free plan to try 1,000 screenshots a month without a card.

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

Troubleshoot common setup and test failures

Symptom Likely cause What to check
Playwright launches with a missing-executable or browser error. The browser binaries for the installed Playwright version were not installed, or the package was upgraded without refreshing them. Run playwright install in the active environment; confirm the script and CLI use the same Python environment. On a minimal Linux host, check whether playwright install-deps is needed.
Selenium cannot create a Chrome session. The browser may be unavailable, driver management may have failed, or the host may restrict downloads or execution. Confirm Chrome is installed and executable, verify network and permissions for Selenium Manager, and inspect the complete session-creation error. Where automatic management is unsuitable, use an explicitly managed compatible driver.
A test sometimes reads old or missing content. The script acts before the needed application state is ready, or it waits on a condition unrelated to that state. Replace an arbitrary delay with a locator or explicit expected condition for the result the next step actually needs.
A test passes in one engine and fails in another. The tested engines, browser versions, page behavior, or assumptions differ. Reproduce in the failing browser, verify it is installed and part of the intended test matrix, and inspect the failing condition rather than assuming a browser-independent result.
A page loads but the expected control is absent. The script may have reached a different route, a consent or authentication screen, or an application error state. Inspect the current title and visible page state, verify navigation and session prerequisites, and wait for the correct element on the intended page.
Headless works locally but fails in CI. The CI host can differ in browser binaries, system dependencies, permissions, or runtime configuration. Make browser installation reproducible, check Playwright system dependencies where applicable, and keep the browser options and package versions aligned across environments.

Keep runs maintainable and affordable

Neither tool’s documentation in the available sources establishes comparative execution costs or performance figures, so treat runtime as something to measure in your own suite. A useful baseline is to record elapsed time and failure rates by browser and scenario in the environments where you deploy the tests. Do not optimize waits by replacing a meaningful condition with an unrealistically short sleep.

  • Pin versions deliberately. Playwright needs matching browser binaries; Selenium relies on a compatible browser/driver session even when Selenium Manager handles setup.
  • Close sessions reliably. Use finally blocks or test-fixture teardown to close browsers and drivers after both success and failure.
  • Keep the test matrix proportional. Exercise critical flows in all required engines, and avoid duplicating the entire suite across browsers without a reason.
  • Separate browser failures from application failures. Record which browser and condition failed so CI output helps distinguish setup problems from genuine regressions.
  • Use the right tool for the job. Full browser automation is appropriate for interaction and cross-browser behavior. For a screenshot-only requirement, an API can avoid installing and maintaining a local browser stack.

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.