Skip to content

How to Use Proxies With Playwright (Chromium, Firefox, WebKit)

Playwright's proxy option from its own docs and source: browser-wide or per context, why user:pass in the server URL is dropped, SOCKS5 without a login, bypass.

HProxy TeamJuly 21, 2026Updated October 13, 20267 min read

How to Use Proxies With Playwright (Chromium, Firefox, WebKit)

Playwright takes a proxy as one small object with four fields: server, bypass, username and password. You can pass it when you launch the browser or when you create a context. The fields behave exactly as Playwright's own code says, and two of its rules catch most people: a login inside the server URL disappears, and a SOCKS5 proxy cannot take a login at all.

This guide follows Playwright's documentation and source on its main branch, read on October 13, 2026, with version 1.64.0 of October 7, 2026, the latest release on npm. We ran none of the code for this page.

Set the proxy at launch or per context

Playwright's network guide puts it in one line: "Proxy can be either set globally for the entire browser, or for each browser context individually." At launch, the proxy covers every context in that browser.

const { chromium } = require('playwright');

(async () => {
  const browser = await chromium.launch({
    proxy: { server: 'http://203.0.113.7:8080', username: 'user', password: 'pass' },
  });
  const page = await browser.newPage();
  await page.goto('https://httpbin.org/ip');
  console.log(await page.textContent('body'));
  await browser.close();
})();

Per context, the proxy covers that context only. The option's documentation reads "Network proxy settings to use with this context. Defaults to none." Playwright describes contexts as "isolated clean-slate environments", each with its own cookies and storage, so two contexts in one browser can use two proxies at once.

from playwright.sync_api import sync_playwright

with sync_playwright() as p:
    browser = p.chromium.launch()
    context = browser.new_context(
        proxy={"server": "http://203.0.113.7:8080", "username": "user", "password": "pass"}
    )
    page = context.new_page()
    page.goto("https://httpbin.org/ip")
    print(page.text_content("body"))
    context.close()
    browser.close()

The same object works for chromium, firefox and webkit. The server accepts both kinds of proxy: "HTTP and SOCKS proxies are supported, for example" http://myproxy.com:3128 or socks5://myproxy.com:3128. A server without a scheme counts as HTTP: "Short form myproxy.com:3128 is considered an HTTP proxy."

Why user:pass in the server URL disappears

Many tools accept http://user:pass@host:port. Playwright does not keep that part. Its function normalizeProxySettings parses the server and rebuilds it with one line, server = url.protocol + '//' + url.host;. Protocol and host survive, and the username and password inside the URL are gone before the browser starts. A proxy that needs a login then answers 407 Proxy Authentication Required.

Why user:pass in Playwright's proxy server disappears, and the fix
  1. server: http://user:pass@host

    the login sits in the URL

  2. normalizeProxySettings

    keeps protocol and host only

  3. Proxy answers 407

    no login reached it

  4. username and password fields

    the login in its own fields

Source: Playwright's server source and docs, main branch, read October 13, 2026 · hproxy.comProxy.
// Dropped: Playwright keeps only protocol and host from this URL
const context = await browser.newContext({
  proxy: { server: 'http://user:pass@203.0.113.7:8080' },
});

// Kept: the login in its own fields
const context2 = await browser.newContext({
  proxy: { server: 'http://203.0.113.7:8080', username: 'user', password: 'pass' },
});

The fields are documented for HTTP proxies: "Optional username to use if HTTP proxy requires authentication." Playwright turns them into a Basic credential, and one of its code paths adds the header Proxy-Authorization itself. Our guide to 407 Proxy Authentication Required covers the proxy's side of that exchange.

Printed on our own machine on October 13, 2026, from Playwright's documentation and server source, saved that day; no request was made while printing and no Playwright code was run.

SOCKS5: no login, and names resolve at the proxy

A socks5:// server works, without a username or password. The same normalizing function refuses the combination: with a login on a SOCKS5 server it throws "Browser does not support socks5 proxy authentication", and for SOCKS4 "Socks4 proxy protocol does not support authentication". So a SOCKS5 proxy that needs a login cannot be used this way. Use the provider's HTTP endpoint with the fields, or let the provider admit your address without a password.

On Chromium, Playwright adds one more argument for a SOCKS5 proxy: --host-resolver-rules with "MAP * ~NOTFOUND , EXCLUDE" and the proxy's own host. Every local DNS lookup except the proxy's fails on purpose, so hostnames resolve at the proxy.

Hosts that skip the proxy

The bypass field takes a comma-separated list, and the docs give the example ".com, chromium.org, .domain.com". For Chromium, Playwright turns the list into Chrome's own switch, --proxy-bypass-list, and rewrites a leading dot as a wildcard (t.startsWith('.') ? '*' + t : t).

What Playwright does with each proxy setting

SettingResultWhere
Server, no schemeHTTP proxyThe docs
user:pass in serverDroppedIts source
SOCKS5 with loginErrorIts source
SOCKS5 on ChromiumDNS at proxyIts source
bypass listSkips proxyThe docs

Playwright docs (network.md, params.md) and server source (browserContext.ts, chromium.ts), main branch, read October 13, 2026

Spreading work over several proxies

Two set-ups keep the code simple. Give each new context its own proxy from your list, and close the context when its work is done. Or point every context at one rotating gateway: one host and port in the proxy object, with the outgoing address changing behind it.

