Resolving Playwright browser download timeout behind corporate proxy

Playwright’s npx playwright install (or postinstall download) fails behind a corporate proxy because the browser binaries are fetched by Playwright’s own Node.js downloader from cdn.playwright.dev (with fallbacks to playwright.download.prss.microsoft.com and playwright-akamai.azureedge.net), not by npm, so npm’s proxy settings are not applied to it. The downloader only honors the HTTPS_PROXY/HTTP_PROXY environment variables, and it fails with ETIMEDOUT, ECONNRESET, or Download failure, code=1 when those are unset, when the proxy performs TLS interception with an untrusted CA, or when the proxy blocks the CDN hostnames.

Root Cause Diagnosis

Three independent failures produce the same timeout symptom:

  1. No proxy configured for the downloader. The .npmrc proxy/https-proxy values apply to package installation only. The browser download is a separate HTTP request made by Playwright’s registry code using environment variables.
  2. TLS interception. The corporate proxy re-signs HTTPS traffic with an internal CA that Node.js does not trust, causing a stalled or reset connection (UNABLE_TO_GET_ISSUER_CERT_LOCALLY, SELF_SIGNED_CERT_IN_CHAIN).
  3. Hostname blocking. The proxy allowlist lacks the Playwright CDN hosts, so requests hang until the timeout.

Quick Fix

Set the proxy and extend the download timeout for the current shell session, then retry.

Linux / macOS (bash/zsh):

export HTTPS_PROXY=http://proxy.corp.example.com:8080
export HTTP_PROXY=http://proxy.corp.example.com:8080
export PLAYWRIGHT_DOWNLOAD_CONNECTION_TIMEOUT=120000
npx playwright install

Windows (PowerShell):

$env:HTTPS_PROXY="http://proxy.corp.example.com:8080"
$env:HTTP_PROXY="http://proxy.corp.example.com:8080"
$env:PLAYWRIGHT_DOWNLOAD_CONNECTION_TIMEOUT="120000"
npx playwright install

If the proxy requires authentication, embed credentials (URL-encode special characters, e.g. @ → %40):

export HTTPS_PROXY=http://user:p%40ssword@proxy.corp.example.com:8080

Step-by-Step Resolution

1. Confirm the proxy is reachable and identify its scheme

curl -I -x http://proxy.corp.example.com:8080 https://cdn.playwright.dev

A 200/301 response means the proxy forwards the host. A 403, 407, or timeout points to an allowlist or authentication problem (go to step 4 or 5).

2. Enable Playwright debug output

DEBUG=pw:install npx playwright install chromium

On Windows PowerShell:

$env:DEBUG="pw:install"; npx playwright install chromium

The log shows the exact URL being requested and which host fails.

See also  Resolving Python multiprocessing deadlock with SQLite3 database locks

3. Set proxy variables persistently

Linux / macOS: append to ~/.bashrc or ~/.zshrc:

export HTTPS_PROXY=http://proxy.corp.example.com:8080
export HTTP_PROXY=http://proxy.corp.example.com:8080
export NO_PROXY=localhost,127.0.0.1,.corp.example.com

Windows: set user-level variables:

setx HTTPS_PROXY "http://proxy.corp.example.com:8080"
setx HTTP_PROXY "http://proxy.corp.example.com:8080"
setx NO_PROXY "localhost,127.0.0.1,.corp.example.com"

Open a new terminal afterward; setx does not affect the current session.

Project-level (CI-friendly): set the variables in the pipeline environment rather than committing them to the repository.

4. Trust the corporate CA (TLS interception)

Export the corporate root CA as PEM (e.g. /etc/ssl/certs/corp-root-ca.pem) and point Node.js to it:

export NODE_EXTRA_CA_CERTS=/etc/ssl/certs/corp-root-ca.pem
npx playwright install

Windows:

setx NODE_EXTRA_CA_CERTS "C:\certs\corp-root-ca.pem"

Do not use NODE_TLS_REJECT_UNAUTHORIZED=0 as a permanent fix; it disables certificate validation for every Node.js process in that shell.

5. Request an allowlist for required hosts

Ask the network team to permit HTTPS (port 443) to:

cdn.playwright.dev
playwright.download.prss.microsoft.com
playwright-akamai.azureedge.net
playwright-verizon.azureedge.net

Hosts can change between Playwright versions; confirm the active host in the DEBUG=pw:install output from step 2.

6. Use an internal mirror when the CDN cannot be allowlisted

Host the browser archives on an internal artifact server (Artifactory, Nexus, or a static web server) preserving the CDN path structure, then point Playwright at it:

export PLAYWRIGHT_DOWNLOAD_HOST=https://artifacts.corp.example.com/playwright
npx playwright install

Per-browser overrides are also supported:

