ScreenshotNeo

BlogHow-to

How to Set `PLAYWRIGHT_BROWSERS_PATH` for Playwright

Set Playwright’s browser location correctly across shells, languages, CI, Docker and local development, with fixes for common path errors.

By the ScreenshotNeo team1 October 20266 min read

Set PLAYWRIGHT_BROWSERS_PATH before both browser installation and the process that launches Playwright. Both processes must use the same directory. For a Bash shell:

export PLAYWRIGHT_BROWSERS_PATH="$HOME/pw-browsers"
npx playwright install
npx playwright test

For a one-off command, prefix each command instead:

PLAYWRIGHT_BROWSERS_PATH=$HOME/pw-browsers npx playwright install
PLAYWRIGHT_BROWSERS_PATH=$HOME/pw-browsers npx playwright test

The variable changes where Playwright-managed browser binaries are installed and found. It does not move an operating-system installation of Google Chrome or Microsoft Edge. See the official Playwright browser documentation for the supported patterns and defaults.

1. What the variable controls

Playwright downloads browser revisions that match the Playwright release you installed. PLAYWRIGHT_BROWSERS_PATH points Playwright to the directory containing those managed Chromium, Firefox and WebKit binaries.

Configuration Location or behavior Good fit
Unset OS cache directory Normal local development
Custom path Your shared or persistent directory Multiple projects, CI caches, shared build hosts
0 Hermetic, package-local installation Packaging browsers with a project

Default cache locations are:

  • Windows: %USERPROFILE%\AppData\Local\ms-playwright
  • macOS: ~/Library/Caches/ms-playwright
  • Linux: ~/.cache/ms-playwright

A custom value does not need to be inside your project, but the account running installation and tests must be able to read it. The directory can be shared by processes when permissions and lifecycle are managed consistently.

2. Bash, macOS and Linux

Persistent for the current shell

export PLAYWRIGHT_BROWSERS_PATH="$HOME/pw-browsers"
npx playwright install
npx playwright test

Use an absolute path when a service, container or CI runner may start with a different working directory. To verify the value:

printf '%s\n' "$PLAYWRIGHT_BROWSERS_PATH"
ls -la "$PLAYWRIGHT_BROWSERS_PATH"

One command only

PLAYWRIGHT_BROWSERS_PATH="$PWD/.pw-browsers" npx playwright install chromium
PLAYWRIGHT_BROWSERS_PATH="$PWD/.pw-browsers" npx playwright test

Because the assignment applies only to that command, repeat it for every Playwright command that needs the browsers.

Hermetic project-local installation

PLAYWRIGHT_BROWSERS_PATH=0 npx playwright install
PLAYWRIGHT_BROWSERS_PATH=0 npx playwright test

With Node.js, the documented result is under node_modules/playwright-core/.local-browsers. Keep the install and runtime commands on the same setting.

3. PowerShell and Windows Batch

PowerShell

$Env:PLAYWRIGHT_BROWSERS_PATH="$Env:USERPROFILE\pw-browsers"
npx playwright install
npx playwright test

For one command:

$Env:PLAYWRIGHT_BROWSERS_PATH="$Env:USERPROFILE\pw-browsers"; npx playwright test

Windows Command Prompt

set PLAYWRIGHT_BROWSERS_PATH=%USERPROFILE%\pw-browsers
npx playwright install
npx playwright test

set affects the current Command Prompt window. Use setx only when you intentionally want to create a persistent user environment variable for future shells; open a new shell afterward.

4. JavaScript, Python, Java and .NET

The variable is read from the process environment, so the shell syntax is independent of the language binding. Install the binding, set the variable, install browsers, then run your program.

Node.js

export PLAYWRIGHT_BROWSERS_PATH="$HOME/pw-browsers"
npm install playwright
npx playwright install
node screenshot.js

In a Node script, launch Playwright normally; the child process inherits the environment:

import { chromium } from 'playwright';

const browser = await chromium.launch();
const page = await browser.newPage();
await page.goto('https://example.com');
await page.screenshot({ path: 'example.png', fullPage: true });
await browser.close();

Python

export PLAYWRIGHT_BROWSERS_PATH="$HOME/pw-browsers"
pip install playwright
python -m playwright install
python screenshot.py
from playwright.sync_api import sync_playwright

with sync_playwright() as p:
    browser = p.chromium.launch()
    page = browser.new_page()
    page.goto("https://example.com")
    page.screenshot(path="example.png", full_page=True)
    browser.close()

For Java and .NET, use the same environment-variable step before the binding’s documented browser-install command. Playwright provides language-specific examples for Python, Java and .NET.

5. CI, containers and shared directories

