Web Scraping & Automation

Playwright Proxies: Setup, Authentication and Per-Context Proxies

How to use proxies with Playwright in Node.js and Python: launch-level and context-level proxies, authentication, SOCKS5, rotating proxies, bypass lists and troubleshooting.

By Team of Monkeys Editorial Updated 4 min read Affiliate disclosure

This guide contains affiliate links to Geonode. If you buy through them we may earn a commission, at no extra cost to you.

Playwright's built-in proxy support

Playwright, Microsoft's browser automation library for Chromium, Firefox and WebKit, has first-class proxy support. Unlike Puppeteer, where authentication needs page.authenticate(), Playwright accepts a username and password directly in its proxy configuration, and it supports separate proxies per browser context out of the box.

Launch-level proxy (Node.js)

javascript
import { chromium } from 'playwright';

const browser = await chromium.launch({
  proxy: {
    server: 'http://gate.example.com:7777',
    username: 'customer-USER-country-us',
    password: 'PASS',
  },
});
const page = await browser.newPage();
await page.goto('https://httpbin.org/ip');
console.log(await page.textContent('body'));
await browser.close();

Launch-level proxy (Python)

python
from playwright.sync_api import sync_playwright

with sync_playwright() as p:
    browser = p.chromium.launch(proxy={
        "server": "http://gate.example.com:7777",
        "username": "customer-USER-country-us",
        "password": "PASS",
    })
    page = browser.new_page()
    page.goto("https://httpbin.org/ip")
    print(page.text_content("body"))
    browser.close()

Per-context proxies

Each browser context can have its own proxy, which is ideal for running several identities or locations in one browser:

javascript
const browser = await chromium.launch();
const us = await browser.newContext({
  proxy: { server: 'http://gate.example.com:7777', username: 'customer-USER-country-us', password: 'PASS' },
  locale: 'en-US',
  timezoneId: 'America/New_York',
});
const de = await browser.newContext({
  proxy: { server: 'http://gate.example.com:7777', username: 'customer-USER-country-de', password: 'PASS' },
  locale: 'de-DE',
  timezoneId: 'Europe/Berlin',
});

Note the locale and timezoneId options: Playwright makes it easy to match the browser to the proxy's location, which reduces fingerprint mismatches. See browser fingerprinting and proxies.

On older Playwright versions with Chromium on Windows, per-context proxies required launching the browser with a placeholder global proxy (for example proxy: { server: 'http://per-context' }). Current versions don't need this, but keep it in mind if you're on an old release.

SOCKS5

javascript
const browser = await chromium.launch({ proxy: { server: 'socks5://203.0.113.10:1080' } });

As with Puppeteer, SOCKS5 authentication isn't supported by Chromium in Playwright; use IP whitelisting or a local forwarder. See SOCKS5 proxies.

Bypassing the proxy for some hosts

javascript
proxy: { server: 'http://gate.example.com:7777', bypass: 'localhost,.internal.example.com' }

Rotating proxies in Playwright

Create a new context per session with a new session ID (for rotating residential) or the next proxy from your list (for static proxies):

javascript
const newSession = () => `customer-USER-country-us-session-${Math.random().toString(36).slice(2, 10)}`;

async function scrape(browser, url) {
  const ctx = await browser.newContext({
    proxy: { server: 'http://gate.example.com:7777', username: newSession(), password: 'PASS' },
  });
  try {
    const page = await ctx.newPage();
    const res = await page.goto(url, { waitUntil: 'domcontentloaded', timeout: 45000 });
    return { status: res?.status(), html: await page.content() };
  } finally {
    await ctx.close();
  }
}

See proxy rotation strategies.

Saving bandwidth

Block heavy resources with routing:

javascript
await ctx.route('**/*', (route) => {
  const t = route.request().resourceType();
  return ['image', 'media', 'font'].includes(t) ? route.abort() : route.continue();
});

On per-GB residential proxies, this can cut costs dramatically.

Proxy tip: If you need a pool to run this against, Geonode works with every tool in this guide: rotate per request for stateless pages, or hold a sticky session for logins and pagination. See using Geonode with Playwright for working code.

Troubleshooting

ProblemFix
407 Proxy Authentication RequiredCheck username/password; ensure they're in the proxy object, not the server URL
ERR_PROXY_CONNECTION_FAILEDWrong host/port or scheme
Per-context proxy ignoredUpdate Playwright; on old versions use the per-context placeholder
SOCKS5 fails with credentialsWhitelist IP or use a forwarder

See common proxy errors.

Playwright vs Puppeteer for proxies

PlaywrightPuppeteer
Auth in configYesNo (page.authenticate())
Per-context proxyYes, matureYes, in recent versions
Locale/timezone per contextBuilt inVia page emulation
BrowsersChromium, Firefox, WebKitChrome/Chromium (Firefox experimental support)

