Why Playwright is easy with proxies
Playwright accepts a proxy server, username and password as structured options, so you don't need workarounds for authentication. You can set a proxy for the whole browser or for each browser context, which makes per-session IPs straightforward. Background in Playwright proxies.
Node.js: proxy at launch
import { chromium } from "playwright";
const browser = await chromium.launch({
proxy: {
server: "http://p.webshare.io:80",
username: `${process.env.WS_USER}-rotate`,
password: process.env.WS_PASS,
},
});
const page = await browser.newPage();
await page.goto("https://httpbin.org/ip");
console.log(await page.textContent("body"));
await browser.close();Node.js: one proxy per context
Each context is an isolated browser profile with its own cookies. Giving each its own Webshare session keeps cookies and IP together:
const browser = await chromium.launch();
async function newSession() {
const sid = Math.floor(Math.random() * 1e6);
return browser.newContext({
proxy: { server: "http://p.webshare.io:80", username: `${user}-${sid}`, password: pw },
});
}
const ctx = await newSession();
const page = await ctx.newPage();Older Playwright versions required a placeholder proxy at launch for per-context proxies on Chromium; current versions don't.
Python
from playwright.sync_api import sync_playwright
with sync_playwright() as p:
browser = p.chromium.launch(proxy={
"server": "http://PROXY_IP:PORT",
"username": "USERNAME",
"password": "PASSWORD",
})
page = browser.new_page()
page.goto("https://httpbin.org/ip")
print(page.text_content("body"))
browser.close()This example uses a direct proxy from your list. Swap in the backbone host and a rotate or session username to let Webshare choose the IP.
Choosing rotate, session or a fixed IP
| Task | Proxy setup |
|---|---|
| Scrape many independent pages | New context per page or batch, each with a new session number |
| Log in and perform actions | One session (or one fixed static IP) per context |
| Long-lived accounts | Dedicated static residential IP per account |
| Lenient sites at volume | Datacenter IPs from a direct list, one per context |
Avoid the plain rotate option inside a single page load; dozens of sub-requests on different IPs can look odd and break sessions. See Webshare sticky sessions.
Saving bandwidth
await page.route("**/*", (route) => {
const t = route.request().resourceType();
return ["image", "media", "font"].includes(t) ? route.abort() : route.continue();
});On residential plans billed per GB, this is the single biggest saving.
Budget tip: You can test most of this guide for free: Webshare gives every new account 10 datacenter proxies and 1 GB of bandwidth a month without a credit card. Move to a paid plan once the pilot works. See our complete Webshare guide.
Matching the rest of the fingerprint
Set locale, timezoneId and, where relevant, geolocation on the context to match the proxy's country. A US IP with a browser set to another timezone is an easy signal for bot protection. See browser fingerprinting and proxies.
Common errors
net::ERR_PROXY_CONNECTION_FAILED: wrong host or port; test with cURL.- 407 or blank pages: wrong credentials, or a direct-mode username used on the backbone.
- Timeouts at scale: too many concurrent contexts for your plan's threads. See Webshare bandwidth and threads.
Running many markets in parallel
const markets = [
{ cc: "us", locale: "en-US", tz: "America/New_York" },
{ cc: "de", locale: "de-DE", tz: "Europe/Berlin" },
{ cc: "jp", locale: "ja-JP", tz: "Asia/Tokyo" },
];
await Promise.all(markets.map(async (m) => {
const ctx = await browser.newContext({
proxy: { server: "http://p.webshare.io:80", username: targetingUser(m.cc), password: pw },
locale: m.locale,
timezoneId: m.tz,
});
const page = await ctx.newPage();
await page.goto("https://www.example.com/");
await page.screenshot({ path: `home-${m.cc}.png` });
await ctx.close();
}));targetingUser() builds the country-targeted username from your dashboard's format.
Tracing failures
Playwright's tracing records network, console and screenshots. Turn it on for failed runs only, so you can see whether a failure came from the proxy (connection errors), the target (challenge pages) or your script.
Proxy tip: If your residential usage goes up and down, compare Geonode: its per-GB residential bandwidth doesn't expire, so you only pay for what you use. See using Geonode with Playwright.
Python async for scale
For larger jobs from Python, use async_playwright with a semaphore so you don't open more contexts than your Webshare plan's threads allow. Contexts are cheap; browsers aren't, so run a few browsers with many contexts.
Choosing the product
Lenient sites and QA can run on datacenter IPs per context. Protected sites need rotating residential with a session per context. Logged-in automation should use a dedicated static residential IP per account.
A real-world example
A localisation team runs a nightly Playwright suite against their website in 12 markets. Each market gets a browser context with a Webshare proxy in that country, plus matching locale and timezone. Most markets use datacenter IPs; two markets where the site's CDN treats datacenter traffic differently use residential sessions. The suite saves screenshots and asserts currency, language and consent banners, catching two regressions before release in its first month.
Before you commit to any provider, it helps to see the wider market: our guide to the best proxies in 2026 compares proxy types by job, and cheap proxies explains how to keep costs down without buying IPs that get blocked. For browser automation in depth, see our Puppeteer proxies guide.
Key takeaways
- Playwright takes proxy server, username and password as options, per browser or per context.
- Give each context its own session or fixed IP to keep cookies and IP together.
- Set locale and timezone per context to match the proxy's country.
- Block heavy resources with routes to save residential bandwidth.
- Browsers can't send SOCKS5 credentials; use HTTP with credentials or SOCKS5 with IP authorization.
FAQ
Does Playwright support SOCKS5 with Webshare?
Playwright supports SOCKS5 servers, but browser engines generally don't support SOCKS5 authentication, so use HTTP with credentials, or SOCKS5 with IP authorization.
Can each Playwright context have a different country?
Yes. Use a different targeting username for each context's proxy. See Webshare geo-targeting.
Is Playwright or Puppeteer better with Webshare?
Both work well. Playwright's per-context proxy options make multi-session setups simpler. See Webshare with Puppeteer.
Can Playwright use a different proxy per context?
Yes. Pass the proxy option to browser.newContext().
Does Playwright work with Webshare's backbone gateway?
Yes. Use the gateway as the server and put rotate, session or targeting options in the username.
Which browsers does this work with?
Playwright's Chromium, Firefox and WebKit all accept proxy settings, though behaviour can differ slightly between engines.
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.