15% off your first purchase with code WELCOME15, up to 25 GB.

See pricing

Guide · Scraping practice

Playwright vs Puppeteer vs Selenium for web scraping

For new scraping code, Playwright is often the most convenient of the three: it drives Chromium, Firefox and WebKit from JavaScript, Python, Java or .NET, waits for elements before acting, and takes an authenticated proxy per browser or per context. Puppeteer suits JavaScript teams working mainly with Chrome, with proxy credentials supplied per page. Selenium implements the W3C WebDriver standard, covers the most languages and existing test grids, but has no field for proxy credentials. All three render pages in a real browser, which costs far more bandwidth than an HTTP client — so first check whether you need a browser at all.

Reviewed 30 Oct 2026

The short answer

  • Use a browser only when the data is built client-side and you cannot find the JSON request behind it.
  • Playwright: proxy with server, username and password on launch or on each new context.
  • Puppeteer: --proxy-server (or proxyServer per browser context) for the address, page.authenticate() for credentials on every page.
  • Selenium: options.proxy takes host and port only; authenticated proxies need a local forwarder that adds the credentials.
  • The choice usually follows your team's language and existing infrastructure more than any feature gap.

The three tools side by side

AspectPlaywrightPuppeteerSelenium
LanguagesJavaScript/TypeScript, Python, Java, .NETJavaScript/TypeScriptJava, Python, C#, Ruby, JavaScript
BrowsersChromium, Firefox, WebKitChrome, FirefoxChrome, Firefox, Edge, Safari via their drivers
ControlIts own browser builds, installed with playwright installChrome DevTools Protocol or WebDriver BiDiW3C WebDriver, plus WebDriver BiDi
WaitingActionability checks before every actionLocators wait for element state before actingExplicit waits; implicit wait defaults to 0
Proxy credentialsusername and password fieldspage.authenticate() per pageNo field; local forwarder
Proxy per isolated contextYes, new_context(proxy=…)Yes, createBrowserContext({ proxyServer })One proxy per driver session
Request blockingroute()Request interceptionThrough WebDriver BiDi; support varies by language binding

How each tool takes a proxy

Playwright documents a proxy option that can be set globally for the browser or per browser context, with server, username and password. It answers the proxy's authentication challenge itself. One context per task, each with its own sticky-session username, gives each task its own exit and cookie jar. Details and code: Playwright proxy setup.

Puppeteer passes the proxy address to Chrome as --proxy-server or per context as proxyServer; Chrome's flag has no place for credentials, so they go to page.authenticate(), which must be called on every new page before its first navigation. See Puppeteer proxy setup.

Selenium sets host and port through its proxy capability, but neither that capability nor Chrome's flag carries a username and password. The dependable pattern is a small local forwarder that Selenium talks to without credentials and that adds them on the way to the gateway. See Selenium proxy setup.

Waiting, network control and bandwidth

Scrapers fail most often on timing: the element is not there yet. Playwright performs actionability checks before each action and waits for them to pass. Puppeteer's locator API likewise waits — for example for an element to be enabled and to have a stable position — before clicking. Selenium leaves it to you: its documentation describes an implicit wait that defaults to zero and explicit waits for specific conditions, and warns against mixing the two.

Network control decides your bandwidth bill. Blocking images, media and fonts is one line in Playwright's route() and a request-interception handler in Puppeteer; Selenium can intercept requests through WebDriver BiDi, with support that varies by language binding. A rendered page with assets is megabytes against kilobytes for its HTML, so blocking is worth doing in any of them — see how to reduce proxy bandwidth.

Concurrency and sessions

  • Playwright contexts are isolated — separate cookies and storage — and cheap to create, so one browser can run many tasks, each with its own proxy username and sticky session.
  • Puppeteer browser contexts give the same isolation, and proxyServer per context lets each use its own exit; remember authenticate() on each page.
  • Selenium isolates per driver session, which means one browser process per concurrent task and one forwarder or proxy setting per session. Selenium Grid distributes sessions across machines if you already run one.

