Playwright is one of the most powerful tools for browser automation, headless testing, and data scraping. However, without a properly configured proxy, your script will quickly get banned by IP: websites have learned to recognize automated requests and block them. In this guide, we will cover all the ways to connect a proxy in Playwright — from basic configuration to IP rotation and bypassing Cloudflare.
Why Use a Proxy in Playwright and When You Can't Do Without It
Playwright launches a real browser (Chromium, Firefox, or WebKit) in the background — this is what headless means. From the website's perspective, you appear as a regular user, but only up to a certain point. As soon as hundreds of requests per hour come from a single IP, the protection algorithms react instantly: CAPTCHA, temporary bans, complete bans.
Here are specific scenarios when a proxy is essential:
- Scraping Marketplaces — Wildberries, Ozon, Avito, Yandex.Market block scripts after just 50–100 requests from a single IP.
- Monitoring Competitor Prices — if you run checks every 15 minutes, without changing IPs, you will get banned within a few hours.
- Geolocation Testing — you need to check how the site looks for users from Germany, the USA, or Kazakhstan.
- Form Filling and Account Registration — platforms tie accounts to IPs and block mass registrations.
- SEO Monitoring — collecting positions from Google and Yandex requires constant IP changes; otherwise, the search engine will show CAPTCHA.
- A/B Testing Features — some features are only available to users from certain countries or regions.
It is important to understand: Playwright itself does not make you anonymous. Without a proxy, all requests come from your real IP address. Adding a proxy is the first and most important step toward the stable operation of any automated script.
💡 Important to Know
Playwright supports proxies at the browser level, individual context (BrowserContext), and even individual pages. This provides flexibility: different pages can operate through different IPs simultaneously.
Which Type of Proxy to Choose for Headless Automation
Not all proxies are equally suitable for Playwright. The choice depends on the task: what you are scraping, how aggressive the website's protection is, and what volume of requests you plan to make.
| Proxy Type | Trust Level | Speed | Suitable For |
|---|---|---|---|
| Datacenter | Low | Very High | Scraping without strict protection, testing |
| Residential | High | Medium | Websites with Cloudflare, marketplaces, social networks |
| Mobile | Maximum | Medium | Facebook, TikTok, Instagram, strict anti-bots |
| SOCKS5 | Depends on the source | High | Universal protocol, supported by Playwright |
For most scraping tasks, the optimal choice is residential proxies with rotation. They have real IPs of home users, so websites do not identify them as datacenter and do not block them automatically. For websites with aggressive protection (Cloudflare Bot Management, Akamai), it is better to use mobile proxies — their IPs belong to mobile operators, which generates maximum trust.
Playwright supports the protocols http, https, and socks5. Important: SOCKS5 does not support authentication via username:password directly in some versions — more on this in the errors section.
Basic Proxy Setup in Playwright (JavaScript and Python)
Playwright allows you to set a proxy when launching the browser using the proxy parameter. This is the simplest way — all browser requests will go through the specified proxy server.
JavaScript / Node.js
const { chromium } = require('playwright');
(async () => {
const browser = await chromium.launch({
proxy: {
server: 'http://proxy.example.com:8080'
}
});
const page = await browser.newPage();
await page.goto('https://httpbin.org/ip');
const content = await page.textContent('body');
console.log(content); // will show the proxy server's IP
await browser.close();
})();
Python
from playwright.sync_api import sync_playwright
with sync_playwright() as p:
browser = p.chromium.launch(
proxy={
"server": "http://proxy.example.com:8080"
}
)
page = browser.new_page()
page.goto("https://httpbin.org/ip")
print(page.text_content("body")) # will show the proxy's IP
browser.close()
For SOCKS5, simply change the scheme in the server address:
# Python — SOCKS5 proxy
browser = p.chromium.launch(
proxy={
"server": "socks5://proxy.example.com:1080"
}
)
To quickly check that the proxy is working, open https://httpbin.org/ip or https://api.ipify.org — the response should show the proxy server's IP, not your real one.
Proxy with Username and Password Authentication
Most commercial proxy providers use username and password authentication — this is standard practice. Playwright supports it through the username and password fields in the proxy object.
JavaScript
const browser = await chromium.launch({
proxy: {
server: 'http://gate.proxyprovider.com:7777',
username: 'your_login',
password: 'your_password'
}
});
Python
browser = p.chromium.launch(
proxy={
"server": "http://gate.proxyprovider.com:7777",
"username": "your_login",
"password": "your_password"
}
)
You can also pass the username and password directly in the proxy server URL — this is convenient if you are dynamically forming the string:
# Authentication in URL (Python)
proxy_url = f"http://{login}:{password}@gate.proxyprovider.com:7777"
browser = p.chromium.launch(
proxy={"server": proxy_url}
)
⚠️ Attention
Do not store the proxy username and password directly in the code! Use environment variables (os.environ in Python or process.env in Node.js) or a .env file with the dotenv library.
Secure Storage via .env (Python)
import os
from dotenv import load_dotenv
from playwright.sync_api import sync_playwright
load_dotenv()
PROXY_SERVER = os.getenv("PROXY_SERVER")
PROXY_LOGIN = os.getenv("PROXY_LOGIN")
PROXY_PASSWORD = os.getenv("PROXY_PASSWORD")
with sync_playwright() as p:
browser = p.chromium.launch(
proxy={
"server": PROXY_SERVER,
"username": PROXY_LOGIN,
"password": PROXY_PASSWORD
}
)
# ...
Proxy Rotation: Changing IP for Each Request
One proxy will not save you from bans with a high volume of requests. For serious scraping, IP rotation is needed — automatically changing the proxy server at certain intervals or for each new request.
There are two approaches to rotation in Playwright:
Approach 1: Rotating Proxy Endpoint
Most residential proxy providers offer a single gateway address that automatically changes IP with each connection. You do not need to write rotation logic — it is built-in on the provider's side.
# One endpoint — new IP with each browser connection
browser = p.chromium.launch(
proxy={
"server": "http://rotating.proxyprovider.com:8888",
"username": "your_login",
"password": "your_password"
}
)
Approach 2: Manual Rotation via Proxy List
If you have a list of static proxies, you can implement rotation manually — creating a new browser or context for each iteration:
import random
from playwright.sync_api import sync_playwright
PROXY_LIST = [
{"server": "http://proxy1.example.com:8080", "username": "user", "password": "pass"},
{"server": "http://proxy2.example.com:8080", "username": "user", "password": "pass"},
{"server": "http://proxy3.example.com:8080", "username": "user", "password": "pass"},
]
URLS_TO_SCRAPE = [
"https://example.com/page1",
"https://example.com/page2",
"https://example.com/page3",
]
with sync_playwright() as p:
for url in URLS_TO_SCRAPE:
proxy = random.choice(PROXY_LIST) # random proxy
browser = p.chromium.launch(proxy=proxy)
page = browser.new_page()
page.goto(url)
# ... scraping data ...
browser.close() # close the browser, change IP
Approach 3: Rotation via BrowserContext (without restarting the browser)
with sync_playwright() as p:
browser = p.chromium.launch() # browser without proxy
for i, url in enumerate(URLS_TO_SCRAPE):
proxy = PROXY_LIST[i % len(PROXY_LIST)] # round-robin
# New context with new proxy — faster than restarting the browser
context = browser.new_context(proxy=proxy)
page = context.new_page()
page.goto(url)
# ... scraping ...
context.close() # close the context, not the browser
browser.close()
The third approach is the most efficient for mass scraping. Restarting the browser takes 2–4 seconds, while creating a new context takes less than 100 milliseconds.
Proxy at the Context and Page Level
Playwright supports a flexible architecture: one browser can have multiple isolated contexts, each with its own proxy. This allows for parallel operation with multiple IPs within a single process.
Multiple Contexts with Different Proxies (Parallel Scraping)
const { chromium } = require('playwright');
(async () => {
const browser = await chromium.launch();
// Context 1 — proxy from Germany
const context_de = await browser.newContext({
proxy: {
server: 'http://de-proxy.example.com:8080',
username: 'user',
password: 'pass'
}
});
// Context 2 — proxy from the USA
const context_us = await browser.newContext({
proxy: {
server: 'http://us-proxy.example.com:8080',
username: 'user',
password: 'pass'
}
});
const page_de = await context_de.newPage();
const page_us = await context_us.newPage();
// Parallel execution
await Promise.all([
page_de.goto('https://example.com'),
page_us.goto('https://example.com')
]);
// Both pages see different IPs
console.log('DE IP:', await page_de.textContent('body'));
console.log('US IP:', await page_us.textContent('body'));
await browser.close();
})();
This approach is perfect for geolocation testing: you can simultaneously check how the site appears to users from different countries without launching multiple browser instances.
💡 Performance Tip
For maximum parallelism, use asyncio in Python or Promise.all in Node.js. One browser can maintain 10–20 parallel contexts without significant memory load.
Bypassing Anti-Bot Protection: Cloudflare, Akamai, DataDome
Proxies are only part of the solution. Modern anti-bot systems analyze dozens of signals simultaneously: browser fingerprinting, mouse behavior, form filling speed, HTTP headers, and much more. Even with a good proxy, you can still get blocked if these factors are not taken into account.
1. Masking Headless Mode
Playwright in headless mode has distinctive features that can be easily identified: specific values for navigator.webdriver, absence of plugins, non-standard screen sizes. Use the playwright-stealth library for masking:
# Python: installation
# pip install playwright-stealth
from playwright.sync_api import sync_playwright
from playwright_stealth import stealth_sync
with sync_playwright() as p:
browser = p.chromium.launch(
proxy={
"server": "http://residential.proxyprovider.com:8888",
"username": "user",
"password": "pass"
}
)
page = browser.new_page()
stealth_sync(page) # apply masking
page.goto("https://bot.sannysoft.com") # test for bot detection
browser.close()
2. Realistic User-Agent and Viewport
context = browser.new_context(
proxy={
"server": "http://proxy.example.com:8080",
"username": "user",
"password": "pass"
},
user_agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
viewport={"width": 1920, "height": 1080},
locale="ru-RU",
timezone_id="Europe/Moscow" # must match the proxy's geolocation!
)
3. Simulating Human Behavior
import time
import random
# Random delays between actions
def human_delay(min_ms=500, max_ms=2000):
time.sleep(random.randint(min_ms, max_ms) / 1000)
page.goto("https://example.com")
human_delay()
# Smooth scrolling instead of instant
page.evaluate("window.scrollBy({top: 500, behavior: 'smooth'})")
human_delay(300, 800)
# Mouse movement before clicking
page.mouse.move(100, 200)
human_delay(100, 300)
page.mouse.move(300, 400)
human_delay(100, 200)
page.click("button#submit")
4. Matching Timezone with Proxy Geolocation
This is often overlooked, but anti-bot systems check for consistency: if your proxy is from Moscow, but the browser shows a timezone of UTC-8 (Los Angeles) — this is a red flag. Always set timezone_id according to the geolocation of the proxy being used.
Common Errors and How to Fix Them
When working with proxies in Playwright, developers regularly encounter the same issues. Let's break down each one with a specific solution.
Error 1: ERR_PROXY_CONNECTION_FAILED
Reason: Incorrect proxy address or port, proxy unavailable, incorrect credentials.
Solution: Check the proxy availability via curl before launching Playwright:
# Checking proxy via curl
curl -x http://user:[email protected]:8080 https://api.ipify.org
Error 2: SOCKS5 Does Not Accept Authentication
Reason: Playwright (Chromium) has limited support for SOCKS5 with authentication via username/password.
Solution: Use HTTP proxies with authentication or set up a local SOCKS5 tunnel via ssh -D without a password.
Error 3: Proxy Works, but Site Still Blocks
Reason: Datacenter proxies are being used, which are blacklisted; headless mode is not masked; request frequency is too high.
Solution: Switch to residential or mobile proxies, add playwright-stealth, increase delays between requests.
Error 4: Real IP Leak (DNS leak)
Reason: DNS requests may bypass the proxy.
Solution: Playwright by default routes DNS through the proxy when using HTTP proxies. But for verification, use https://dnsleaktest.com in the headless browser.
Error 5: Slow Performance with Proxy
Reason: Residential proxies are slower than datacenter ones; long distance to the proxy server.
Solution: Choose proxies in geographically close locations. For tasks without strict anonymity requirements, use datacenter proxies — they are significantly faster.
| Error | Quick Fix |
|---|---|
| ERR_PROXY_CONNECTION_FAILED | Check curl, login/password, port availability |
| 407 Proxy Auth Required | Add username and password to the proxy config |
| Site Shows CAPTCHA | Change proxy type to residential, add stealth |
| IP Does Not Change on Rotation | Close context/browser between requests |
| Connection Timeout | Increase timeout in goto(), choose a closer proxy |
Conclusion and Recommendations
Setting up a proxy in Playwright is not a one-time task, but part of the architecture of your automation tool. A properly selected type of proxy, smart IP rotation, and masking headless mode together provide stable operation even on websites with aggressive anti-bot protection.
Let's summarize the choice of proxy type for specific tasks:
- Scraping Open Data without Strict Protection — fast datacenter proxies will suffice.
- Marketplaces (Wildberries, Ozon), News Aggregators — residential proxies with rotation are needed.
- Social Networks (Instagram, Facebook, TikTok) and Websites with Cloudflare — only mobile or residential proxies.
- Geolocation Testing — any type of proxy in the required country, the main thing is matching the timezone.
- Mass Scraping with High Frequency — rotating residential proxies with a gateway endpoint.
If you are building a scraping or automated testing system on Playwright and need stable operation without blocks, we recommend considering residential proxies — they provide a high level of trust from websites and support IP rotation through a single endpoint, simplifying integration with Playwright to just a few lines of code.