How to Use Proxies with Puppeteer and Playwright
By froxproxy Team · July 30, 2026 · 3 min read
Both libraries support proxies, but they handle authentication very differently — and Playwright’s approach is considerably better if you need more than one proxy at a time.
Puppeteer
The proxy is a Chrome launch flag, so it applies to the whole browser:
import puppeteer from 'puppeteer';
const browser = await puppeteer.launch({
args: ['--proxy-server=http://HOST:PORT'],
});
const page = await browser.newPage();
await page.authenticate({ username: 'USER', password: 'PASS' });
await page.goto('https://api.ipify.org');
console.log(await page.evaluate(() => document.body.innerText));
await browser.close();
Two things to note.
Credentials cannot go in the flag. --proxy-server=http://user:pass@host:port does not work — Chrome ignores the userinfo. You must call page.authenticate(), and on every page you create.
One proxy per browser. To use several proxies you launch several browsers, which is memory-hungry. Roughly 100–200 MB each, so a pool of twenty is several gigabytes.
For SOCKS5, note that Chrome cannot authenticate SOCKS proxies at all. Use IP whitelisting if you need SOCKS — see authentication methods.
Playwright
Playwright accepts credentials directly and, more usefully, supports a proxy per browser context:
import { chromium } from 'playwright';
const browser = await chromium.launch();
const context = await browser.newContext({
proxy: {
server: 'http://HOST:PORT',
username: 'USER',
password: 'PASS',
},
});
const page = await context.newPage();
await page.goto('https://api.ipify.org');
console.log(await page.textContent('body'));
await browser.close();
Contexts are the reason to prefer Playwright here. Each is an isolated browser session — its own cookies, storage and proxy — but they share one browser process. Ten contexts with ten proxies cost a fraction of ten browsers:
const proxies = [/* ... */];
const contexts = await Promise.all(
proxies.map((p) =>
browser.newContext({
proxy: { server: p.server, username: p.user, password: p.pass },
})
)
);
That combination — isolated cookies plus a dedicated IP per context — is exactly what you want for managing multiple accounts. See proxies for social media.
Block images to cut bandwidth
On residential proxies you pay per gigabyte, and images are most of a page’s weight:
await page.route('**/*', (route) => {
const type = route.request().resourceType();
if (['image', 'media', 'font'].includes(type)) return route.abort();
return route.continue();
});
This routinely cuts bandwidth by 70–80%. The trade-off is that a browser fetching no images is itself a signal — worth it for bulk work, not when you are trying hard to look human.
Puppeteer equivalent:
await page.setRequestInterception(true);
page.on('request', (req) => {
['image', 'media', 'font'].includes(req.resourceType()) ? req.abort() : req.continue();
});
Headless browsers are detectable by default
A proxy hides your IP; it does nothing about the browser announcing itself as automated.
Out of the box, both libraries expose navigator.webdriver === true, ship a HeadlessChrome user agent, and have missing or inconsistent properties that detection scripts check routinely.
At minimum:
const context = await browser.newContext({
proxy: { /* ... */ },
userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 ' +
'(KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36',
viewport: { width: 1920, height: 1080 },
locale: 'en-GB',
timezoneId: 'Europe/London',
});
Keep those consistent with the proxy. A German IP with en-US and America/New_York is a contradiction that fingerprinting catches immediately — it is worse than leaving the defaults.
For the deeper tells, puppeteer-extra-plugin-stealth patches the well-known ones. It is not a complete answer against serious anti-bot systems, but it clears the easy checks. More on this in why proxies get banned.
Verify the proxy is actually in use
const ip = await page.evaluate(() =>
fetch('https://api.ipify.org').then((r) => r.text())
);
console.log('exit IP:', ip);
If that matches your own address, the configuration is not taking effect — with Puppeteer this usually means the launch flag was malformed.
Which to choose
Playwright, unless you have a reason not to. Per-context proxies, credentials handled natively, and far lower memory when running several identities at once. Puppeteer is fine for a single proxy and a single session.
See pricing for proxy costs, or how many proxies you need for sizing.
Ready to try froxproxy?
Residential, ISP, mobile and datacenter proxies with instant setup and pay-as-you-go pricing.
View pricing