Playwright, Puppeteer and Selenium can all automate modern JavaScript-heavy websites in headless mode, but they are optimized for different workflows.
Playwright is especially strong for modern end-to-end testing across Chromium, Firefox and WebKit, with built-in auto-waiting, resilient locators, tracing and parallel test tooling. Puppeteer is a focused browser-automation library maintained by the Chrome Browser Automation team and now supports both Chrome and Firefox. Selenium remains the broadest long-running cross-browser ecosystem, with W3C WebDriver, Grid and expanding WebDriver BiDi support.
This comparison is based on current official Playwright, Puppeteer and Selenium documentation. It does not present Digital Bhatti execution-speed, memory or concurrency benchmark results. The article now includes runnable equivalent scripts and a deterministic localhost benchmark method so future measurements can be reproduced with pinned framework/browser/runtime versions.
Last verified: September 24, 2026. Browser support, protocol implementations, Docker images and CI/runtime dependencies change frequently; verify the current framework documentation before pinning production or CI versions.
Playwright: 1.63.0. Current official Docker docs publish matching v1.63.0 images for Ubuntu Noble, Jammy and Resolute.
Puppeteer: 25.12.0, released September 23, 2026. Its support matrix maps this release to Chrome for Testing 154.0.8037.57 and Firefox 156.x.
Selenium: 4.49.0, released September 9, 2026 across the major bindings and Grid.
Benchmark runtime: use Node.js 22.x for the JavaScript comparison and record the exact node --version, OS/kernel and browser binary version before every published run.
Choose by Browser Coverage and Workflow, Not a Universal “Fastest” Claim
Playwright: modern cross-browser E2E testing and debugging. Puppeteer: Chrome/Firefox automation with strong Chrome tooling. Selenium: broad language/browser ecosystem, remote execution and existing enterprise Grid environments.
1. Playwright vs Puppeteer vs Selenium: Comparison Matrix
| Framework | Browser Coverage | Languages | Notable Strengths |
|---|---|---|---|
| Playwright | Chromium, Firefox, WebKit; branded Chrome/Edge options | TypeScript/JavaScript, Python, .NET, Java | Auto-waiting, resilient locators, browser contexts, tracing, screenshots/video, parallel testing |
| Puppeteer | Chrome and Firefox | JavaScript/TypeScript | Chrome DevTools integration, Chrome for Testing, WebDriver BiDi, screenshots/PDFs, network automation |
| Selenium | Major browsers via WebDriver implementations | Java, Python, JavaScript, C#, Ruby and others | W3C WebDriver, Grid, broad language ecosystem, remote/multi-machine testing, growing BiDi APIs |
2. Playwright: Strong Fit for Modern Cross-Browser E2E Testing
Playwright’s current browser documentation supports Chromium, Firefox and WebKit through one API. Its test tooling includes auto-waiting, auto-retrying assertions, tracing and parallel execution. Playwright's recommended locator model also favors user-facing attributes such as roles, labels and text instead of brittle DOM chains.
Playwright browser contexts are isolated sessions inside a browser process. They are useful for scenarios such as multiple users, separate authentication states and parallel tests without launching a completely independent browser for every logical session.
Playwright headless Chrome / Chromium
Playwright supports headless Chromium workflows and also documents a newer headless mode through the Chromium channel. The exact browser binaries are tied to the installed Playwright version, so browser installation should be updated whenever Playwright is upgraded.
npm install -D @playwright/[email protected]
npx playwright install --with-deps chromium
npx playwright --version
For a reproducible benchmark, pin the dependency rather than using @latest. For ongoing application development, update deliberately after reviewing the release and reinstall the matching browsers.
3. Puppeteer: Chrome-Focused Automation with Firefox Support
Puppeteer is maintained by the Chrome Browser Automation team. Current Puppeteer browser support covers both Chrome and stable Firefox; Firefox support is no longer accurately described as merely experimental.
For Chrome, Puppeteer continues to use the Chrome DevTools Protocol (CDP) by default. Its current FAQ states that Puppeteer v23+ has production-ready WebDriver BiDi support for both Chrome and Firefox, with BiDi used by default for Firefox.
At this verification date, current Puppeteer documentation is versioned 25.12.0. The release's documented default browser mapping includes Chrome for Testing 154.0.8037.57 and Firefox 156.x.
Puppeteer is often a practical fit when:
- The automation is written in JavaScript/TypeScript.
- Chrome-specific browser tooling matters.
- You need screenshots, PDF generation, network inspection or browser scripting.
- You do not need Playwright's WebKit coverage or its integrated Playwright Test runner.
4. Selenium: Broad Ecosystem, WebDriver, Grid and WebDriver BiDi
Selenium WebDriver is a W3C Recommendation for browser automation. Selenium supports the major browser ecosystem through browser-specific WebDriver implementations and remains widely used for cross-browser and cross-platform testing.
It is outdated to describe modern Selenium only as one-way HTTP automation. Selenium is actively moving toward WebDriver BiDi, the W3C bidirectional protocol that adds a WebSocket connection for browser events such as network activity, console messages and JavaScript errors while retaining backwards compatibility as far as practical.
Selenium Grid remains useful when tests need to run across multiple machines, browser/OS combinations or remote execution environments.
The current Selenium release verified for this guide is 4.49.0. Selenium 4.49 continues the cross-binding WebDriver BiDi work while preserving classic WebDriver compatibility.
5. Auto-Waiting and Locator Reliability
Playwright automatically performs actionability checks before actions such as clicks. It can wait for an element to be visible, stable, enabled and able to receive events before performing the action.
Its locator API is designed around retryability and fresh DOM resolution. For E2E tests, this can reduce manual sleep statements and brittle CSS/XPath chains.
Selenium and Puppeteer also provide waiting mechanisms, but the exact synchronization model and recommended patterns differ by framework. Do not compare reliability based only on whether a framework has a method named wait; compare how your test suite handles asynchronous UI state.
6. Browser Coverage: WebKit, Firefox and Branded Browsers
- Playwright: Chromium, Firefox and WebKit builds; it can also run branded Chrome and Edge channels.
- Puppeteer: current official support covers Chrome and Firefox.
- Selenium: supports major browsers through their WebDriver implementations, including common Chrome, Firefox, Edge and Safari workflows.
Playwright's WebKit build is not the same thing as automating branded Safari itself. If your requirement is actual Safari automation on Apple platforms, evaluate Selenium/WebDriver support or other Safari-specific tooling rather than assuming WebKit equals Safari.
7. Debugging: Traces, Screenshots, Video and Browser Events
Playwright's tracing tooling can record browser operations, network activity, screenshots and DOM snapshots for later inspection in Trace Viewer. Playwright Test can also retain videos and traces according to failure/retry policy.
Puppeteer provides strong screenshot, PDF and browser/network inspection capabilities. Selenium's WebDriver BiDi work increasingly exposes network, logging, scripting and browsing-context events through standardized APIs.
8. Network Interception and API-Aware Testing
All three ecosystems can participate in workflows that inspect or influence browser-network activity, but the APIs differ.
Common legitimate uses include:
- Stubbing test API responses.
- Verifying requested resources.
- Observing failed network calls.
- Testing offline/error states.
- Capturing browser console or JavaScript errors.
For production data extraction, automate only where you have permission or another lawful basis. Respect applicable terms/policies, published rate limits, authentication boundaries, privacy obligations and legal restrictions. Robots directives can be an additional signal about crawler preferences, but they are not a substitute for authorization or applicable law.
This guide does not provide CAPTCHA bypass, anti-bot evasion, fingerprint-spoofing or access-control bypass instructions. If a site blocks the workflow, use an authorized API, obtain permission or stop the automation.
9. Testing vs Scraping: Use the Right Tool for the Job
A headless browser is useful when the page depends on client-side JavaScript or real browser APIs. It is not automatically the best choice for every data-extraction task.
Prefer a direct HTTP/API workflow when the data is legitimately available without rendering because it is usually simpler and less resource-intensive. Use a browser when rendering, interaction, authentication flows or browser behavior are genuinely required.
10. Authentication and Session Reuse
Modern browser-automation suites often avoid logging in from scratch before every test. Playwright supports persisted storage state, while Puppeteer and Selenium can likewise manage cookies/session state through their respective APIs.
Treat stored authentication state as a secret. Do not commit session cookies or authenticated browser profiles to public repositories.
11. Parallelism and Isolation
Parallel browser automation can consume substantial CPU and memory, but there is no universal RAM-per-context or “X times faster” figure that applies across frameworks.
Capacity depends on:
- Browser engine and version.
- Number of tabs/pages/contexts.
- Page complexity.
- Video/tracing/screenshot recording.
- Extensions and browser flags.
- Network activity.
- Container limits.
- Test runner concurrency.
Measure your own workload before sizing CI runners or VPS workers.
12. Docker and Headless Linux Deployment
Playwright’s current Docker guidance recommends pinning the image version and matching it to the Playwright version used by the project. A mismatch can prevent Playwright from locating compatible browser executables.
The official Playwright image contains browser binaries and system dependencies, but the Playwright package itself must still be installed separately. The project also cautions that its official image is intended for testing/development and is not recommended for visiting untrusted websites.
For Playwright, use an official Microsoft Playwright container image whose version matches the Playwright package used by the project. Avoid copying a stale hard-coded image tag from an old tutorial.
# Example pattern — replace VERSION with the same Playwright version used by your project
docker run --rm -it --ipc=host \
-v "$(pwd)":/work \
-w /work \
mcr.microsoft.com/playwright:VERSION-noble \
/bin/bash
The --ipc=host option can be useful for Chromium workloads in Docker, but it should not be presented as a universal requirement for every environment. Follow the current framework/container security guidance, especially when automating untrusted websites.
Puppeteer also publishes an official versioned container image. Its documentation says the image includes Chrome for Testing, dependencies and Puppeteer, and is intended to run Chrome with its sandbox:
docker run -i --init --cap-add=SYS_ADMIN --rm ghcr.io/puppeteer/puppeteer:25.12.0 node -e "console.log(require('puppeteer/package.json').version)"
The required SYS_ADMIN capability is a meaningful security boundary. Do not expose a browser-automation container that can visit untrusted content without reviewing sandboxing, user privileges, network access and host/container isolation.
Selenium publishes official Grid/Standalone container images through Docker Hub and, since 2026, an official GHCR mirror under ghcr.io/seleniumhq. Pin the release image used by CI rather than relying on a moving latest tag when reproducibility matters.
13. Debian vs Ubuntu for Playwright: No Universal Performance Winner
The visible GSC query around Debian vs Ubuntu suggests readers are looking for an operating-system recommendation for Playwright. The practical difference is usually less about a universal speed winner and more about browser dependency compatibility, package availability, image maintenance and your deployment standard.
Playwright’s official prebuilt Docker images are Ubuntu-based. Its current image tags include supported Ubuntu LTS variants, while Alpine is not supported for Firefox/WebKit because those browser builds depend on glibc. A custom Debian image can also run Playwright when the required Node.js, browser binaries and system dependencies are installed correctly.
For performance-sensitive automation, compare Debian and Ubuntu only with the same:
- Playwright version.
- Browser build.
- CPU/RAM allocation.
- Container limits.
- Page workload.
- Concurrency.
- Tracing/video settings.
- Kernel and virtualization environment.
Without those controls, an operating-system comparison is not a meaningful browser-performance benchmark.
14. Use One Deterministic Local Workload for Framework Comparisons
Benchmarking a third-party website mixes framework overhead with DNS, CDN, network congestion, server load, consent dialogs and site changes. For framework-overhead testing, use a deterministic local page that you control.
The benchmark kit accompanying this update serves a local page on http://127.0.0.1:4173/fixture.html. Each framework performs the same task:
- Launch Chrome/headless browser.
- Open a fresh isolated session.
- Navigate to the local fixture.
- Wait for a button to become actionable.
- Click it once.
- Wait for a deterministic DOM update.
- Read the result text.
- Close the session/browser cleanly.
This workload is intentionally small. It is useful for comparing launch/navigation/action overhead and process behavior—not for predicting how any framework will behave on your full production application.
15. Pin One JavaScript Runtime and Framework Versions
For the supplied comparison, use one language/runtime so Python-vs-Java-vs-JavaScript overhead does not get mislabeled as framework overhead.
node --version
npm --version
npm install --save-dev [email protected] [email protected] [email protected]
Record the exact Node.js version rather than writing only “Node 22.” The benchmark kit targets Node.js 22.x as a controlled baseline, but published results should include the full runtime version string.
16. Record the Exact Browser Binary Instead of Assuming It
Framework packages can select different browser builds by default. That makes a “framework benchmark” confounded if each tool launches a different Chrome/Chromium version.
For a same-browser test, install one compatible Chrome or Chrome for Testing binary and set:
export CHROME_BINARY=/absolute/path/to/chrome
"$CHROME_BINARY" --version
node --version
uname -a
Then point all three scripts to that exact executable. At this verification date, Puppeteer 25.12.0 officially maps to Chrome for Testing 154.0.8037.57; if you use a different common browser build, record it explicitly.
17. Runnable Playwright Script
import { chromium } from 'playwright';
import { performance } from 'node:perf_hooks';
const url = process.env.TARGET_URL ?? 'http://127.0.0.1:4173/fixture.html';
const executablePath = process.env.CHROME_BINARY || undefined;
const started = performance.now();
const browser = await chromium.launch({ headless: true, executablePath });
const context = await browser.newContext();
const page = await context.newPage();
await page.goto(url, { waitUntil: 'domcontentloaded' });
await page.getByRole('button', { name: 'Run task' }).click();
await page.getByTestId('result').waitFor({ state: 'visible' });
const result = await page.getByTestId('result').textContent();
await context.close();
await browser.close();
console.log(JSON.stringify({
framework: 'playwright',
ok: result === 'completed',
duration_ms: Number((performance.now() - started).toFixed(2))
}));
18. Runnable Puppeteer Script
import puppeteer from 'puppeteer';
import { performance } from 'node:perf_hooks';
const url = process.env.TARGET_URL ?? 'http://127.0.0.1:4173/fixture.html';
const executablePath = process.env.CHROME_BINARY || undefined;
const started = performance.now();
const browser = await puppeteer.launch({ headless: true, executablePath });
const page = await browser.newPage();
await page.goto(url, { waitUntil: 'domcontentloaded' });
await page.locator('::-p-aria(Run task)').click();
await page.waitForFunction(
() => document.querySelector('[data-testid="result"]')?.textContent === 'completed'
);
const result = await page.$eval(
'[data-testid="result"]',
element => element.textContent
);
await browser.close();
console.log(JSON.stringify({
framework: 'puppeteer',
ok: result === 'completed',
duration_ms: Number((performance.now() - started).toFixed(2))
}));
19. Runnable Selenium JavaScript Script
import { Builder, By, until } from 'selenium-webdriver';
import chrome from 'selenium-webdriver/chrome.js';
import { performance } from 'node:perf_hooks';
const url = process.env.TARGET_URL ?? 'http://127.0.0.1:4173/fixture.html';
const options = new chrome.Options();
options.addArguments('--headless=new');
if (process.env.CHROME_BINARY) {
options.setChromeBinaryPath(process.env.CHROME_BINARY);
}
const started = performance.now();
const driver = await new Builder()
.forBrowser('chrome')
.setChromeOptions(options)
.build();
try {
await driver.get(url);
const button = await driver.wait(
until.elementLocated(By.css('button[aria-label="Run task"]')),
5000
);
await driver.wait(until.elementIsVisible(button), 5000);
await button.click();
const resultElement = await driver.wait(
until.elementLocated(By.css('[data-testid="result"]')),
5000
);
await driver.wait(
async () => (await resultElement.getText()) === 'completed',
5000
);
const result = await resultElement.getText();
console.log(JSON.stringify({
framework: 'selenium',
ok: result === 'completed',
duration_ms: Number((performance.now() - started).toFixed(2))
}));
} finally {
await driver.quit();
}
These examples deliberately use framework-native waiting rather than arbitrary sleep delays.
20. Minimal Playwright Browser-Context Example
import { chromium } from 'playwright';
const browser = await chromium.launch({ headless: true });
const context = await browser.newContext();
const page = await context.newPage();
await page.goto('https://example.com');
console.log(await page.title());
await context.close();
await browser.close();
For test suites, Playwright Test's fixtures are usually preferable to manually managing every browser lifecycle.
21. Workload Decision Matrix
| Workload | Framework(s) to Evaluate First | Reason |
|---|---|---|
| Modern E2E web testing | Playwright | Integrated test runner, auto-waiting, tracing and Chromium/Firefox/WebKit coverage. |
| Chrome-centric scripting / PDF / browser tooling | Puppeteer | Strong Chrome automation while also supporting Firefox. |
| Existing multi-language enterprise test suite | Selenium | Mature bindings, WebDriver ecosystem and Grid. |
| Cross-browser tests including WebKit | Playwright | Built-in WebKit project support. |
| Remote browser farm / Selenium Grid estate | Selenium | Grid is designed for distributed browser execution. |
| Dynamic-page data extraction | Playwright or Puppeteer | Good browser scripting APIs; use only where browser rendering is genuinely needed. |
22. Reproducible Benchmark Methodology
Run a warm-up phase first, then repeated measured runs. A reasonable starting protocol is:
- Record hardware, virtualization/container limits, OS/kernel, Node.js, framework and browser versions.
- Disable video/tracing/screenshots unless that feature is part of the workload being compared.
- Use the same browser executable and headless mode for all three frameworks where supported.
- Serve the deterministic fixture locally.
- Run 5 unreported warm-up iterations per framework.
- Run at least 30 measured iterations per framework.
- Rotate framework order between runs or execute separate isolated batches so thermal/load drift does not always favor the first tool.
- Record successful duration, failures/retries, peak RSS/container memory and CPU data.
- Report median and p95; retain the raw CSV.
If you test concurrency, repeat the complete experiment at controlled levels such as 1, 2, 4 and 8 simultaneous sessions. Do not assume linear scaling, and stop increasing concurrency when the host is swapping, throttling or producing unstable failures.
23. Benchmark Environment Record
| Variable | Record Before Publishing Results |
|---|---|
| CPU / vCPU model and allocation | Fill from actual machine |
| RAM / container limit | Fill from actual machine |
| OS + kernel | uname -a + distro release |
| Node.js | node --version |
| Playwright | 1.63.0 for this methodology unless deliberately updated |
| Puppeteer | 25.12.0 for this methodology unless deliberately updated |
| Selenium | 4.49.0 for this methodology unless deliberately updated |
| Chrome / Chrome for Testing | Record exact --version output and binary path |
| Headless mode / flags | Record exact launch options |
| Concurrency | 1 / 2 / 4 / 8 or actual tested values |
24. Results Table — Leave Blank Until the Benchmark Is Actually Run
| Framework | Runs | Median ms | p95 ms | Failures / Retries | Peak RSS / Container Memory |
|---|---|---|---|---|---|
| Playwright | Record | Measure | Measure | Measure | Measure |
| Puppeteer | Record | Measure | Measure | Measure | Measure |
| Selenium | Record | Measure | Measure | Measure | Measure |
Do not fill this table from vendor marketing, another website or a different machine. Publish it only from the raw runs produced by the recorded environment.
25. CI/CD and Resource Sizing
Do not size CI runners from generic “MB per browser” numbers. Run representative tests with the exact browser versions and recording options you plan to use.
Before measuring, capture the host baseline:
node --version
uname -a
lscpu
free -h
Inside containers, also record the actual cgroup/container CPU and memory limits rather than assuming the host's total resources are available.
Measure:
- Peak RSS / container memory.
- CPU saturation.
- Test duration.
- Failure/retry rate.
- Disk consumed by browser binaries, traces and videos.
- Network usage.
If browser workers run on a Linux VPS, compare the compute layer separately using the Shared vs VPS vs Cloud Hosting Guide.
If browser workers are exposed as a service or run untrusted workloads, harden the host separately using the Linux VPS Security Hardening Guide.
26. Integration with Self-Hosted Automation
Browser tasks can be triggered by queues, CI systems, cron jobs or workflow tools. For automation workflows that use n8n on your own server, see How to Self-Host n8n with Docker on a Linux VPS.
Keep long-running browser jobs isolated from latency-sensitive web traffic when they compete for CPU, memory or file descriptors.
27. Browser Lifecycle, Cleanup and Zombie Processes
Long-running automation services should treat browser cleanup as part of capacity planning. Crashed jobs, abandoned contexts or orphaned browser processes can consume memory, file descriptors and process slots long after the original task failed.
Use structured cleanup so pages, contexts and browser processes are closed even when a task throws an exception. Also monitor the worker host for:
- orphaned Chrome/Chromium/Firefox processes,
- rising resident memory,
- file-descriptor growth,
- stale temporary profiles,
- retry storms, and
- queue depth that exceeds available browser capacity.
Reusing a browser process with multiple isolated contexts can reduce launch overhead for some trusted test workflows, but it should be evaluated against isolation, crash impact and memory behavior rather than treated as a universal optimization.
Every runnable example in a long-lived worker should use try/finally or equivalent cleanup around browser/session lifecycle so an exception does not leave a browser process behind. Also use a container init process where the framework's container guidance recommends one.
28. Common Comparison Mistakes
- Calling Puppeteer Chromium-only: current Puppeteer supports Chrome and Firefox.
- Calling Selenium “HTTP-only”: Selenium is actively implementing WebDriver BiDi.
- Equating Playwright WebKit with branded Safari: they are not identical targets.
- Publishing universal RAM/speed rankings: results vary heavily by workload and configuration.
- Benchmarking different browser builds: a Playwright Chromium vs Puppeteer Chrome vs Selenium-discovered Chrome comparison is not framework-only evidence.
- Publishing a single run: use warm-ups, repeated runs, median/p95 and failure rate.
- Benchmarking the public internet as the only workload: network/server variance can dominate framework overhead.
- Using fixed sleeps everywhere: prefer framework-specific waiting/locator strategies.
- Using a headless browser when a direct API is enough: browser rendering adds resource cost.
- Hard-coding old Docker image versions: match the browser image to the framework package.
- Mixing testing with access-control bypass: browser automation should respect authorization and site policies.
- Giving benchmark containers unnecessary privileges: understand sandbox/capability requirements before exposing browser workers to untrusted input.
Summary: Playwright vs Puppeteer vs Selenium Checklist
- Use Playwright when Chromium + Firefox + WebKit coverage, auto-waiting, tracing and modern E2E tooling fit the project.
- Use Puppeteer when JavaScript/TypeScript browser scripting and strong Chrome tooling are central; remember current Puppeteer also supports Firefox.
- Use Selenium when you need its broad language ecosystem, WebDriver compatibility, Grid or an existing enterprise automation estate.
- Pin and record Playwright, Puppeteer and Selenium versions.
- Record Node.js, browser, OS/kernel, CPU and RAM/container limits.
- Use the same browser executable for framework benchmarks where practical.
- Run warm-ups plus repeated measured runs; report median, p95 and failure/retry rate.
- Measure your own concurrency and memory requirements.
- Use resilient locators and explicit test contracts.
- Keep test authentication state secret.
- Match Docker/browser images to framework versions.
- Prefer direct HTTP/API access when browser rendering is unnecessary.
- Prefer a deterministic local fixture for framework-overhead benchmarks.
- Keep the raw benchmark CSV/results before publishing conclusions.
- Do not treat CAPTCHA, anti-bot or access-control bypass as a normal automation requirement.
Need to Run Browser Jobs Inside a Workflow?
Keep browser workers resource-isolated, then trigger them from queues, CI or self-hosted workflow automation rather than tying long-running browser sessions to normal web requests.
Open n8n Self-Hosting Guide →Frequently Asked Questions
Does Puppeteer support Firefox?
Yes. Current Puppeteer supports both Chrome and Firefox. Puppeteer uses CDP by default for Chrome and WebDriver BiDi for Firefox, while also supporting BiDi for Chrome.
Does Playwright support headless Chrome?
Yes. Playwright supports headless Chromium workflows and can also run branded Chrome channels. Keep the Playwright package and installed browser binaries in sync when upgrading.
Is Playwright faster than Selenium?
There is no universal answer. Runtime depends on browser versions, test architecture, parallelism, page complexity, waits, tracing/video settings and machine resources. Measure the exact suite instead of relying on generic benchmark claims.
Does Selenium support bidirectional browser events?
Yes. Selenium is implementing the W3C WebDriver BiDi protocol, which adds bidirectional WebSocket communication for features including network, logging, scripting and browsing-context events.
Should I use a headless browser for web scraping?
Only when browser rendering or interaction is genuinely required. If an authorized HTTP endpoint or API already exposes the data, a direct client is usually simpler and less resource-intensive.
Does Playwright WebKit equal Safari?
No. Playwright uses its own WebKit build. It is useful for WebKit-engine testing, but it is not identical to automating the branded Safari browser itself.
What framework versions were current for this update?
This article was verified against Playwright 1.63.0, Puppeteer 25.12.0 and Selenium 4.49.0 on September 24, 2026. Pin exact versions when publishing benchmark results.
Which Chrome version does Puppeteer 25.12.0 use?
Current Puppeteer documentation maps version 25.12.0 to Chrome for Testing 154.0.8037.57. For a framework comparison, use one compatible Chrome binary for all tools where practical and record its exact version.
How many benchmark runs should I use?
There is no universal statistical sample size, but one run is not adequate evidence. The methodology in this article uses warm-up runs followed by at least 30 measured runs and reports median, p95 and failures/retries. Increase the sample when results are noisy.
Should I benchmark Playwright, Puppeteer and Selenium against a public website?
Not as the only test. A public site introduces network, CDN, server-load and content-change variance. Use a deterministic local fixture for framework overhead, then test your own authorized production/staging application separately for real workflow reliability.
Can I use browser automation to bypass CAPTCHA or anti-bot protection?
This guide does not provide bypass or evasion instructions. Use authorized APIs, obtain permission, follow the site's supported automation path or stop the workflow when access controls prohibit it.
Abdul Shakoor
Founder of Digital Bhatti, an independent technical publication focused on web hosting and infrastructure, WordPress, technical SEO, web performance and automation.
This guide is documentation-led. It does not claim a Digital Bhatti framework-speed, RAM, concurrency or Debian-vs-Ubuntu benchmark unless the exact code, versions, hardware and raw repeated-run results are explicitly published.