Puppeteer vs Playwright in practice
The APIs are 85% the same — both expose page, frame, request, and response abstractions with similar method names. Differences that matter for scraping:
- Auto-waiting — Playwright waits for elements to be actionable by default; Puppeteer waits only when explicitly told. Puppeteer scripts have more
waitForSelectorcalls. - Parallel contexts — Playwright's
browserContextabstraction is cleaner for running multiple isolated sessions in one browser. Puppeteer supports it but the API is older. - Languages — Puppeteer is Node-only. If your stack is Python, Playwright is the only choice.
- Stealth plugins — Puppeteer's stealth ecosystem is older and more mature.
puppeteer-extra-plugin-stealthhas more patches than its Playwright equivalent, though both lose to Function.toString() inspection equally.
For a greenfield scraping project in Node, default to Playwright unless your team has existing Puppeteer code. Puppeteer is not deprecated, but the active feature investment has shifted to Playwright.
puppeteer-extra and the stealth plugin
The puppeteer-extra plugin system, with puppeteer-extra-plugin-stealth, is the most-cited stealth approach for Puppeteer. It runs ~17 individual patches: hides navigator.webdriver, fixes the plugin array, patches WebGL parameters, normalises the User-Agent, masks the chrome.runtime object, and so on.
It defeats every detection a 2019 anti-bot system used. It does not defeat 2024+ vendors that check via Function.toString() (see that entry) or that look for CDP runtime artifacts. Each of the 17 patches is a JS function whose source is visible to toString(); Kasada, recent Akamai, and PerimeterX flag this stack on first request.
For Puppeteer in production against hard targets, the modern approach is puppeteer-real-browser (driving a real Chrome rather than headless Chromium) or switching to a C++-patched variant like CloakBrowser.
When to actually use Puppeteer
Three scenarios where Puppeteer is the right pick over Playwright:
- The codebase is already on Puppeteer and switching is gratuitous.
- The project depends on a Puppeteer-only library (
puppeteer-cluster,puppeteer-screen-recorder) that doesn't have a Playwright equivalent. - The team specifically wants the older, smaller API surface — Puppeteer's scope is narrower than Playwright's, which some teams find easier to reason about.
For everything else, the answer is Playwright. The CDP protocol, the Chromium binary, and the detection surface are identical — the practical difference is API ergonomics and the language reach.
