Set up Playwright with ProxyField
- Check the login once with curl (section 1): if curl fails, Playwright fails too.
- Pass
proxy: { server, username, password }tochromium.launch()to send the whole browser through the gateway. - Or pass it to
browser.newContext()to give each context its own username and IP. - Open
https://api.ipify.org?format=jsonin a page to see the exit IP.
The whole-browser proxy in Playwright for Python, with a New York exit IP.
from playwright.sync_api import sync_playwright
with sync_playwright() as p:
browser = p.chromium.launch(proxy={
"server": "http://gate.proxyfield.io:7000",
"username": "<login>-country-us-city-new_york",
"password": "<password>",
})
page = browser.new_page()
page.goto("https://api.ipify.org")
print(page.inner_text("body"))
browser.close()Playwright's own guide to the proxy option: Network: HTTP Proxy (Playwright docs).
const us = await browser.newContext({ proxy: { server: 'http://gate.proxyfield.io:7000', username: '<login>-country-us', password: '<password>' } });
const de = await browser.newContext({ proxy: { server: 'http://gate.proxyfield.io:7000', username: '<login>-country-de-session-he9f2qga-ttl-600', password: '<password>' } });- On a budget: 1 GB of residential for $2.95 or 20 GB of rotating datacenter for $5.80; datacenter at $0.29/GB for sites that don't block server IPs, residential from $2.95/GB for 1 GB to $1.95/GB from 1,000 GB for most scraping; no minimum purchase (budget table).
- Cloudflare: a residential proxy fixes only the IP signal; Cloudflare also reads the browser fingerprint, TLS signature and behavior. Keep one context on one sticky IP per visit, slow down, stay on public pages and stop when the challenge repeats; challenge pages still cost traffic (section 10).
On this page 17 sections
A different authenticated proxy per browser context
Give each context its own proxy object with server, username and password. The username carries the country and the session, so two contexts in one browser leave through two different IPs:
// npm i playwright && npx playwright install chromium
const { chromium } = require('playwright');
(async () => {
const browser = await chromium.launch();
// Context 1: rotating, a new US IP on every request
const us = await browser.newContext({ proxy: {
server: 'http://gate.proxyfield.io:7000',
username: '<login>-country-us',
password: '<password>',
} });
// Context 2: one German IP held for 10 minutes (sticky session)
const de = await browser.newContext({ proxy: {
server: 'http://gate.proxyfield.io:7000',
username: '<login>-country-de-session-he9f2qga-ttl-600',
password: '<password>',
} });
for (const context of [us, de]) {
const page = await context.newPage();
await page.goto('https://ipinfo.io/json');
console.log(await page.textContent('body'));
}
await browser.close();
})();Read moreShow less
Expected output: two JSON objects with different IPs, the first with "country": "US", the second with "country": "DE" (ipinfo.io's fields, shortened):
{ "ip": "<US exit IP>", "country": "US", ... }
{ "ip": "<DE exit IP>", "country": "DE", ... }The same two contexts in Python (pip install playwright), with new_context(proxy=...):
from playwright.sync_api import sync_playwright
with sync_playwright() as p:
browser = p.chromium.launch()
for username in ("<login>-country-us", "<login>-country-de-session-he9f2qga-ttl-600"):
context = browser.new_context(proxy={"server": "http://gate.proxyfield.io:7000",
"username": username, "password": "<password>"})
page = context.new_page()
page.goto("https://ipinfo.io/json")
print(page.inner_text("body")) # one US object, then one DE object, with different IPs
context.close()
browser.close()The proxy object takes four fields (Playwright API reference): server (http://, https:// or socks5://; no scheme means HTTP), username, password and bypass, a comma-separated list of hosts that go direct, such as bypass: 'localhost,127.0.0.1,.internal.example.com'.
| Feature | Whole browser | One context |
|---|---|---|
Where proxy goes | chromium. (Python: launch(proxy=...)) | browser. (Python: new_context(proxy=...)) |
| What it affects | every context and page of that browser | the pages of that context only |
| Credentials | proxy.username, proxy.password | the same, per context |
| To change it | close and relaunch the browser | close the context and open a new one; the browser keeps running |
| Use it for | one exit for everything, quick scripts | a different country, session or account per context |
Why this is short with ProxyField: one host and port for HTTP, HTTPS and SOCKS5 (gate.proxyfield.io:7000), with the country, city and session in the username, so one proxy object per context is all the code you change; there is no list of proxy endpoints to manage.
Three rules from Playwright's network docs that this code follows:
- A proxy can be set for the whole browser or for each context. Every page in a context shares that context's proxy, so a different proxy per page means one context per page.
- Proxy credentials go in
proxy.usernameandproxy.password. The docs allow a username and password for an HTTP(S) proxy;httpCredentialsis for HTTP authentication on the website itself, not for the proxy. - A context's proxy is fixed when you create it. To change the proxy, close the context and open a new one; the browser keeps running.
In Playwright Test, create the contexts from the browser fixture:
import { test } from '@playwright/test';
test('two exit countries', async ({ browser }) => {
for (const cc of ['us', 'de']) {
const context = await browser.newContext({ proxy: {
server: 'http://gate.proxyfield.io:7000',
username: `<login>-country-${cc}`,
password: '<password>',
} });
const page = await context.newPage();
await page.goto('https://ipinfo.io/json');
console.log(cc, await page.textContent('body'));
await context.close();
}
});Replace <login> and <password> with the credentials from your dashboard. Access opens once the payment is confirmed. The Python version is in section 3.
The code uses Playwright's stable proxy option.
Connection settings
| Setting | Value |
|---|---|
server | http:// (HTTP, HTTPS and SOCKS5 on the same host and port) |
username | <login>, plus optional targeting: -country-us, -region-new_york, -city-new_york, -session-<id>-ttl-<seconds> |
password | your password from the dashboard |
| Authentication | username:password; with the IP allowlist, the port you set up in the dashboard |
| Rotation | a new IP on every request by default |
| Sticky sessions | 30 s to 36 h (ttl-30 to ttl-129600); 20 min when -session-<id> has no ttl; an IP idle for 120 s gets a new IP |
| Threads | unlimited concurrent threads |
| Residential, mobile or rotating datacenter | residential by default; add -mobile after the login for mobile IPs, as in <login>-mobile-country-us, or -dc for rotating datacenter, as in <login>-dc-country-us (country targeting only) |
| Credentials | your account dashboard; the configurator generates as many proxy lines as you need |
Best proxies for Playwright on a budget
The lowest-cost way in is 1 GB of residential for $2.95 or 20 GB of rotating datacenter for $5.80. The lowest price per GB is rotating datacenter at $0.29/GB; for most scraping, use residential at $2.95/GB for 1 GB down to $1.95/GB from 1,000 GB; and blocking images, fonts and media cuts the bytes per page (in the example below, a 10,000-page job drops from about 20 GB to about 5 GB; example inputs, not measurements). Pick the lowest-cost proxy type your target accepts, then cut the bytes each page loads. Free public proxy lists are not a budget option for Playwright: they are shared, often already flagged, and their operators can read unencrypted traffic.
Read moreShow less
| Target | Proxy type | ProxyField price | Why |
|---|---|---|---|
| Your own staging site, sites that don't block server IPs | Rotating datacenter | $0.29/GB (1-49 GB), $0.27 (50-249), $0.25 (250-999), $0.22 (1,000+) | The lowest price per GB |
| Most public-data scraping | Rotating residential | $2.95/GB (1-9 GB), $2.79 (10-49), $2.65 (50-99), $2.49 (100-249), $2.29 (250-499), $2.09 (500-999), $1.95 (1,000+) | Home ISP IPs, city targeting |
| Signed-in flows that keep one IP for weeks | Dedicated ISP | from $2.29 per IP for 30 days | One fixed IP per account |
| Targets that treat carrier IPs differently | Mobile 5G/4G | $3.45/GB (1 GB) down to $2.45/GB (1,000+ GB) | Carrier IPs, same balance as residential |
No minimum purchase: the smallest payment for traffic is $2.95, the price of the Easy Trial. Many providers make you buy 2 GB or more to start; with ProxyField you can buy just 1 GB, on the same pool as a 1 TB order. The tier rate applies to the whole purchase, there is no subscription, and residential, mobile and datacenter traffic never expires.
What a budget buys (the tier rate applies to the whole purchase):
| Budget | Residential | Datacenter |
|---|---|---|
| $2.95, just testing your Playwright code | 1 GB at $2.95 (the Easy Trial): about 2,000 pages at 0.5 MB with images blocked | – |
| $5.90 | 2 GB at $2.95 | 20 GB at $0.29 ($5.80) |
| $50.22 | 18 GB at $2.79 | 186 GB at $0.27 |
| $132.50 | 50 GB at $2.65 | 530 GB at $0.25 |
The lowest-cost order to try: rotating datacenter ($0.29/GB) first; residential when pages come back blocked; a sticky residential session or a dedicated ISP IP (from $2.29 per IP per 30 days) only for signed-in flows; mobile ($3.45/GB for 1 GB) only when residential is treated differently from carrier IPs.
What a Playwright scrape costs (example inputs, not measurements; your dashboard shows real usage):
| Job | Traffic | Datacenter | Residential | Mobile |
|---|---|---|---|---|
| 10,000 pages, full load at about 2 MB each | about 20 GB | 20 × $0.29 = $5.80 | 20 × $2.79 = $55.80 | 20 × $3.29 = $65.80 |
| The same 10,000 pages with images, fonts and media blocked, about 0.5 MB each | about 5 GB | 5 × $0.29 = $1.45 | 5 × $2.95 = $14.75 | 5 × $3.45 = $17.25 |
Datacenter costs least only where the target serves server IPs normally; test it with a small purchase first and move to residential if pages come back blocked. To see which type an exit IP is, look it up on https://ipinfo.io/json: its org field names the network that owns the IP. The blocking code is in section 8.
1. Check your credentials with cURL first (30 seconds)
Run one cURL command before you write any Playwright code: if it fails, Playwright will fail too.
# Any exit IP
curl -x http://gate.proxyfield.io:7000 -U "<login>:<password>" https://api.ipify.org
# An exit IP in New York, United States
curl -x http://gate.proxyfield.io:7000 -U "<login>-country-us-city-new_york:<password>" https://api.ipify.orgYou should see an IP that is not yours. Check its country with https://ipinfo.io/json, or test your proxy in the ProxyField proxy checker (up to 100 proxies per check; your list and results are not stored). More flags and SOCKS5 examples: test the proxy with cURL.
2. Set a proxy for the whole browser (Node.js)
Set proxy in chromium.launch(), and every context and page of that browser goes through it.
const { chromium } = require('playwright');
(async () => {
const browser = await chromium.launch({
proxy: {
server: 'http://gate.proxyfield.io:7000',
username: '<login>-country-us',
password: '<password>',
},
});
const page = await browser.newPage();
await page.goto('https://api.ipify.org?format=json');
console.log(await page.textContent('body')); // {"ip":"<exit IP>"}
await browser.close();
})();Notes:
- Playwright takes the username and password as separate fields, so special characters in the password need no URL-encoding. Don't put
user:pass@insideserver. - A
serverwithout a scheme, such asgate.proxyfield.io:7000, is read as an HTTP proxy. - To send some hosts direct, add
bypass: 'localhost,.internal.example'to theproxyobject. firefox.launch()andwebkit.launch()take the sameproxyoption.
3. Playwright proxy in Python (sync and async)
The Python API takes the same settings as a dict: proxy= on launch() for the whole browser, or on new_context() for one context. For proxies in plain Python scripts, see Python proxy setup.
# pip install playwright && playwright install chromium
from playwright.sync_api import sync_playwright
PROXY = {
"server": "http://gate.proxyfield.io:7000",
"username": "<login>-country-us",
"password": "<password>",
}
with sync_playwright() as p:
browser = p.chromium.launch(proxy=PROXY)
page = browser.new_page()
page.goto("https://api.ipify.org?format=json")
print(page.inner_text("body"))
browser.close()This async version gives each context its own country and prints the exit IP and country of each:
import asyncio
from playwright.async_api import async_playwright
def proxy_for(username):
return {"server": "http://gate.proxyfield.io:7000", "username": username, "password": "<password>"}
async def main():
async with async_playwright() as p:
browser = await p.chromium.launch()
for username in ("<login>-country-us", "<login>-country-de-session-he9f2qga-ttl-600"):
context = await browser.new_context(proxy=proxy_for(username))
page = await context.new_page()
await page.goto("https://ipinfo.io/json")
print(username, await page.inner_text("body"))
await context.close()
await browser.close()
asyncio.run(main())4. A different proxy per browser context: details
Each context has its own proxy, cookies and storage, and one browser process can run many contexts at once, which is lighter than launching one browser per proxy. Set locale and timezoneId to match the exit country, so the page's language and clock agree with its IP:
await browser.newContext({ proxy: proxyFor('us'), locale: 'en-US', timezoneId: 'America/New_York' });
await browser.newContext({ proxy: proxyFor('de'), locale: 'de-DE', timezoneId: 'Europe/Berlin' });Older Playwright versions needed a launch-level proxy before contexts could set their own (Chromium on Windows threw Browser needs to be launched with the global proxy). If you see that error, update Playwright, or launch with proxy: { server: 'http://per-context' } and keep the per-context settings.
5. Country, city and sticky sessions
Targeting goes in the username. ProxyField targets by country, region (state) and city, covers all 50 US states, and charges the same price per GB for every targeting. Names are lowercase with underscores.
| Goal | Username |
|---|---|
| Any exit IP | <login> |
| United States | <login>-country-us |
| A US state | <login>-country-us-region-new_ |
| New York, United States | <login>-country-us-city-new_ |
| Germany | <login>-country-de |
| A sticky session of 10 minutes | <login>-country-us-session-he9f2qga-ttl-600 |
| A sticky session of 36 hours (the maximum) | <login>-country-us-session-he9f2qga-ttl-129600 |
A sticky IP ends when its ttl runs out, after 120 s without traffic, or when its exit node drops: the gateway then retries once with a new session, so the IP may change, and an established connection that breaks is not restored. The carrier is not a targeting option. All parameters: targeting docs.
6. Rotating proxies in Playwright
You don't rotate proxies in Playwright code: the gateway gives a new IP on every request, or keeps one IP for a sticky session of 30 s to 36 h.
- Sticky session per context for logged-in flows, multi-step forms and any sequence of pages that must come from one IP.
- Rotation for independent page fetches, such as one product page or one search result per job.
const { chromium } = require('playwright');
const jobs = ['https://api.ipify.org?format=json', 'https://api.ipify.org?format=json', 'https://api.ipify.org?format=json'];
(async () => {
const browser = await chromium.launch();
for (const url of jobs) {
// One context per job: fresh cookies, fresh connection, new exit IP.
const context = await browser.newContext({
proxy: { server: 'http://gate.proxyfield.io:7000', username: '<login>-country-us', password: '<password>' },
});
const page = await context.newPage();
await page.goto(url);
console.log(await page.textContent('body'));
await context.close();
}
await browser.close();
})();Browsers keep their connections to the proxy open and reuse them, so requests inside one page load can leave through the same IP. Open a new context when a task needs a new IP. More on both modes: rotating proxies with sticky sessions.
7. SOCKS5 in Playwright
Playwright connects to SOCKS5 proxies with a socks5:// server, but Chromium does not send a username and password to a SOCKS5 proxy: it stops at launch with Browser does not support socks5 proxy authentication. So for SOCKS5 in Chromium, add your own IP to the allowlist in the dashboard, leave the credentials out and connect to socks5://gate.proxyfield.io:<port>, where <port> is the port you set up in the dashboard; or stay on HTTP, http://gate.proxyfield.io:7000 with your username and password, which also carries HTTPS sites.
const { chromium } = require('playwright');
(async () => {
// Allowlist your own IP in the dashboard first: no username or password here.
// <port> is the port you set up in the dashboard for your allowlisted IP.
const browser = await chromium.launch({ proxy: { server: 'socks5://gate.proxyfield.io:<port>' } });
const page = await browser.newPage();
await page.goto('https://api.ipify.org?format=json');
console.log(await page.textContent('body'));
await browser.close();
})();With allowlisted access there is no username to carry targeting: with the allowlist, the product, location and session are set per port in the dashboard.
8. Cut traffic: block images, fonts and media
You pay per GB, so every image, font and video a page loads through the proxy uses your balance. Block them with context.route(), and the same pages cost fewer GB.
const { chromium } = require('playwright');
const BLOCKED = new Set(['image', 'font', 'media']);
(async () => {
const browser = await chromium.launch({
proxy: { server: 'http://gate.proxyfield.io:7000', username: '<login>-country-us', password: '<password>' },
});
const context = await browser.newContext();
// 1. Abort images, fonts and media before they reach the proxy.
await context.route('**/*', (route) =>
BLOCKED.has(route.request().resourceType()) ? route.abort() : route.continue()
);
// 2. Add up the bytes of every finished request.
const sizes = [];
context.on('requestfinished', (request) => sizes.push(request.sizes()));
const page = await context.newPage();
await page.goto('https://example.com', { waitUntil: 'networkidle' });
let bytes = 0;
for (const s of await Promise.all(sizes)) {
bytes += s.requestHeadersSize + s.requestBodySize + s.responseHeadersSize + s.responseBodySize;
}
console.log(`${(bytes / 1024).toFixed(1)} KB through the proxy`);
await browser.close();
})();Keep scripts and stylesheets: most pages need them to render. request.sizes() counts headers and bodies as the browser sees them and leaves out connection overhead, so treat the total as an estimate. Your dashboard shows real-time usage and the gigabytes you have left.
9. Headers, user agent and stealth
Set headers for a whole context with extraHTTPHeaders and userAgent in browser.newContext(), next to its proxy, and keep Accept-Language, locale and timezoneId in line with the exit country (scraping headers guide). The ProxyField gateway adds no Via, X-Forwarded-For or Forwarded header, passes your own headers through, and removes Proxy-Authorization before the request reaches the site.
Three projects add stealth on top of Playwright, and all three take the same proxy settings:
- playwright-extra is a Node.js wrapper that brings puppeteer-extra plugins, including the stealth plugin, to Playwright. Its last release, 4.3.6, dates from March 2023.
- playwright-stealth is a Python port of the stealth evasions. Version 2.0.3 came out in April 2026.
- Camoufox is a Firefox-based anti-detect browser with a Playwright-style Python API. It accepts the same
proxydict, and withgeoip=Trueit matches its locale and timezone to the proxy's exit IP. Version 0.5.8 came out in October 2026.
More options: Puppeteer alternatives. For browser profiles managed in a desktop app: proxies for antidetect browsers.
10. How do I get past Cloudflare when scraping with Playwright and residential proxies?
A residential proxy fixes only the IP signal: Cloudflare also reads the browser's fingerprint, TLS signature and behavior, and no proxy solves a challenge. So on public pages, within the site's terms, run one context on one sticky residential IP per visit with a matching locale and time zone, go slowly, and stop when the challenge repeats:
const context = await browser.newContext({
proxy: { server: 'http://gate.proxyfield.io:7000', username: '<login>-country-us-session-cf1-ttl-1800', password: '<password>' },
locale: 'en-US',
timezoneId: 'America/New_York',
});Read moreShow less
Challenge pages still cost traffic. Every "Just a moment..." page and every 403 or 429 the browser downloads counts as GB: at $2.79/GB (the 10–49 GB rate), a run that mostly gets challenge pages spends balance on nothing. Stop early, and block images, fonts and media (section 8) so failed loads cost less.
The checks, in order:
- Check that you may collect it. Public pages only; follow the site's terms and
robots.txt. If you need more than public pages at a gentle rate, use the site's API or ask the owner for access. - Name what fired. A plain
403or429with no page usually means a firewall rule or a rate limit; a full-page interstitial titled "Just a moment..." is a challenge; an embedded widget is Turnstile. On Cloudflare's side these come from Bot Fight Mode (free plans), Super Bot Fight Mode (Pro, Business and Enterprise), Bot Management (Enterprise, a bot score on every request), WAF custom rules and rate limiting (Cloudflare bot solutions). - Keep one IP per session. Use one context with one sticky session (
<login>-country-us-session-<id>-ttl-1800) for a whole visit. Cloudflare keeps a passed challenge in thecf_clearancecookie, and a new IP or a new context can bring a new challenge. - Match the browser to the IP. Set
localeandtimezoneIdto the exit country (section 4), and use a real browser channel rather than a stripped-down build. - Slow down. Fewer parallel contexts per site, pauses between pages, and only the pages you need (section 8).
- Stop when the challenge repeats. A challenge that comes back on every page means the rule is about the browser or the behavior, not the IP; more IPs will not change it.
| What you get | What it usually means | Next step |
|---|---|---|
403 or 429 with no page | a firewall rule or a rate limit | slow down; check that the page is public and allowed |
| A full page titled "Just a moment..." | a challenge on this visit (Cloudflare's interstitial challenge pages: "The visitor cannot reach their destination without passing the challenge") | keep one context on one sticky IP; stop if it returns on every page |
| An embedded Turnstile widget | the site asks for a check at this step | do not automate past it; use the site's API or ask the owner |
If you own the Cloudflare-protected site, don't fight your own bot rules: add a WAF custom rule with the Skip action for your test runner's IP, and in staging use Turnstile's test sitekeys: 1x00000000000000000000AA always passes, 2x00000000000000000000AB always fails, 3x00000000000000000000FF forces an interactive challenge. Cloudflare's testing page says automated suites such as Playwright "are detected as bots by Turnstile", which is why the test keys exist. What a challenge is, in Cloudflare's words: security mechanisms "to verify whether a visitor to your site is a real human" (Cloudflare challenges).
Step-by-step checks for the error page: Cloudflare 403 Forbidden. Why it happens: why Cloudflare thinks you're a bot.
11. Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
net:: | Wrong host or port, or a firewall blocks port 7000, or the port you set up in the dashboard for the allowlist | Use http:// with your username and password (with the allowlist, the port you set up in the dashboard) and run the cURL check from section 1. |
| Every page fails or times out right after launch, while the cURL check also fails | Wrong or missing username or password, or your current IP is not on the allowlist | Copy the credentials from the dashboard again, or add your IP to the allowlist. |
net:: | The proxy could not open a tunnel to the site: the site is down or refused the connection | Check the site without the proxy. Some site categories are restricted to protect the network, including financial and government services. |
Browser does not support socks5 proxy authentication | username and password set with a socks5:// server in Chromium | Use the allowlist without credentials, or switch to http://. |
| Wrong country | A misspelled username parameter, or a reused keep-alive connection | Check the username against the table in section 5, and open a new context. |
| Your own IP shows up | The page runs in a context without a proxy, or the host is on the bypass list | Set proxy on the browser or on that context, and check bypass. |
| The sticky IP changed mid-session | ttl ran out, 120 s passed without traffic, or the exit node dropped | Raise ttl, keep the session busy, and reconnect after a broken connection. |
| Timeouts on heavy pages | Large pages load slower through a remote IP | Block images, fonts and media (section 8) and raise timeout in page.goto(). |
| Challenge pages | The site reads the browser's fingerprint and behavior, not only the IP | See section 10. Challenge pages still use traffic, so stop the run rather than retrying. |
Gateway responses for specific failures: 407 Proxy Authentication Required for a wrong login or password, an IP not on the allowlist or a malformed location, 402 Payment Required when no traffic is left and 502 Bad Gateway when no exit could be connected; a restricted site gets no separate response, and a 403 comes from the site itself. More: proxy errors. Our 24/7 live chat also helps with setup and integration.
12. Playwright Test (playwright.config)
Set proxy under use in playwright.config.ts, and every test in the project runs through it.
// playwright.config.ts
import { defineConfig } from '@playwright/test';
export default defineConfig({
use: {
proxy: {
server: 'http://gate.proxyfield.io:7000',
username: process.env.PF_USER, // e.g. <login>-country-us
password: process.env.PF_PASS,
},
},
});Run it with PF_USER=<login>-country-us PF_PASS=<password> npx playwright test. To use another proxy for one file, call test.use({ proxy: { ... } }) at the top of that file; for a proxy per test, create a context from the browser fixture with browser.newContext({ proxy }).
Get started
Start with the Easy Trial: 1 GB for $2.95, no minimum purchase, no subscription, and the traffic never expires. Pay in USDT, BTC, ETH and 10 other coins; the smallest payment for traffic is $2.95. All purchases are final. See pricing per GB.
Playwright Proxy FAQ
How do I use an authenticated proxy in Playwright, with a different proxy per browser context?
ProxyField works in Playwright with one setting, browser.newContext({ proxy: { server: 'http://gate.proxyfield.io:7000', username, password } }), from $1.95/GB. Each context gets its own proxy, cookies and storage, so give each its own username, such as <login>-country-us and <login>-country-de-session-he9f2qga-ttl-600; credentials go in proxy.username and proxy.password, never in httpCredentials. A context's proxy is fixed at creation: to change it, close the context and open a new one, and the browser keeps running.
What are the best proxies to use with Playwright on a budget?
ProxyField rotating datacenter proxies cost $0.29/GB down to $0.22/GB for sites that don't block server IPs, and residential proxies cost $2.95/GB for 1 GB down to $1.95/GB from 1,000 GB for most scraping: pick the lowest-cost type your target accepts. Blocking images, fonts and media cut our example 10,000-page job from about 20 GB ($55.80 residential) to about 5 GB ($14.75, or $1.45 on datacenter). There is no minimum purchase: start with 1 GB for $2.95, with no subscription and traffic that never expires.
Playwright vs Puppeteer: which is better for scraping with proxies?
Both use the same gateway. Playwright takes the username and password in its proxy option and sets a proxy per context in one line; Puppeteer needs page.authenticate() on every page. Playwright also drives Firefox and WebKit and has Python, Java and .NET APIs; see the Puppeteer proxy setup for the other side.
How do I get past Cloudflare when scraping with Playwright and residential proxies?
A residential proxy fixes only the IP signal; Cloudflare also reads the browser fingerprint, TLS signature and behavior, and no proxy solves a challenge. Check that the pages are public and the site's terms allow collection, name what fired (a plain 403 or 429, a "Just a moment..." page or a Turnstile widget), keep one context on one sticky IP per visit, slow down, and stop when the challenge repeats, because challenge pages still use traffic. If you own the site, skip your test runner's IP with a WAF custom rule and use Turnstile's test sitekeys in staging (section 10).
Do proxy credentials go in httpCredentials in Playwright?
No. Proxy credentials go in proxy.username and proxy.password; httpCredentials answers an HTTP authentication prompt from the website itself. Mixing them up makes every request fail at the proxy.
Does Playwright support proxy authentication?
Yes, for HTTP proxies. Pass username and password in the proxy option of launch() or newContext(). For SOCKS5, Chromium sends no credentials, so use an IP allowlist instead.
How do I set a proxy in Playwright Python?
Pass a dict to launch or new_context: {"server": "http://gate.proxyfield.io:7000", "username": "<login>-country-us", "password": "<password>"}. The sync and async APIs take the same dict (section 3).
How do I rotate proxies in Playwright?
Let the gateway rotate: ProxyField gives a new IP on every request by default, or a sticky session from 30 s to 36 h, chosen in the username. Open one browser context per session or per job.
Should I use a rotating or sticky residential proxy with Playwright?
Sticky for logged-in flows, multi-step forms and anything that must come from one IP; rotating for independent page fetches. A sticky session holds one IP from 30 s to 36 h (20 min if you set no ttl), and an IP idle for 120 s is replaced.
Can Playwright use a different proxy per page or context?
Per context, not per page: every page in a context shares that context's proxy. When each page needs its own IP, open one context per page; contexts are cheap compared with launching a new browser.
Show 11 more questionsShow fewer questions
Can Playwright change the proxy without restarting the browser?
Yes. Close the context and open a new one with another proxy setting; the browser keeps running. Changing only the username, for example from <login>-country-us to <login>-country-de, switches the country.
Does Playwright support SOCKS5 proxies?
Yes, with a socks5:// server, but Chromium sends no credentials to a SOCKS5 proxy and stops with Browser does not support socks5 proxy authentication. Allowlist your IP and connect to gate.proxyfield.io on the port you set up in the dashboard, or stay on HTTP, which also carries HTTPS sites.
Can an HTTP proxy open HTTPS websites in Playwright?
Yes. For an HTTPS site the browser opens a CONNECT tunnel through the HTTP proxy, and TLS runs between the browser and the site; the ProxyField gateway does not decrypt it. Use http://gate.proxyfield.io:7000 for both kinds of site.
Does Playwright use the HTTP_PROXY and HTTPS_PROXY environment variables?
Don't rely on them for page traffic: set proxy in launch(), newContext() or playwright.config so every run uses the gateway on purpose. The variables do matter when npx playwright install downloads browsers behind a corporate proxy.
Where do I put the proxy in a Playwright Test config?
Under use.proxy in playwright.config.ts, with the username and password from environment variables (section 12). test.use({ proxy: { ... } }) at the top of a file gives that file its own proxy.
Can I target specific countries or cities with Playwright?
Yes, in the username: <login>-country-us for the United States, <login>-country-us-city-new_york for New York. ProxyField targets country, region (state) and city, with all 50 US states at the same price per GB, and each context can use a different location.
How do I verify that Playwright is using the proxy?
Open https://api.ipify.org?format=json in the page and compare the IP with your own; https://ipinfo.io/json also shows its country. Run the cURL check from section 1 first if the page doesn't load.
Which proxy type works best with Playwright?
Residential proxies suit most public-data scraping. Mobile 5G/4G proxies fit targets that treat carrier IPs differently, and residential and mobile share one balance. For targets that don't block datacenter IPs, rotating datacenter proxies cost less per GB.
What is playwright-extra?
playwright-extra is a Node.js wrapper that brings puppeteer-extra plugins, including stealth, to Playwright. Its last release, 4.3.6, dates from March 2023, and it uses Playwright's own proxy settings.
What is playwright-stealth?
playwright-stealth is a Python port of the stealth evasions that hides some automation signals. Version 2.0.3 came out in April 2026; the proxy still goes in Playwright's proxy option.
What proxy format does Playwright use?
A server URL with scheme, host and port, such as http://gate.proxyfield.io:7000, plus separate username and password fields. Don't put user:pass@ inside server; a server without a scheme is read as HTTP.