Playwright Proxy: Auth, Contexts, and Testing

Configure a Playwright proxy in TypeScript with safer authentication, global or per-context routing, bypass rules, controlled checks, and geo-QA safeguards.

Written by the Mexela Editorial Team. Technical guides are reviewed by the Mexela Technical Team under the Mexela Editorial Policy.

QA workstation running browser automation through a compact proxy gateway beside a server rack and globe

Key topics:

PROXY PLANS

Ready to buy proxies for this workflow?

Use the guide below to choose the right proxy type, then start with private proxies for dedicated IPv4 access or shared proxies when price matters more.

To use a proxy with Playwright, set use.proxy in playwright.config.ts for an entire test project, pass proxy to chromium.launch() for a library-managed browser, or pass it to browser.newContext() when a test needs an isolated route. Use separate server, username, and password fields, load secrets from protected environment variables, and verify the observed route only against an endpoint you own or are authorized to test.

Scope: this guide covers a browser launch proxy, context-level proxy, HTTP proxy authentication, bypass rules, route verification, and browser troubleshooting in Playwright. Compare non-browser clients in the developer proxy overview, and find other browser integrations in the Developer Guides hub.

A Playwright proxy changes the browser’s network path; it does not grant access to a destination or automatically change geolocation permissions, JavaScript coordinates, locale, timezone, cookies, or account state. The setup should therefore be treated as one part of a reproducible QA profile. The examples below use TypeScript, placeholder .invalid values, and an APPROVED_TEST_URL environment variable so no real proxy endpoint, credential, or third-party diagnostic service is embedded in source code.

Set a global Playwright proxy in the test config

For a test project in which every page should use the same route, put the proxy under use. Playwright applies those options to the contexts created by the test runner. Keeping the server and credentials as separate fields avoids building or logging a complete credential-bearing URL. A small helper also fails before browser startup when required configuration is missing.

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

function requiredEnv(name: string): string {
  const value = process.env[name];
  if (!value) throw new Error(`Missing required environment variable: ${name}`);
  return value;
}

export default defineConfig({
  use: {
    proxy: {
      server: requiredEnv('PROXY_SERVER'),
      username: 'USER',
      password: 'PASSWORD',
      bypass: process.env.PROXY_BYPASS,
    },
  },
});

Use a value such as http://HOST:3128 for PROXY_SERVER in documentation and substitute an approved endpoint through the deployment secret mechanism. Do not print the environment object or Playwright configuration during debugging because it can contain proxy and application secrets. Environment variables are an injection mechanism, not automatically a vault; in CI, use masked secrets and restrict which jobs and users can read them.

The official Playwright network guide documents global and per-context proxy settings, HTTP(S) and SOCKSv5 support, optional HTTP proxy credentials, and bypass hosts. The separate username and password fields are for HTTP proxy authentication; they are not the same as a destination website’s HTTP authentication or application login. See the proxy authentication methods guide for the operational difference between credentials and IP allowlisting.

Configure a launch-level proxy with the Playwright library

Scripts that use the playwright library directly can set the route when launching the browser. This is useful for a single-purpose automation process whose contexts all share one network path. Close both the context and browser deterministically so processes, temporary profiles, downloads, and recordings do not accumulate after failures.

import { chromium } from 'playwright';

function requiredEnv(name: string): string {
  const value = process.env[name];
  if (!value) throw new Error(`Missing required environment variable: ${name}`);
  return value;
}

async function main(): Promise<void> {
  const browser = await chromium.launch({
    proxy: {
      server: requiredEnv('PROXY_SERVER'),
      username: 'USER',
      password: 'PASSWORD',
    },
  });

  try {
    const context = await browser.newContext();
    const page = await context.newPage();
    page.setDefaultNavigationTimeout(30_000);
    await page.goto(requiredEnv('APPROVED_TEST_URL'), { waitUntil: 'domcontentloaded' });
    await context.close();
  } finally {
    await browser.close();
  }
}

void main();

Prefer the test-runner configuration when projects, fixtures, retries, reports, and parallel workers are already part of the suite. Prefer launch-level configuration for a focused library script. Avoid undocumented browser command-line flags when the supported proxy object expresses the requirement; custom arguments can change behavior across browser releases and make failures harder to reproduce.

Use a Playwright proxy per context for route isolation

