Headless browsers render JavaScript, so they handle modern sites that plain HTTP clients cannot. But a browser still ships every request from one IP, and automation gets caught the moment a site rate-limits or fingerprints that address. Using proxies with Playwright and Puppeteer spreads traffic across IPs and, done right, makes your automation look like ordinary users. Here is the working setup for both, in Python and Node.
Set the proxy at browser launch. Pass authentication as separate username and password fields — do not inline credentials in the server URL:
from playwright.sync_api import sync_playwright
PROXY = {
"server": "http://gate.jibaoproxy.com:10001",
"username": "USERNAME",
"password": "PASSWORD",
}
with sync_playwright() as p:
browser = p.chromium.launch(proxy=PROXY, headless=True)
page = browser.new_page()
page.goto("https://httpbin.org/ip")
print(page.inner_text("body"))
browser.close()
JIBAO exposes both HTTP and SOCKS5 on the gateway. Use the HTTP endpoint for browser automation: Playwright and Puppeteer do not support authenticated SOCKS5 proxies, so HTTP-with-auth is the reliable choice.
const { chromium } = require('playwright');
(async () => {
const browser = await chromium.launch({
headless: true,
proxy: {
server: 'http://gate.jibaoproxy.com:10001',
username: 'USERNAME',
password: 'PASSWORD',
},
});
const page = await browser.newPage();
await page.goto('https://httpbin.org/ip');
console.log(await page.innerText('body'));
await browser.close();
})();
The cleanest way to rotate in Playwright is one IP per BrowserContext. Each context is an isolated session (its own cookies and cache), so binding each to a different exit IP gives you parallel identities from a single browser process:
from playwright.sync_api import sync_playwright
def ctx_proxy(session_id):
return {
"server": "http://gate.jibaoproxy.com:10001",
"username": f"USERNAME-session-{session_id}",
"password": "PASSWORD",
}
with sync_playwright() as p:
browser = p.chromium.launch(headless=True)
for i in range(3):
context = browser.new_context(proxy=ctx_proxy(f"ctx{i}"))
page = context.new_page()
page.goto("https://httpbin.org/ip")
print(i, page.inner_text("body"))
context.close()
browser.close()
Each context uses a distinct sticky session token, so the IP stays stable inside a context (good for login flows) but differs across contexts (good for running many accounts in parallel). This is the pattern anti-detect browsers like GoLogin and Dolphin Anty automate — see our anti-detect proxy setup guide.
Puppeteer sets the proxy server as a Chromium launch flag, then authenticates on the page object:
const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch({
headless: 'new',
args: ['--proxy-server=http://gate.jibaoproxy.com:10001'],
});
const page = await browser.newPage();
await page.authenticate({ username: 'USERNAME', password: 'PASSWORD' });
await page.goto('https://httpbin.org/ip');
console.log(await page.evaluate(() => document.body.innerText));
await browser.close();
})();
Because the proxy is a process-level flag, a single Puppeteer browser uses one IP. To rotate, launch a fresh browser per identity (heavier) or drive rotation through a gateway that changes IPs per connection.
Any flow that creates a session cookie must keep the same IP for its whole life. A cookie minted on IP-A that suddenly appears from IP-B reads as session hijacking and triggers a re-auth or a ban. Keep one context (or one browser) per logged-in account, pinned to one sticky session token, for the entire session.
A residential IP is necessary but not sufficient. Sites also read your browser's TLS/JA4 handshake, HTTP/2 frame order, canvas, WebGL, and navigator properties. Vanilla headless Chromium leaks navigator.webdriver = true and a headless fingerprint that defeats the best IP. Mitigate with stealth plugins and realistic launch flags:
// Node: puppeteer-extra + stealth
const puppeteer = require('puppeteer-extra');
const Stealth = require('puppeteer-extra-plugin-stealth');
puppeteer.use(Stealth());
// Realistic launch flags
const browser = await puppeteer.launch({
headless: 'new',
args: [
'--proxy-server=http://gate.jibaoproxy.com:10001',
'--disable-blink-features=AutomationControlled',
'--window-size=1920,1080',
],
});
To see exactly which signals you are leaking, run your automated browser against JIBAO's free JA3/JA4 fingerprint checker. For the deeper mechanics of why handshakes get flagged, read bypassing TLS fingerprinting and the complete Cloudflare bypass recipe.
headless=False to watch what the target actually shows your bot.Get $5 free credit and residential IPs that keep Playwright and Puppeteer off the ban list.
Start Free TrialNew users get $5 USDT instantly, plus an extra first-deposit reward — limited-time offer.