This Playwright proxy guide covers global configuration, Playwright proxy authentication, launch-level and per-context routing, SOCKS5 endpoints, bypass rules, route verification, and responsible geo testing. The cURL proxy guide provides a smaller command-line route check before browser automation.
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.
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.
Install Playwright and validate the browser runtime
Install Playwright Test in the existing Node project, then install the browser binary that the suite will run. In a CI image, use the installation approach documented for that operating system and keep the package lock file under review. The browser download is separate from the npm package, so a valid TypeScript import does not prove that Chromium, Firefox, or WebKit is available at runtime.
npm install --save-dev @playwright/test
npx playwright install chromium
npx playwright test --list
npx playwright test --list checks discovery without sending test traffic. Before adding a proxy, run one small owned-site test directly. That baseline separates a browser installation or application failure from a proxy failure. Pin a reviewed Playwright version, update intentionally, and test the bundled browser rather than assuming an arbitrary system executable behaves identically. The official BrowserType API describes launch behavior and warns that Playwright works best with its bundled browsers.
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: requiredEnv('PROXY_USERNAME'),
password: requiredEnv('PROXY_PASSWORD'),
bypass: process.env.PROXY_BYPASS,
},
},
});
Use a value such as http://proxy.example.invalid: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: requiredEnv('PROXY_USERNAME'),
password: requiredEnv('PROXY_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://proxy-eu.example.invalid: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.
Keep geo testing separate from browser emulation
A proxy can change network egress, but a website may also observe browser geolocation coordinates, locale, timezone, cookies, cached preferences, account history, and server-side account settings. Playwright exposes emulation options for several of these signals, but you must set them intentionally and only to test scenarios you are authorized to exercise. Do not describe a route as a complete regional user profile merely because an IP database assigns it to a country.
import { chromium } from 'playwright';
const browser = await chromium.launch();
const context = await browser.newContext({
proxy: { server: 'http://proxy.example.invalid:3128' },
locale: 'en-GB',
timezoneId: 'Europe/London',
geolocation: { longitude: -0.1276, latitude: 51.5072 },
permissions: ['geolocation'],
});
try {
const page = await context.newPage();
await page.goto('https://geo-test.example.invalid');
} finally {
await context.close();
await browser.close();
}
That example demonstrates an explicit synthetic QA profile; it is not evidence that the proxy physically resides at those coordinates. For location-sensitive products, define the expected egress region, coordinates, locale, timezone, currency, content, and account state as separate assertions. Use dedicated test accounts and synthetic records so regional tests cannot alter production customers. If the workload is still being defined, the proxy selection checklist helps translate coverage, protocol, authentication, stability, and concurrency requirements into a plan. Only then compare an appropriate private proxy service with the approved test profile.
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.
Use proxies only for authorized, rate-aware testing
A proxy changes routing; it does not bypass contracts, access controls, CAPTCHA, robots guidance, privacy obligations, or rate limits. Prefer a documented API when it serves the requirement. Obtain authorization for the destination, accounts, regions, and traffic volume before automation. Identify the test client where appropriate, use conservative concurrency, cache or reuse approved results, and stop when the destination returns an access or rate-limit response.
For crawling, read the applicable robots policy and terms before fetching. RFC 9309 standardizes the Robots Exclusion Protocol and explicitly distinguishes robots rules from access authorization. Following robots.txt is one control, not permission by itself. Production monitoring and web-data workflows also need data minimization, retention rules, and an owner who can halt the job.
A production checklist for Playwright proxy configuration
- Pin Playwright and install the matching browser runtime.
- Prove a direct baseline before adding the proxy.
- Choose global, launch-level, or per-context routing deliberately.
- Load the proxy server and HTTP credentials from an approved secret mechanism.
- Never log complete proxy URLs, credentials, cookies, or storage state.
- Use explicit
http://orsocks5://schemes. - Review every comma-separated bypass domain as a direct-routing exception.
- Keep TLS verification enabled and fix the trust chain instead of suppressing errors.
- Verify egress only through an owned or approved endpoint.
- Assert geolocation, locale, timezone, cookies, and account state separately.
- Use isolated test accounts for parallel or state-changing tests.
- Set bounded test and navigation timeouts without creating retry storms.
- Respect authorization, APIs, robots rules, privacy requirements, and rate limits.
- Close contexts and browsers deterministically and protect traces and HAR files.
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://proxy.example.invalid: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.
