Products
Datacenter proxies from $19/mo Rotating proxies from $49/mo ISP proxies from $33/mo Dedicated proxies from $3.50/mo UDP proxies from $5/mo Try proxies
Use cases
Data & scraping AI services Social media & messaging E-commerce & finance Media & entertainment Marketing & ads Automation & tools All use cases →
Pricing
Full pricing table All 20 locations Money-back guarantee
Resources
Blog Proxy API MCP server Setup guides FAQ For business About us Affiliate program
English
English Русский

How to set a proxy in Playwright

Playwright has first-class proxy support built into the API: you pass a proxy object either to launch() — for the whole browser — or to newContext() — for an individual browser context. It works the same way in Chromium, Firefox, and WebKit, and username/password authentication is handled by Playwright itself, with no login popups to dismiss. Below are working examples for Node.js and Python.

Before you start: proxy details and ports

You'll need your proxy IP address and port. Both are listed in your Dashboard — open your active subscription to see the full connection details. The port depends on how you want to authenticate:

Authentication HTTP port SOCKS5 port Good for
Username / password
credentials from your Dashboard
8080 1080 Running scripts from machines whose IP changes
IP whitelisting
no login required
8085 1085 Servers with a static IP — keeps credentials out of your code

With IP whitelisting, you first add your server's IP address to the whitelist in the Dashboard — after that, the proxy object only needs the server field.

Set a proxy for the whole browser

Pass the proxy option to launch() — every page and context inherits it:

Node.js

const { chromium } = require('playwright'); (async () => { const browser = await chromium.launch({ proxy: { server: 'http://123.45.67.89:8080', username: 'your-login', password: 'your-password' } }); const page = await browser.newPage(); await page.goto('https://api.ipify.org'); console.log(await page.textContent('body')); // prints the proxy IP await browser.close(); })();

Python

from playwright.sync_api import sync_playwright with sync_playwright() as p: browser = p.chromium.launch(proxy={ "server": "http://123.45.67.89:8080", "username": "your-login", "password": "your-password", }) page = browser.new_page() page.goto("https://api.ipify.org") print(page.text_content("body")) # prints the proxy IP browser.close()

In Playwright Test, set the same object once in playwright.config.ts and every test picks it up:

import { defineConfig } from '@playwright/test'; export default defineConfig({ use: { proxy: { server: 'http://123.45.67.89:8080', username: 'your-login', password: 'your-password' } } });

The username and password fields answer the proxy's authentication challenge automatically — this is the whole fix for “proxy authentication” issues that plague raw --proxy-server flags in Chromium. Keep credentials in environment variables rather than in the script itself. On port 8085 with IP whitelisting, drop both fields and pass only server.

A different proxy per context

A browser context is Playwright's isolated “incognito profile,” and each one can carry its own proxy — handy when one script needs several identities or locations at once:

Node.js

const browser = await chromium.launch(); const usContext = await browser.newContext({ proxy: { server: 'http://123.45.67.89:8085' } }); const deContext = await browser.newContext({ proxy: { server: 'http://98.76.54.32:8085' } });

Python

browser = p.chromium.launch() context = browser.new_context(proxy={"server": "http://123.45.67.89:8085"}) page = context.new_page()

If you need a persistent profile (cookies and storage saved to disk), launch_persistent_context() accepts the same proxy option:

context = p.chromium.launch_persistent_context( "/path/to/profile", proxy={"server": "http://123.45.67.89:8085"}, )

SOCKS5 proxies

Change the scheme in server to use SOCKS5:

browser = p.chromium.launch(proxy={"server": "socks5://123.45.67.89:1085"})

One important limitation: Playwright doesn't pass credentials to SOCKS5 proxies — the username/password fields apply to HTTP proxies only. So for SOCKS5, use port 1085 with IP whitelisting. For most Playwright work an HTTP proxy is the simpler choice anyway.

You may have seen socks5h:// in curl or Python requests manuals — there the extra “h” makes the proxy resolve domain names instead of your machine, so DNS lookups don't leak outside the proxy. Browsers don't recognize that scheme and don't need it: per the Chromium documentation, with a plain socks5:// proxy name resolution is always done on the proxy side.

Sending some hosts around the proxy

The optional bypass field lists hosts that should connect directly — for example, your own staging servers:

proxy: { server: 'http://123.45.67.89:8085', bypass: 'localhost, .internal.example.com' }

Loading proxies from a list and rotating them

With a proxy package, nobody types addresses into code by hand: export your full list from the Dashboard to a file — one IP:port per line, the field order and delimiter are configurable at export — and load it at the start of the script:

Python

from playwright.sync_api import sync_playwright # proxies.txt — one address per line: 123.45.67.89:8085 with open("proxies.txt") as f: proxies = [f"http://{line.strip()}" for line in f if line.strip()] with sync_playwright() as p: # whitelisted machine: the placeholder launch proxy enables per-context proxies in Chromium browser = p.chromium.launch(proxy={"server": "per-context"}) for server in proxies: context = browser.new_context(proxy={"server": server}) page = context.new_page() page.goto("https://example.com") # ... scrape ... context.close() browser.close()

Node.js

const fs = require('node:fs'); const { chromium } = require('playwright'); // proxies.txt — one address per line: 123.45.67.89:8085 const proxies = fs.readFileSync('proxies.txt', 'utf8') .split('\n').map(s => s.trim()).filter(Boolean) .map(s => `http://${s}`); const browser = await chromium.launch({ proxy: { server: 'per-context' } }); for (const server of proxies) { const context = await browser.newContext({ proxy: { server } }); const page = await context.newPage(); await page.goto('https://example.com'); // ... scrape ... await context.close(); } await browser.close();

If your list runs on the credential ports (8080 for HTTP), you don't need a new export — set the username and password once as constants and pass them alongside each address; Playwright answers the auth challenge for you:

from playwright.sync_api import sync_playwright LOGIN, PASSWORD = "your-login", "your-password" # proxies.txt — one address per line: 123.45.67.89:8080 with open("proxies.txt") as f: proxies = [f"http://{line.strip()}" for line in f if line.strip()] with sync_playwright() as p: browser = p.chromium.launch(proxy={"server": "per-context"}) for server in proxies: context = browser.new_context(proxy={ "server": server, "username": LOGIN, "password": PASSWORD, }) page = context.new_page() page.goto("https://example.com") # ... scrape ... context.close() browser.close()

The Node.js version takes the same three fields — { server, username, password } — in newContext(). Remember the HTTP-only caveat: Chromium rejects SOCKS5 credentials, so credential-based rotation runs on port 8080. And if your exported file already embeds credentials (login:password@IP:port lines), split each line once at @ and fill the same three fields — Playwright doesn't parse credentials out of the server URL reliably across engines.

Contexts are cheap to create and destroy, so “one context per proxy from the list” is the standard rotation pattern. Our packages start at 100 IPs, so the list itself isn't the bottleneck — and when a target starts rate-limiting, refresh the list on request and re-export the file. Which of our proxy types fits Playwright best, with pricing and specs, is broken down on the proxies for Playwright page.

If something doesn't work

The most common causes: ERR_TUNNEL_CONNECTION_FAILED or ERR_PROXY_CONNECTION_FAILED usually means the port doesn't match the authentication method (see the table) — or, on ports 8085/1085, that the machine's IP isn't whitelisted; an authentication error on a SOCKS5 proxy means credentials were expected to work where Playwright doesn't send them — switch to port 1085 with whitelisting; and if a context behaves differently from the rest, check whether it overrides the launch-level proxy with its own. If none of these is it, message us in live chat right on this page — we'll help you get connected.