Playwright proxy patterns by use case

Use casePattern
One proxy for everythingLaunch-level proxy
Many locations in parallelOne context per location with its own proxy, locale and timezone
Rotating residentialNew context per session with a new session ID
Logged-in accountsOne persistent context per account (launchPersistentContext) with a static ISP proxy
Mixed proxies and direct trafficbypass list for internal hosts

Persistent contexts for accounts

For workflows that need cookies to survive between runs, use a persistent context with a dedicated proxy:

python
from playwright.sync_api import sync_playwright

with sync_playwright() as p:
    ctx = p.chromium.launch_persistent_context(
        user_data_dir="profiles/account-01",
        proxy={"server": "http://203.0.113.21:8000", "username": "u", "password": "p"},
        locale="en-GB",
        timezone_id="Europe/London",
    )
    page = ctx.new_page()
    page.goto("https://example.com/account")
    ctx.close()

Each account keeps its own profile directory and static IP. See static residential proxies.

Checking the exit location per context

javascript
async function exitInfo(context) {
  const page = await context.newPage();
  await page.goto('https://ipinfo.io/json');
  const info = JSON.parse(await page.textContent('body'));
  await page.close();
  return info; // { ip, city, region, country, org, timezone }
}

You can use the returned timezone to set up a new context with matching settings, which reduces fingerprint mismatches. See browser fingerprinting and proxies.

Firefox and WebKit

Playwright's proxy options work across Chromium, Firefox and WebKit, which lets you vary browser engines as part of your fingerprint strategy. Behaviour details (such as SOCKS authentication) can differ by engine, so test each.

For more on browsers and proxies, see headless browser proxies and our Puppeteer proxies guide.

Playwright and proxies in test suites

Playwright Test can set a proxy in the config so every test runs through it, useful for testing your own site from another region:

javascript
// playwright.config.js
import { defineConfig } from '@playwright/test';
export default defineConfig({
  use: {
    proxy: { server: 'http://gate.example.com:7777', username: process.env.PROXY_USER, password: process.env.PROXY_PASS },
    locale: 'de-DE',
    timezoneId: 'Europe/Berlin',
  },
});

Define separate projects for different regions (each with its own proxy, locale and timezone) to run the same tests across markets. For QA of your own sites, datacenter proxies in each region are usually sufficient and cheap.

Debugging proxy problems with the trace viewer

When a proxied Playwright run fails, the trace viewer often shows why faster than log statements. Record a trace around the failing flow:

javascript
const context = await browser.newContext({
  proxy: { server: 'http://gate.example.com:7777', username: 'USER', password: 'PASS' },
});
await context.tracing.start({ screenshots: true, snapshots: true });
const page = await context.newPage();
await page.goto('https://example.com');
await context.tracing.stop({ path: 'trace.zip' });

Open it with npx playwright show-trace trace.zip. The Network tab lists every request with its status and timing, so you can see:

  • Which requests failed and with what status. A wall of 407s points to credentials; 403s on the main document point to the target.
  • Whether a challenge page was served instead of content, from the snapshots.
  • Slow requests that suggest a slow exit, or resources you should be blocking to save bandwidth.

Keep traces off in normal runs, since they're large, and turn them on for failing jobs or a small sample. Treat trace files as sensitive: they can contain cookies and page content.

The official guide to Playwright's proxy settings covers the options used above. For errors and their meanings, see common proxy errors, and for comparing frameworks, headless browser proxies.

Key takeaways

  • Playwright accepts proxy server, username and password directly at launch or per context.
  • Per-context proxies, with matching locale and timezoneId, make multi-location work straightforward.
  • SOCKS5 authentication isn't supported in Chromium; use IP whitelisting or a forwarder.
  • Rotate by creating a new context per session; block heavy resources with routing to save bandwidth.
  • Persistent contexts with static ISP proxies suit logged-in accounts. See headless browser proxies.

FAQ

Can Playwright use a different proxy for each page?

Per context, yes. Pages in the same context share the context's proxy.

Does Playwright work with residential proxies?

Yes, with any HTTP(S) proxy. Use sticky sessions per context.

What are the best proxies for Playwright?

Same as for Puppeteer: rotating residential with sticky sessions for protected sites, ISP for logged-in sessions, datacenter for lenient sites. See best proxies for web scraping.

Affiliate disclosure: Team of Monkeys is a Geonode affiliate. Links and banners marked as sponsored, and links to Geonode in the text, use our referral link, and we may earn a commission if you buy through them, at no extra cost to you. Our explanations and comparisons are written to be useful whichever provider you choose.

Editorial note: Proxy providers change their pools, features and prices often, so treat any figures here as typical ranges at the time of writing and confirm current terms with the provider before you buy.