A browser context is an isolated, incognito-like session with its own cookies and storage. Playwright also accepts proxy settings on browser.newContext(), allowing a library script to give contexts different approved routes without launching a browser process for every route. That can reduce startup cost, but it does not make the contexts interchangeable: each route and test identity still needs independent evidence and cleanup.

import { chromium, type BrowserContextOptions } from 'playwright';

type ApprovedProfile = {
  name: string;
  proxy: NonNullable<BrowserContextOptions['proxy']>;
  url: string;
};

const profiles: ApprovedProfile[] = [
  {
    name: 'approved-eu-route',
    proxy: { server: 'http://HOST:3128' },
    url: 'https://app.example.invalid/status',
  },
  {
    name: 'approved-us-route',
    proxy: { server: 'socks5://proxy-us.example.invalid:1080' },
    url: 'https://app.example.invalid/status',
  },
];

const browser = await chromium.launch();
try {
  for (const profile of profiles) {
    const context = await browser.newContext({ proxy: profile.proxy });
    try {
      const page = await context.newPage();
      await page.goto(profile.url, { waitUntil: 'domcontentloaded' });
      console.log(profile.name, 'completed');
    } finally {
      await context.close();
    }
  }
} finally {
  await browser.close();
}

The sample is intentionally sequential. Parallelism multiplies load on the proxy, the destination, and shared test data. Increase it only after the destination owner and proxy plan allow the proposed traffic, and give state-changing tests separate test accounts. Playwright’s authentication guidance recommends distinct accounts for parallel tests that modify shared server-side state and warns that saved browser state may contain sensitive cookies and headers. A changed proxy context does not sanitize a reused storageState file.

Choose context-level routing when isolation is part of the test case; choose a global proxy when the whole project has one expected egress. If you need many unrelated long-lived identities, separate workers or browser processes may be easier to observe and contain. The related Python Requests proxy guide covers the same route-versus-destination distinction for an HTTP client without browser state.

Handle authentication, protocols, and bypass rules deliberately

For an authenticated HTTP proxy, supply username and password separately. Keep them out of screenshots, traces, CI command lines, exception text, and copied configuration. Rotate exposed credentials and prefer short-lived or narrowly scoped access when the provider supports it. A 407 Proxy Authentication Required response points to the proxy hop; a 401 Unauthorized response usually comes from the destination. Treat them as different systems.

Playwright supports HTTP and SOCKS proxy servers. An HTTP proxy is often the straightforward choice for browser web traffic and may tunnel HTTPS destinations. A SOCKS5 endpoint operates at a lower transport level and can suit applications that require it. Use an explicit scheme such as http:// or socks5:// so reviewers can see the intended protocol, even though Playwright treats a short host:port form as HTTP. Confirm that the proxy service, browser engine, and authentication method support the same combination; do not assume HTTP credential behavior applies to every SOCKS service. The HTTP versus SOCKS5 guide provides a broader protocol comparison.

The optional bypass field is a comma-separated domain list. Bypassed destinations connect directly, so the list is a routing and data-exposure decision, not merely an optimization. Keep it narrow, review changes, and test every entry from the same runner environment. A typo can send traffic through the proxy when direct routing was intended, while an overly broad suffix can expose requests that were expected to use the proxy.

Verify the route with a controlled Playwright test

A successful page load proves only that one navigation completed. A useful route check compares a direct baseline with the proxy run and validates the observed egress through an owned or explicitly approved diagnostic endpoint. The endpoint can return a small JSON document such as {"ip":"redacted in logs"}. Assert the expected value from a protected environment variable, but do not print the actual address or the proxy URL into public CI output.

import { test, expect } from '@playwright/test';

test('uses the approved proxy egress', async ({ page }) => {
  const testUrl = process.env.APPROVED_TEST_URL ?? '';
  const expectedEgress = process.env.EXPECTED_EGRESS_IP ?? '';
  test.skip(!testUrl || !expectedEgress, 'Approved route-check settings are required');

  const response = await page.goto(testUrl, { waitUntil: 'domcontentloaded' });
  expect(response?.ok()).toBe(true);

  const body = (await response?.json()) as { ip?: string } | undefined;
  expect(body?.ip).toBe(expectedEgress);
});