Which one to choose

  • Python or .NET team, new project: Playwright. If you already use Scrapy, scrapy-playwright adds rendering to the requests that need it.
  • Node.js team, Chrome-centred, existing Puppeteer code: Puppeteer.
  • Existing Selenium test suite or Grid, Java, C# or Ruby codebase: Selenium, with a local forwarder for proxy credentials.
  • Data available in HTML or a JSON endpoint: none of them — use an HTTP client. A headless browser is the expensive fallback, not the default.

FAQ

Questions

Something not covered? Write to contact@arcproxies.io.

Is Playwright better than Selenium for scraping?

For new scraping code it is often more convenient: built-in waiting, isolated contexts and proxy credentials in the launch options. Selenium is the better fit when you already run Selenium infrastructure or work in a language Playwright does not support, such as Ruby.

Can Puppeteer use a proxy with a username and password?

Yes. Pass the proxy address with --proxy-server or as proxyServer on a browser context, then call page.authenticate() with the username and password on each page before it navigates.

Does Selenium support authenticated proxies?

Not directly. Selenium's proxy capability takes a host and port but no credentials. The usual approach is a local forwarding proxy that adds the credentials to each request on its way to the upstream proxy.

Which of the three is fastest?

There is no general answer: page load time is dominated by the site, the network and what you block, not by the automation library. Measure on your own targets with the same browser and blocking rules in each.

Can I use Playwright from Python?

Yes. Playwright has official libraries for Python, Node.js, Java and .NET, all with the same proxy options on launch and on new contexts.

Do I need a headless browser for web scraping?

Only when the content is built by JavaScript and you cannot request the underlying data directly. Many dynamic pages load their data from a JSON endpoint you can call with an HTTP client at a fraction of the bandwidth.

Sources & review

Last reviewed by the ARC Proxies team. Prices are read from the live catalog at build time.

  1. [1]Playwright: Network: HTTP proxy
  2. [2]Playwright: Auto-waiting (actionability checks)
  3. [3]Puppeteer: Puppeteer — introduction
  4. [4]Puppeteer: Page interactions: locators
  5. [5]Selenium: Waiting strategies
  6. [6]W3C: WebDriver

Next

Where to go from here

Use caseProxies for web scraping and data collectionA second provider that just works — Scrapy, requests, Crawlee or Playwright, self-serve, no sales call, bandwidth that never expires.Use caseProxies for QA, app and localisation testingSee your own site the way a user in Tokyo, São Paulo or Munich sees it — currency, language, consent banner, CDN edge and all — before they report it.IntegrationPlaywrightSet up an authenticated proxy in Playwright for Python and Node: launch and per-context proxies, sticky sessions, geo-targeting and handling proxy errors.IntegrationPuppeteerUse an authenticated proxy in Puppeteer: --proxy-server plus page.authenticate, per-context proxies for sticky sessions, geo-targeting and 407 handling.IntegrationSeleniumSelenium has no field for proxy credentials. Route Chrome through a local forwarder that adds them, with sticky sessions, geo-targeting and checks.Integrationscrapy-playwrightSet a proxy for scrapy-playwright: PLAYWRIGHT_LAUNCH_OPTIONS, a sticky session per browser context, markets as contexts and what a 407 looks like.GlossaryHeadless browserA headless browser is a real web browser engine running without a visible window and controlled by code instead of a person; it loads pages, executes JavaScript and builds the DOM like a normal browser, which makes it the tool for pages whose content only appears after scripts run.GlossarySticky sessionA sticky session is a setting on a rotating proxy that keeps the same exit IP address for a chosen period, usually by attaching a session identifier to the connection, so a multi-step task appears to come from one address from start to finish.GuideHow to reduce proxy bandwidthCut proxy bandwidth by fetching HTML or JSON instead of rendering, blocking images and fonts, using compression, conditional requests and local caching.