CI jobs

Set the variable in the same job that installs and runs Playwright:

export PLAYWRIGHT_BROWSERS_PATH="$CI_PROJECT_DIR/.pw-browsers"
npx playwright install --with-deps
npx playwright test

If you cache the directory, key the cache by the Playwright version. A browser directory produced by another Playwright release may contain incompatible revisions. Playwright’s CI guidance also notes that caching is not always faster than downloading; skip caching when restore time is comparable to installation time.

Docker

ENV PLAYWRIGHT_BROWSERS_PATH=/ms-playwright
RUN npx playwright install
COPY . /app
WORKDIR /app
CMD ["npx", "playwright", "test"]

Ensure the runtime user can read the directory. If installation runs as root and tests run as an unprivileged user, fix ownership or install as the runtime user.

Shared hosts

A shared directory reduces duplicate downloads, but coordinate upgrades. Two jobs using different Playwright versions can require different browser revisions. Use separate version-keyed directories when upgrades overlap, or reinstall deliberately during the image or runner build.

6. Versioning, cleanup and retention

Browser binaries are tied to Playwright versions. After upgrading Playwright, run the browser installation command again:

npx playwright install

Playwright tracks which clients need browser packages and can remove revisions it no longer considers required. To retain otherwise unused browsers, set PLAYWRIGHT_SKIP_BROWSER_GC=1 or install with --no-remove, as documented in the browser lifecycle guidance. Retention increases disk usage, so apply it only when the directory is intentionally managed.

7. Troubleshooting

Symptom Likely cause Fix
Executable doesn't exist Install and runtime use different paths, or installation never ran. Print the variable in both processes and rerun npx playwright install with the same value.
Works locally, fails in CI The variable was set in one step but not exported to another, or the cache restored a different version. Set it in the job environment and key caches by Playwright version.
Permission denied The test user cannot read or traverse the custom directory. Choose a user-owned path or correct directory ownership and permissions.
Browsers keep downloading The path changes between runs, or the cache is not persisted. Use one stable absolute path and persist that directory only when it saves time.
Chrome or Edge location did not change The variable controls Playwright-managed browsers only. Configure the branded browser through its normal OS installation and launch options.
Old revisions disappear Playwright browser garbage collection removed versions no longer needed. Use PLAYWRIGHT_SKIP_BROWSER_GC=1 or --no-remove when retention is required.
PowerShell shows an empty value Unix syntax was used in PowerShell, or a new shell was not opened after a persistent change. Use $Env:PLAYWRIGHT_BROWSERS_PATH=... and verify with $Env:PLAYWRIGHT_BROWSERS_PATH.

8. A reliable setup checklist

  1. Pick an OS cache, a stable custom directory or hermetic value 0.
  2. Use the shell’s correct environment-variable syntax.
  3. Set the value before playwright install.
  4. Set the identical value before tests or application startup.
  5. Make the directory readable by the runtime account.
  6. Reinstall browsers after Playwright upgrades.
  7. For CI, decide whether download time or cache restore time is lower.
  8. Version cache keys and shared directories by Playwright version.

9. Or skip the browser setup

If your goal is simply to obtain a clean screenshot from a URL, ScreenshotNeo provides a hosted API and MCP server. One request returns PNG, JPEG, WebP or PDF, so there is no local Playwright browser directory to install or maintain.

cURL (see the ScreenshotNeo API documentation):

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}`);

ScreenshotNeo accepts cookie and consent banners before capture and removes more than 60 known consent platforms, newsletter popups and chat widgets. Bot checks, blank pages, timeouts, failed loads and cache hits cost nothing, and response headers identify the page verdict and whether the shot was billed. Its MCP server lets Claude, Cursor and other MCP clients call take_screenshot, get_page_info and capture_pdf. The Free plan includes 1,000 screenshots each month with no card; paid plans start at $5 for 3,000 shots. Create a free ScreenshotNeo account.

10. FAQ

Can I use a relative path?

Yes, but an absolute path is safer in CI, services and multi-process workflows because the working directory may differ.

Does the variable affect browser downloads from a system package manager?

No. It controls Playwright-managed browser binaries, not Google Chrome or Microsoft Edge installed by the operating system.

Should every project share one directory?

Only when the directory is writable and its lifecycle is coordinated. Version-keyed directories avoid collisions during Playwright upgrades.

Why does setting the variable to 0 help packaging?

It selects Playwright’s documented hermetic mode, placing browsers inside the local Playwright package directory instead of the OS cache.

Is browser caching always worthwhile?

No. Compare cache restore time with downloading. If restore is as slow as a download, the CI documentation recommends downloading instead.