Selenium vs. Playwright vs. Puppeteer
A three-way comparison of Selenium, Playwright and Puppeteer: protocols, browser coverage, language support, waiting behaviour, and how to choose.
All three drive real browsers programmatically. They differ in how they talk to the browser, how many browsers they reach, and how much work they do on your behalf. Choosing between them is mostly a question of browser coverage and language, not capability.
1. Selenium
The oldest and the only W3C standard, driving browsers through the WebDriver protocol implemented by each vendor's own driver binary.
- Protocol: W3C WebDriver over HTTP
- Browsers: Chrome, Firefox, Safari, Edge, and anything with a conforming driver
- Languages: Java, Python, C#, Ruby, JavaScript, and more
- Waiting: explicit, your responsibility
- Distinctive strength: real Safari, and the broadest language support in existence
2. Puppeteer
Google's Node.js library for Chrome, released in 2017, speaking the Chrome DevTools Protocol directly.
- Protocol: CDP over WebSocket
- Browsers: Chromium, with Firefox support added later
- Languages: JavaScript and TypeScript only
- Waiting: mostly explicit
- Distinctive strength: a thin, well-documented layer over CDP with direct access to raw protocol calls
3. Playwright
Microsoft's cross-browser library from 2020, built largely by former Puppeteer engineers, using native debugging protocols.
- Protocol: CDP and native protocols over WebSocket
- Browsers: Chromium, Firefox, WebKit
- Languages: JS/TS, Python, Java, .NET
- Waiting: automatic on most actions
- Distinctive strength: one API across three engines, auto-waiting, and a test runner included
4. Side by Side
| Selenium | Puppeteer | Playwright | |
|---|---|---|---|
| First released | 2004 | 2017 | 2020 |
| Standardised | W3C | No | No |
| Real Safari | Yes | No | No (WebKit approximates) |
| Firefox | Yes | Limited | Yes |
| Languages | Many | JS/TS only | JS/TS, Python, Java, .NET |
| Auto-waiting | No | Partial | Yes |
| Speed | Slower (HTTP per command) | Fast | Fast |
| Network interception | Limited (CDP in v4) | Yes | First-class |
| Test runner included | No | No | Yes |
| Parallel isolation | New session per test | Contexts | Contexts, cheap |
| Ecosystem age | Two decades | Mature | Newer, growing fast |
5. How to Choose
The decision usually collapses to two questions.
Do you need real Safari? If yes, Selenium, and the discussion is over. Playwright's WebKit shares Safari's engine but is not Safari β it lacks Safari's own layer, and Safari-specific bugs can hide in that gap.
What language are you writing in? Puppeteer is Node-only. If you are in Python, Java or .NET, it is not a candidate. Selenium and Playwright both cover those.
After that:
- Chrome-only, Node.js, want minimal abstraction β Puppeteer. The smaller surface and direct CDP access are genuine advantages for rendering services, PDF generation, and tracing.
- Cross-browser, or flakiness is your recurring cost β Playwright. Auto-waiting removes the failure class that explicit waits exist to patch, and the included runner saves assembling one.
- Existing Selenium Grid and expertise β Selenium. Migrating a large working suite rarely pays for itself.
6. The Difference That Matters Day to Day
Not speed β waiting.
In Selenium and Puppeteer, code that clicks an element rendered after an XHR needs an explicit wait first. Omit it and the test passes on a fast machine and fails in CI, which is the origin of most flaky suites and most sleep() calls.
Playwright's actions wait for the element to be attached, visible, stable and enabled before acting. The code is shorter and the flakiness class largely disappears.
If your suite is peppered with fixed sleeps, that is the symptom Playwright addresses structurally. It is usually a bigger practical win than any performance difference.
7. Summary
Selenium is the standard: broadest browsers including real Safari, broadest language support, two decades of tooling, and explicit waiting. Puppeteer is the focused Chrome library for Node.js with direct protocol access. Playwright is the cross-browser, multi-language framework with auto-waiting, network interception, and a runner included.
For new work without a Safari requirement, Playwright is the lowest-friction choice. For Chrome-only Node work where you want the thinnest layer, Puppeteer remains a good fit. For real Safari, unusual browsers, or an established grid, Selenium is still correct β and running Playwright day to day with Selenium for the Safari matrix is a perfectly sensible combination rather than a compromise.