Run a small number of checks and record the stage rather than retrying blindly. Validate egress, expected country or region when applicable, TLS, navigation status, and stability separately. Never make a public IP-check service an unreviewed dependency of every test. The proxy verification guide explains why connectivity and suitability are different outcomes, while the DNS and WebRTC leak guide covers browser-side checks that a simple egress assertion does not.

Troubleshoot by identifying the failing hop

Do not fix every network error by increasing timeouts or disabling checks. Keep TLS validation enabled; ignoreHTTPSErrors can hide a certificate or interception problem and is not a proxy repair. Start with the direct baseline, then confirm the endpoint scheme and port, proxy credentials or allowlist, DNS reachability, proxy connection, TLS tunnel, destination response, and application assertion in that order.

Symptom Likely boundary Next controlled check
Browser executable is missing Playwright runtime Install the pinned browser and rerun a direct owned-site test.
Connection refused or timed out before navigation Runner to proxy Confirm scheme, hostname, port, firewall, and allowlist without printing secrets.
407 response Proxy authentication Check the approved credential source and authentication method.
401, 403, or CAPTCHA page Destination policy or application auth Stop retries and confirm authorization, test account, API option, and destination rules.
TLS or certificate error Tunnel or trust chain Inspect the certificate path and install the approved CA where required; do not suppress verification.
Expected country but wrong language or timezone Browser or account profile Set and assert locale, timezone, geolocation, cookies, and account state separately.
Some hosts avoid the proxy Bypass configuration Review the comma-separated domains and run one approved check per rule.
Only CI fails Environment difference Compare masked variables, outbound firewall, browser version, certificates, and DNS.

Capture enough evidence to name the failing stage, but redact proxy credentials, authorization headers, cookies, query strings, and complete storage-state files. Traces and HAR files can contain sensitive request data, so limit collection, access, and retention. Follow the proxy troubleshooting guide when the failure is not specific to Playwright.

Match configuration to the current Playwright API

The official BrowserType proxy option defines server, bypass, username, and password fields. The Playwright network guide shows global and per-context proxy scopes, while the test-use network options document configuration for Playwright Test. Keep the Playwright package and bundled browser versions aligned.

Expected observation: the selected browser or context uses the intended proxy, HTTP credentials are supplied at the proxy boundary, bypass hosts remain direct by design, and a clean context reports the assigned exit without leaking state from another test.

Operational limits: browser automation must remain authorized and rate-aware. A proxy does not erase cookies, account history, browser fingerprints, consent state, or destination policy. Keep concurrency bounded, isolate contexts, and stop when access is denied.

Choose capacity only after the client passes

If regional QA is part of an approved test plan, compare the verified country, latency, and browser-session requirements with currently available proxy locations. Review the relevant Mexela option only after the acceptance test is repeatable.

Frequently asked questions

How do I set a proxy in Playwright?

Set use.proxy in playwright.config.ts for a test project, pass proxy to browserType.launch() for a whole library-managed browser, or pass it to browser.newContext() for an isolated context. Provide an explicit server scheme and test the route through an approved endpoint.

How does Playwright proxy authentication work?

For an HTTP proxy, Playwright accepts separate username and password fields alongside server. Load them from a protected secret source and distinguish a proxy’s 407 response from destination authentication failures.

Can Playwright use a SOCKS5 proxy?

Yes. Playwright documents SOCKSv5 support and accepts a server such as socks5://HOST:1080. Confirm the endpoint, browser engine, and provider’s authentication requirements instead of assuming HTTP proxy credential behavior applies to SOCKS.

Can each Playwright browser context use a different proxy?

Yes. Pass a proxy object to browser.newContext(). Per-context routing can isolate approved test routes while sharing a browser process, but cookies, storage state, test accounts, traffic limits, and cleanup still need deliberate isolation.

Does a Playwright proxy change browser geolocation and timezone?

No. A proxy can change network egress, but Playwright geolocation, locale, timezone, permissions, cookies, and account state are separate settings. Define and assert each signal required by the authorized geo-QA scenario.

Why does my Playwright proxy return 407 or fail only in CI?

A 407 response normally indicates proxy authentication. CI-only failures can also come from missing masked variables, outbound firewall rules, IP allowlists, DNS, certificate trust, or a different browser build. Compare the failing stage with a direct baseline and redact all secrets from evidence.