Playwright tests can be configured to a surprising degree by environment variables, often dictating behavior that feels hardcoded.

Let’s watch Playwright spin up a browser and navigate to a page, all while we manipulate its environment.

# First, let's set up a simple test file
cat << EOF > test_env.py
import os
import pytest
from playwright.sync_api import sync_playwright

def test_env_vars():
    browser_type = os.environ.get("PLAYWRIGHT_TEST_BROWSER_TYPE", "chromium")
    headless = os.environ.get("PLAYWRIGHT_TEST_HEADLESS", "true").lower() == "true"
    slow_mo = int(os.environ.get("PLAYWRIGHT_TEST_SLOW_MO", "0"))
    trace_dir = os.environ.get("PLAYWRIGHT_TEST_TRACE_DIR")

    print(f"Browser Type: {browser_type}")
    print(f"Headless: {headless}")
    print(f"Slow Motion: {slow_mo}")
    print(f"Trace Directory: {trace_dir}")

    with sync_playwright() as p:
        browser = p.new_browser(browser_type=browser_type, headless=headless)
        context = browser.new_context()
        page = context.new_page()
        page.goto("https://playwright.dev")
        print(f"Page title: {page.title()}")
        context.close()
        browser.close()

EOF

# Now, let's run it with default settings
pytest test_env.py

Output will show:

Browser Type: chromium
Headless: True
Slow Motion: 0
Trace Directory: None
Page title: Playwright: Fast, reliable end-to-end testing for modern web apps

Now, let’s change some things:

# Run with Firefox, visible, and slow motion
export PLAYWRIGHT_TEST_BROWSER_TYPE="firefox"
export PLAYWRIGHT_TEST_HEADLESS="false"
export PLAYWRIGHT_TEST_SLOW_MO="500"
pytest test_env.py

Output will now show:

Browser Type: firefox
Headless: False
Slow Motion: 500
Trace Directory: None
Page title: Playwright: Fast, reliable end-to-end testing for modern web apps

You’ll see a Firefox browser window pop up and move slowly.

The core problem Playwright environment variables solve is making test execution dynamic without modifying test code. This is crucial for CI/CD pipelines, different testing environments (dev, staging, prod), or even just debugging specific scenarios. You can switch browsers, control visibility, inject delays, and enable detailed tracing all from the command line or your CI configuration.

Internally, Playwright’s sync_playwright() and async_playwright() functions, and the subsequent browser instantiation methods like p.chromium.launch(), p.firefox.launch(), etc., check for these environment variables before they even create the browser instance.

  • PLAYWRIGHT_BROWSERS_PATH: This variable dictates where Playwright looks for its downloaded browser binaries. By default, it’s a hidden directory within your user’s home directory (~/.cache/ms-playwright). If you set this to a different path, Playwright will attempt to find or download browsers there. This is useful for managing disk space or using custom browser builds.
    • Diagnosis: Check os.environ.get("PLAYWRIGHT_BROWSERS_PATH").
    • Fix: export PLAYWRIGHT_BROWSERS_PATH="/path/to/your/browsers"
    • Why it works: Playwright uses this path as the root for its browser executables.
  • PLAYWRIGHT_CHROMIUM_LAUNCH_OPTIONS, PLAYWRIGHT_FIREFOX_LAUNCH_OPTIONS, PLAYWRIGHT_WEBKIT_LAUNCH_OPTIONS: These allow you to pass specific launch arguments to each browser type. They expect JSON strings. For example, to enable GPU acceleration for Chromium:
    • Diagnosis: Inspect the environment variable value.
    • Fix: export PLAYWRIGHT_CHROMIUM_LAUNCH_OPTIONS='{"args": ["--use-gl=desktop"]}'
    • Why it works: Playwright parses this JSON and passes the dictionary as keyword arguments to the respective browser’s launch method.
  • PLAYWRIGHT_TEST_BROWSERS: A comma-separated list of browsers to test against (e.g., chromium,firefox,webkit). Playwright will iterate through these if you’re using a test runner like pytest-playwright.
    • Diagnosis: Check os.environ.get("PLAYWRIGHT_TEST_BROWSERS").
    • Fix: export PLAYWRIGHT_TEST_BROWSERS="chromium,firefox"
    • Why it works: The test runner or Playwright’s internal mechanisms use this to determine which browsers to launch for each test.
  • PLAYWRIGHT_IGNORE_HTTPS_ERRORS: Setting this to true will make Playwright ignore TLS/SSL certificate errors. Essential when testing against internal sites with self-signed certificates.
    • Diagnosis: Check os.environ.get("PLAYWRIGHT_IGNORE_HTTPS_ERRORS").
    • Fix: export PLAYWRIGHT_IGNORE_HTTPS_ERRORS="true"
    • Why it works: This flag is passed directly to the browser launch options, instructing the browser to bypass certificate validation.
  • PLAYWRIGHT_SCREENSHOTS_DIR: If you’re taking screenshots within your tests, this variable specifies the directory where they should be saved.
    • Diagnosis: Check os.environ.get("PLAYWRIGHT_SCREENSHOTS_DIR").
    • Fix: export PLAYWRIGHT_SCREENSHOTS_DIR="./my-screenshots"
    • Why it works: Playwright’s page.screenshot() method checks this variable for the output directory.
  • PLAYWRIGHT_TRACE: Controls the trace recording. Can be on, off, or retain-on-failure. retain-on-failure is particularly useful in CI.
    • Diagnosis: Check os.environ.get("PLAYWRIGHT_TRACE").
    • Fix: export PLAYWRIGHT_TRACE="retain-on-failure"
    • Why it works: This directly influences Playwright’s trace agent, telling it when to start and stop recording detailed execution logs and artifacts.
  • PLAYWRIGHT_TIMEOUT: Sets the default timeout for most Playwright operations (e.g., page.goto, page.click). Default is 30 seconds.
    • Diagnosis: Check os.environ.get("PLAYWRIGHT_TIMEOUT").
    • Fix: export PLAYWRIGHT_TIMEOUT="60000" (for 60 seconds)
    • Why it works: This value is used to configure the timeout parameter in various Playwright API calls.

The most subtle and powerful environment variable is PLAYWRIGHT_CLI_ARGS. This allows you to pass arbitrary arguments that would normally be passed to the playwright test command itself, directly via an environment variable. For instance, if you wanted to run tests with a specific tag and parallelize them, you could do this:

export PLAYWRIGHT_CLI_ARGS='--grep "@smoke" --workers 4'
pytest test_env.py # Or playwright test your_tests_dir

This is incredibly useful for dynamically controlling test runs in CI without having to modify the CI script itself, allowing a single CI job definition to trigger different test suites or configurations.

If you’ve set all these and your tests are still behaving unexpectedly, the next thing to check is the PLAYWRIGHT_SERVICE_URL.

Want structured learning?

Take the full Playwright course →