const browser = await chromium.launch();
for (const proxy of proxies) {               // [{ server, username, password }, ...]
  const context = await browser.newContext({ proxy });
  try {
    const page = await context.newPage();
    await page.goto('https://httpbin.org/ip', { timeout: 20000 });
    console.log(proxy.server, await page.textContent('body'));
  } finally {
    await context.close();
  }
}
await browser.close();

Use addresses you are allowed to use. Each site's terms and robots.txt apply whatever address a request comes from.

Check the exit

Load an address-echo page through the context and compare it with your own address. If the two match, the proxy is not in use; the usual causes are a login left in the server URL or a context created without the proxy. Our proxy checker tests a proxy from your own connection before you put it into a script.

What a site can see

A proxy changes the address a request comes from. Automation itself is visible by design: MDN describes navigator.webdriver as the property that tells a page whether the browser is "controlled by automation." Whether a site accepts automated browsers is that site's decision. This page gives no way to hide automation or to get past a site's checks.

  • SpyderProxy says "Use stealth patches. Libraries like playwright-stealth hide automation flags (navigator.webdriver and friends) that anti-bot systems check." The flag exists so a page can tell an automated browser; hiding it works around the site's own checks.
  • ZenRows writes that a proxy lets you "avoid IP bans and access geo-restricted content", and skips what Playwright does with a login inside the server URL.
  • Oxylabs answers the detection question with tools "that will help ensure smooth and block-free data-gathering". A site that blocks automated browsers has decided, and a proxy leaves that decision as it was.
  • Bright Data says a proxy "helps mask your real IP address and bypass rate limiters", and shows how to change the User-Agent "To avoid detection". Both work around the site's own rules.
  • ScrapingBee suggests rotating user agents so requests "appear to come from different browsers and devices, reducing the chances of getting blocked".

Where HProxy fits

Our residential proxies put a rotating gateway behind one host and port, which suits the set-up above, with the login in the username and password fields, from $0.44 per GB. Premium lines take SOCKS5 as well as HTTP, and an IP whitelist admits your machine's address without a password, so a SOCKS5 line works in Playwright with no login to send. Premium also holds one address for up to 24 hours, from $1.00 per GB.

What we could not find out

  • How Firefox and WebKit resolve names behind a SOCKS5 proxy. We read Playwright's Chromium launcher only.
  • Whether every proxy accepts the Basic credential Playwright sends. Playwright's code sends Basic; we used no proxy.
  • How releases before 1.64 behaved. We read the main branch.

Sources

Read on October 13, 2026.

  • Playwright documentation source: network.md (HTTP Proxy), params.md (the proxy option) and browser-contexts.md.
  • Playwright server source: browserContext.ts and chromium.ts.
  • npm: playwright, version 1.64.0 of October 7, 2026.
  • MDN: Navigator.webdriver.
  • Demand data: Google Keyword Planner volumes and Search Console figures for this URL, July 15 to October 12, 2026.
  • Guides we judged, read the same day and deliberately left unlinked: SpyderProxy, ZenRows, Oxylabs, Bright Data and ScrapingBee.

Frequently asked questions

How do I set a proxy in Playwright?

Pass a proxy object with a server field when you launch the browser, or when you create a context: browser.newContext({ proxy: { server: 'http://host:port' } }). Playwright's docs say a proxy can be set for the entire browser or for each browser context. Add the username and password fields for an HTTP proxy that needs a login, and bypass for hosts that should skip the proxy.

Why is my Playwright proxy username and password ignored?

Because they sit in the server URL. Playwright rebuilds the server from the URL's protocol and host, so a user:pass@ part is dropped before the browser sees it, and a proxy that needs a login answers 407. Put the credentials in the separate username and password fields, which Playwright uses to answer the proxy's login.

Can I use a different proxy per browser context in Playwright?

Yes. Playwright lists proxy among the context options, and a context's proxy defaults to none. Contexts are isolated, clean-slate sessions, each with its own cookies and storage, so two contexts in one browser can use two different proxies at the same time. Close a context when its work is done.

Does Playwright support SOCKS5 proxies?

Yes, with server: 'socks5://host:1080', but without a login. Playwright's own code throws Browser does not support socks5 proxy authentication when a SOCKS5 proxy gets a username or password, and SOCKS4 takes none either. On Chromium, Playwright also stops local DNS lookups for a SOCKS5 proxy, so names resolve at the proxy. For a proxy that needs a login, use its HTTP endpoint or an address allow list.

How do I rotate proxies in Playwright?

Either give each new context its own proxy from your list, or point every context at one rotating gateway, where the address changes behind one host and port. The gateway keeps your script a one-proxy script. Use addresses you are allowed to use; each site's own rules apply whatever the address.

Does a proxy stop Playwright from being detected?

A proxy changes the address a site sees. Automation is visible by design: in MDN's words, navigator.webdriver indicates whether the browser is controlled by automation. Whether a site accepts automated browsers is the site's decision, and this page gives no way to hide automation.

Proxies that don't die mid-job

Residential, ISP, datacenter and mobile, verified by the same engine that runs tens of millions of checks. They read as a real device and hold up under load. Pay as you go, and your balance never expires. $0.44/GB is the 2,000 GB+ rate; a single gigabyte is $0.50/GB, with no minimum order.

129M+ proxy checks run · 100+ countries · HTTP / HTTPS / SOCKS · re-checked every few minutes · no signup

HProxy.

Honest guides and comparisons on proxies, scraping and staying unblocked, from the team that runs the network.

RSS feed