Playwright proxy
A Playwright proxy is a Playwright launch or context option that tunnels the browser through an upstream gateway. Pass server, username, and password as separate fields — Chromium strips credentials out of a proxy URL and returns 407. Full walkthrough: the 2026 Playwright residential guide.
Full Playwright + residential proxy guide — per-context placeholder, sticky TTL, geo match, bandwidth aborts.
Why a residential Playwright proxy
Playwright already executes JavaScript and presents a real Chromium TLS fingerprint. That does not change the ASN of the machine it runs on. A GitHub runner, an AWS box, or a Hetzner VPS still looks like a datacenter to Cloudflare and DataDome. A residential proxy substitutes an ISP-assigned household exit so the destination scores the session as a consumer visit. Aethyn puts country, optional city/ISP (Elite), and sticky session on the username, so one credential set covers a single-identity scrape and a pool of isolated contexts. Rotation is a new context, not a mutated live one. Per-context proxies on Chromium are ignored unless you pass a placeholder proxy at launch — that gotcha, plus geo-matching and bandwidth aborts, is in the long guide rather than duplicated here.
Setup steps
- 1Install Playwright: pip install playwright (or npm i playwright).
- 2Pass a proxy object with server, username, and password — never user:pass@host.
- 3For many identities, launch Chromium with proxy: { server: 'per-context' }, then set the real proxy on each newContext().
- 4Put targeting suffixes (-country-, -session-, -lifetime-) in the username field.
Code
from playwright.sync_api import sync_playwright
with sync_playwright() as p:
# Chromium ignores context proxies unless launch() already has one.
browser = p.chromium.launch(proxy={"server": "per-context"})
context = browser.new_context(proxy={
"server": "http://proxy.aethyn.io:2099",
"username": "aethyn-XXXXX-country-us",
"password": "PASSWORD",
})
page = context.new_page()
page.goto("https://httpbin.org/ip")
print(page.content())
context.close()
browser.close()import { chromium } from "playwright";
const browser = await chromium.launch({
proxy: {
server: "http://proxy.aethyn.io:2099",
username: "aethyn-XXXXX-country-us",
password: "PASSWORD",
},
});
const page = await browser.newPage();
await page.goto("https://httpbin.org/ip");
console.log(await page.content());
await browser.close();Replace aethyn-XXXXX and PASSWORD with your dashboard credentials. See the full targeting reference and protocol/port list. Or use the official proxy-builder-sdk to build targeting strings without hand-assembling usernames.
Troubleshooting
The failure that looks like “the proxy is broken” is almost always credentials in the URL or a context proxy that Chromium ignored. Put username and password in the fields, never in server. To run many identities in one process, launch with proxy: { server: 'per-context' }, then set the real Aethyn gateway on each newContext(). If you launched with no proxy at all, every context-level proxy is a silent no-op. 407 means auth; net::ERR_TUNNEL_CONNECTION_FAILED usually means the wrong port (Premium HTTP 2099, Elite HTTP 5499, SOCKS5 1099/3499). A 200 with empty or challenge HTML is a soft block — see Playwright silent 403. Full setup, sticky TTL (1–1440 minutes), and locale matching: /blog/playwright-residential-proxies-2026.
Tips
- Keep server as host:port and put credentials in username/password — never user:pass@host.
- Chromium per-context proxies need launch({ proxy: { server: 'per-context' } }) or they are ignored.
- For the hardest targets, use Elite with city/ISP targeting. Long guide: /blog/playwright-residential-proxies-2026.