
- Puppeteer is a library for Chrome and Firefox in JavaScript and TypeScript; Playwright supports Chromium, Firefox and WebKit and the languages JS/TS, Python, Java, .NET
- In Puppeteer the proxy is usually set when the browser launches, and the username and password are passed through page.authenticate
- In Playwright a proxy with a username and password is set at launch or for a separate context, which is handy for several profiles in one browser
- For logging in to an account and other multi-step scenarios, take a sticky port 10000-20000; for independent requests, rotation on 823 or 824
- Blocking images, fonts and video through request interception noticeably cuts traffic use in both libraries
Puppeteer and Playwright solve the same task: they control a real browser from code. A script opens pages, clicks buttons, fills in forms and collects data. Both libraries can work through a proxy, but they do it differently.
Below: how they differ, how to connect a proxy in each, how to save traffic and which ports to use for different scenarios. At the end, a simple rule for choosing.
Two libraries with shared roots
Puppeteer appeared earlier and is developed by the Chrome team at Google. For a long time it worked only with Chrome and Chromium, and now it also supports Firefox. You write in it in JavaScript or TypeScript on Node.js.
Playwright was created at Microsoft, and some of its authors used to work on Puppeteer. That is why the syntax is similar, but Playwright was designed broader from the start: several browsers, several languages, built-in tools for tests.
Comparison in one table
| What we compare | Puppeteer | Playwright |
|---|---|---|
| Browsers | Chrome and Chromium, Firefox | Chromium, Firefox, WebKit |
| Languages | JavaScript, TypeScript | JavaScript, TypeScript, Python, Java, .NET |
| Where the proxy is set | The --proxy-server argument at browser launch | The proxy option at browser launch or for a separate context |
| Proxy username and password | page.authenticate() on the page | The username and password fields in the proxy option |
| Different IPs in one browser | Usually one proxy per launch, different browsers for different IPs | Each context with its own port |
| Waiting for elements | Usually written by hand | Auto-waiting before actions |
| Tests and recording actions | A separate test runner is needed | Its own Playwright Test runner and the codegen code generator |
| Request interception | page.setRequestInterception() | page.route() or context.route() |
Browsers and languages: where the choice starts
If your team writes in Python, Java or C#, the question is almost settled. Playwright has official versions for these languages with the same set of features. Puppeteer officially has only JavaScript and TypeScript, and third-party ports to other languages are developed separately and lag behind.
It is a similar story with browsers. Puppeteer covers Chrome and Firefox well. Playwright adds WebKit, the engine Safari runs on. This matters if you test a website the way iPhone and Mac users see it.
How to connect a proxy in Puppeteer
Chromium in Puppeteer takes the proxy from the --proxy-server argument at launch. It contains only the protocol, host and port, without the username. The username and password are passed separately, through page.authenticate(), before the first navigation on the page.
The main consequence: the proxy is tied to the browser launch. If you need three different addresses, you usually launch three browsers, each on its own port. In newer versions you can also set a proxy for a separate context, but authentication still goes through the page. Step-by-step setup is in the Puppeteer guide.
The example below launches a browser on a sticky port, turns off images, fonts and video and prints the address the website sees:
import puppeteer from "puppeteer";
const browser = await puppeteer.launch({ args: ["--proxy-server=http://gw.prokso.com:10001"] });
const page = await browser.newPage();
await page.authenticate({ username: "USERNAME", password: "PASSWORD" });
await page.setRequestInterception(true);
page.on("request", (req) => {
if (["image", "font", "media"].includes(req.resourceType())) req.abort();
else req.continue();
});
await page.goto("https://api.ipify.org");
console.log(await page.evaluate(() => document.body.innerText));
await browser.close();How to connect a proxy in Playwright
Playwright accepts the proxy together with the username and password in the proxy option: the server, username and password fields. No separate authentication on the page is needed. You can pass the option at browser launch, and then the proxy is shared by all pages.
The second option is to set the proxy for a context: browser.newContext({ proxy }). A context is like a separate profile: its own cookies, storage and its own address. This way several profiles on different sticky ports work in one browser, and you do not need to relaunch the browser for each one. In Python the syntax is the same. Details are in the Playwright guide.
import { chromium } from "playwright";
const browser = await chromium.launch();
const ports = [10001, 10002, 10003];
for (const port of ports) {
const context = await browser.newContext({
proxy: { server: `http://gw.prokso.com:${port}`, username: "USERNAME", password: "PASSWORD" },
});
await context.route("**/*", (route) =>
["image", "font", "media"].includes(route.request().resourceType()) ? route.abort() : route.continue()
);
const page = await context.newPage();
await page.goto("https://api.ipify.org");
console.log(port, await page.textContent("body"));
await context.close();
}
await browser.close();Each context here exits through its own port and gets its own address. If you open an IP check page in them, you will see three different IPs from one country.
A SOCKS5 limitation common to both
Chromium does not accept a password for a SOCKS5 proxy, and this applies to both Puppeteer and Playwright. So it is more convenient to work with a username and password over HTTP: port 823 or sticky ports 10000-20000. If you specifically need SOCKS5, turn on access by IP in the dashboard: up to 5 addresses per plan, no username needed.
What else Playwright gives you
Auto-waiting is the most noticeable difference in daily work. Before a click or text input, Playwright itself waits until the element appears and becomes visible and available. Scripts come out shorter and fail less often on slow pages, and through a proxy pages sometimes load longer than usual.
Two more tools come included. Playwright Test is a test runner with parallel runs, reports and tracing. Codegen records your actions in the browser and turns them into ready code, which greatly speeds up the first steps.
Maturity and community
Puppeteer has a long history, so there are many ready answers, examples and third-party modules for typical questions. Many tools that connect to an already open browser have historically offered examples specifically for Puppeteer.
Playwright is younger, but it has grown fast and is actively developed. Its documentation is detailed, and examples are available for all languages at once. For new projects, especially ones with tests, it is chosen more and more often.
How to save traffic in either of them
Traffic in Prokso is counted in both directions and paid for by the gigabyte. A browser loads the whole page, and images, video and fonts often take up most of the volume. If you only need text or data, you can skip loading them.
- In Puppeteer, turn on
page.setRequestInterception(true)and abort requests of the image, font and media types. - In Playwright, use
page.route()orcontext.route()and callroute.abort()for the same types. - Do not open the same page several times per run: save the result and take it from the cache.
- Close contexts and browsers after the task so that background requests do not waste traffic.
The traffic calculator will help you estimate usage in advance. Prices per gigabyte for each proxy type are on the pricing page.
Sticky port or rotation
The choice of port does not depend on the library, it depends on the scenario. If a script goes through several steps on one website (login, confirmation, cart), the address must not change halfway. Otherwise the website will see that one user ended up in different places within a minute.
- A multi-step scenario: a sticky port from 10000 to 20000 on gw.prokso.com. It keeps one address for 1 to 120 minutes, 30 by default. Set the hold time with a margin for the whole scenario.
- Independent pages, for example collecting product cards: rotation, port 823 for HTTP or 824 for SOCKS5, a new address on every request.
- Several profiles in parallel: each gets its own sticky port, a separate browser in Puppeteer or a separate context in Playwright.
Keep in mind that a sticky residential or mobile address can change before its time is up if the device goes offline. The port then gets a new address from the same country. It is good if the script can continue the step after such a change rather than fail with an error. More about the modes in the glossary: sticky session.
How to choose: a short rule
- You do not write in JavaScript: take Playwright.
- You need WebKit or tests in several browsers: Playwright.
- Many profiles with different addresses in one process: Playwright with contexts is more convenient.
- You already have working Puppeteer code or need only Chrome: there is no point in rewriting it, Puppeteer will do the job.
- The project is already on Selenium and everything suits you: stay with it, the proxy connects there too.
If you are on Selenium, see the Selenium guide. And if an AI agent controls the browser, the article proxies for AI agents will be useful: it has the same rules about ports and traffic, only adjusted for the fact that the agent acts on its own.
In both cases, start small: one script, one port, an address check on the my IP page. When everything works, add profiles and threads. And remember that proxies do not cancel a website's rules: the request pace and the platform's terms apply to any address.
FAQ
Which library should a beginner choose?
If you write in Python, Java or .NET, the choice is simple: Playwright, since Puppeteer has no official support for these languages. In JavaScript you can start with either. Playwright is easier for tests thanks to auto-waiting and its built-in runner; Puppeteer fits when you only need to automate Chrome.
Can I set a different proxy for different tabs in Puppeteer?
The classic way is one proxy per browser launch through the --proxy-server argument. In newer versions you can also set a proxy for a separate browser context, but the username and password are still passed on the page. If you need many profiles with different addresses, this is easier in Playwright.
Why does SOCKS5 with a username and password not work?
Chromium does not accept a password for a SOCKS5 proxy, and this applies to both libraries. Use HTTP ports with a username and password or turn on access by IP in the dashboard: then SOCKS5 works without a password.
Which port should I use to log in to an account?
A sticky one, from the 10000-20000 range. It keeps one address for 1 to 120 minutes, 30 by default, so the login, confirmation and next steps go from one IP. Ports 823 and 824 change the address on every request and suit collecting independent pages.
How many browsers can I run in parallel?
On the Prokso side, the limit is up to 1000 concurrent connections per plan. In practice you will hit the memory and CPU of your own machine sooner: each browser is heavy. Start with a few instances and increase the number while watching for errors.