export PLAYWRIGHT_CHROMIUM_DOWNLOAD_HOST=https://artifacts.corp.example.com/playwright
export PLAYWRIGHT_FIREFOX_DOWNLOAD_HOST=https://artifacts.corp.example.com/playwright
export PLAYWRIGHT_WEBKIT_DOWNLOAD_HOST=https://artifacts.corp.example.com/playwright

7. Install on an unrestricted machine and copy the cache (offline fallback)

On a machine with internet access:

PLAYWRIGHT_BROWSERS_PATH=./pw-browsers npx playwright install

Transfer the pw-browsers directory to the restricted machine, then run tests with:

export PLAYWRIGHT_BROWSERS_PATH=/opt/pw-browsers
npx playwright test

The Playwright package version on both machines must match exactly, because each release pins specific browser revisions.

8. Skip the automatic download in CI and install separately

To prevent npm install from failing when the download is blocked:

export PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD=1
npm ci

Then run npx playwright install in a later pipeline stage that has proxy access, or restore the browsers from a cache.

See also  Fixing urllib3 ConnectionResetError(104, 'Connection reset by peer') during bulk API requests

9. Use a system-installed browser instead of the bundled one

If an approved Chrome or Edge is already installed, bypass the download entirely in playwright.config.ts:

import { defineConfig } from '@playwright/test';

export default defineConfig({
  use: {
    channel: 'chrome', // or 'msedge'
  },
});

This works only for Chromium-based channels; Firefox and WebKit have no equivalent system channel.

Why This Fails for Some Users

  • Proxy auto-config (PAC) files. Playwright does not evaluate PAC/WPAD scripts. Resolve the effective proxy address from the PAC file manually and set HTTPS_PROXY explicitly.
  • NTLM or Kerberos proxies. The Node.js downloader supports only Basic authentication in the proxy URL. For NTLM/Kerberos proxies, run a local forwarding proxy such as CNTLM or Px and point HTTPS_PROXY to http://127.0.0.1:3128.
  • https:// scheme in the proxy URL. Most corporate proxies accept plain HTTP on the proxy port and tunnel HTTPS with CONNECT. Setting HTTPS_PROXY=https://... against an HTTP-only proxy port causes an immediate handshake failure.
  • Lowercase vs. uppercase variables. Some environments, particularly containers with minimal shells, only expose lowercase https_proxy. Set both forms when in doubt.
  • sudo strips environment variables. sudo npx playwright install --with-deps runs without your exported proxy. Use sudo -E or pass variables inline: sudo HTTPS_PROXY=$HTTPS_PROXY npx playwright install --with-deps.
  • --with-deps uses a different network path. On Debian/Ubuntu, it invokes apt-get, which reads its own proxy config from /etc/apt/apt.conf.d/95proxy:Acquire::http::Proxy "http://proxy.corp.example.com:8080"; Acquire::https::Proxy "http://proxy.corp.example.com:8080";
  • Docker builds. Environment variables in the host shell are not inherited by docker build. Pass them as build arguments (--build-arg HTTPS_PROXY=...) and declare ARG HTTPS_PROXY plus ENV HTTPS_PROXY=$HTTPS_PROXY in the Dockerfile. Alternatively, use the official mcr.microsoft.com/playwright image, which ships with browsers preinstalled.
  • Windows service accounts and WSL. Variables set with setx apply to the user profile only. CI agents running as a service account or inside WSL need the variables set in their own environment; WSL does not inherit Windows proxy settings.
  • Download timeout too short on slow proxies. The default connection timeout is 30 seconds. Chromium archives exceed 150 MB, and proxies that buffer the full response before forwarding can exceed that window. Increase PLAYWRIGHT_DOWNLOAD_CONNECTION_TIMEOUT (milliseconds) as shown in the Quick Fix.
  • Antivirus or DLP scanning. Inline scanners can hold the download until the scan completes. Request an exclusion for the Playwright cache directory and download hosts.
  • Cache location permissions. The default cache is ~/.cache/ms-playwright (Linux), ~/Library/Caches/ms-playwright (macOS), and %USERPROFILE%\AppData\Local\ms-playwright (Windows). Read-only or roaming-profile home directories cause write failures that resemble timeouts. Override with PLAYWRIGHT_BROWSERS_PATH to a writable location.
  • Corrupt partial downloads. A previous interrupted attempt can leave a partial archive. Delete the cache directory and rerun the install.
  • Unsupported OS versions. Older distributions (e.g. Ubuntu 18.04, older RHEL/CentOS) are not supported for current Playwright releases and may fall back to a different build path or fail dependency validation after download. Verify support against the Playwright system requirements for the pinned version.
  • ARM and Apple Silicon. Architecture-specific builds are served from different paths. If the allowlist or internal mirror was populated only for x64, arm64 downloads return 404 or time out.
See also  Fix PyAutoGUI FailSafeException triggered on virtual display or headless RDP

Leave a Comment