# Playwright vs Puppeteer: the same jobs timed on one machine, and what actually differs

> Playwright 1.64 vs Puppeteer 25.7: the same screenshot, PDF and element jobs timed on one machine, plus headless modes, browsers, languages and waiting.

Published 2026-11-08 · https://shareglint.com/en/guides/playwright-vs-puppeteer

Playwright and Puppeteer are the two libraries people choose between to drive a browser from code, and for everyday jobs their code looks almost the same. So instead of a feature checklist, we ran the **same jobs in both on one machine** and compared the numbers, then went through the differences that actually decide the choice.

**How we measured.** On 2026-11-08: Puppeteer 25.7.0 in the official `ghcr.io/puppeteer/puppeteer` image (Chrome 152.0.7977.42) and Playwright 1.64.1 in the official `mcr.microsoft.com/playwright:v1.64.1-noble` image (Chromium 156.0.8078.80), on the same computer — an AMD Ryzen 9 7950X3D under WSL2 — against the same local test page. Each run: five cold launches, then ten rounds on one browser of *open the page → viewport screenshot → full-page screenshot → A4 PDF → element screenshot*; the numbers are medians, from three runs each. The machine was shared with other work (load average 10–66 during the runs), so read differences under about 20 % as noise. Browser versions differ too: each library ships the build it is tested with.

## The numbers

| Median, ms | Puppeteer (default: new headless) | Puppeteer (`headless: 'shell'`) | Playwright (default: headless shell) | Playwright (`channel: 'chromium'`) |
|---|---|---|---|---|
| Launch the browser | 246–315 | 118–137 | 43–61 | 90–98 |
| Open page (`load`) | 30–31 | 23–30 | 17–20 | 26–28 |
| Viewport screenshot | 66–72 | 60–61 | 48–50 | 46–56 |
| Full-page screenshot | 129–142 | 96–113 | 113–128 | 115–120 |
| A4 PDF | 34–38 | 13–16 | 6–8 | 22–23 |
| Element screenshot | 70–73 | 57–68 | 87–93 | 84–85 |
| **Whole job** | **324–365** | **257–280** | **272–291** | **287–304** |

What the table says:

- **Launch time is where they differ — and it is mostly the headless mode, not the library.** Playwright's default for headless Chromium is the separate `chromium-headless-shell` build, as its [browsers page](https://playwright.dev/docs/browsers) explains; Puppeteer's default is Chrome's new headless mode, which is the full browser. Put Puppeteer on the shell (`headless: 'shell'`) and its launch fell from ~300 to ~130 ms; put Playwright on the full browser (`channel: 'chromium'`) and its launch rose from ~50 to ~95 ms.
- **Per job, they are close.** With the same kind of headless browser, a whole job took 257–280 ms (Puppeteer shell) and 272–291 ms (Playwright shell). Playwright was faster at viewport screenshots and PDFs, Puppeteer at full-page and element screenshots.
- **If speed matters, reuse the browser.** A launch costs as much as a job or more; both libraries let you keep one browser open and open pages in it. Our [speed guide](https://shareglint.com/en/guides/speed-up-puppeteer-screenshots) measured that pattern in detail.

Outputs were essentially the same size: a 13.7 KB and a 13.2 KB viewport PNG, 29.7 and 29.2 KB full pages, 28.8 and 22.8 KB PDFs.

## The code, side by side

```javascript
// Puppeteer
import puppeteer from 'puppeteer';
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.setViewport({ width: 1280, height: 800 });
await page.goto(url, { waitUntil: 'load' });
await page.screenshot({ path: 'page.png', fullPage: true });
await (await page.$('ul')).screenshot({ path: 'list.png' });
await browser.close();
```

```javascript
// Playwright
import { chromium } from 'playwright';
const browser = await chromium.launch();
const page = await browser.newPage({ viewport: { width: 1280, height: 800 } });
await page.goto(url, { waitUntil: 'load' });
await page.screenshot({ path: 'page.png', fullPage: true });
await page.locator('ul').screenshot({ path: 'list.png' });
await browser.close();
```

These are the scripts we timed, minus the timers. Moving a script from one to the other is mostly renaming:

| Puppeteer | Playwright |
|---|---|
| `puppeteer.launch()` | `chromium.launch()` (or `firefox`, `webkit`) |
| `page.setViewport({ width, height })` | `browser.newPage({ viewport: { width, height } })` |
| `page.$(selector)` / `page.$$(selector)` | `page.locator(selector)` |
| `page.waitForSelector(selector)` | `page.locator(selector).waitFor()` |
| `page.evaluate(fn)` | `page.evaluate(fn)` |

The waiting model is the one change that needs thought: Playwright's locators wait on every action, so explicit waits copied over from Puppeteer can often be deleted.

## What actually differs

| | Puppeteer | Playwright |
|---|---|---|
| Languages | JavaScript / TypeScript | JavaScript / TypeScript, Python, Java, .NET |
| Browsers | Chrome, Firefox | Chromium, Firefox, WebKit |
| Default headless Chromium | New headless (full Chrome) | `chromium-headless-shell` |
| Waiting | `waitForSelector`, locators that wait, `waitUntil` | Auto-waiting actions and locators, `waitUntil` |
| Testing | Bring your own test runner | Playwright Test: runner, parallelism, `toHaveScreenshot` |

- **Languages.** Playwright's docs: it "is available in multiple languages that share the same underlying implementation", with all core features in each. Puppeteer is JavaScript only; in Python people use Playwright or the unofficial pyppeteer ([Python screenshots](https://shareglint.com/en/guides/screenshots-in-python-playwright-pyppeteer)).
- **Browsers.** WebKit — the engine behind Safari — is a common reason to pick Playwright: of the two, only it gets close to how a page renders in Safari. Puppeteer drives Firefox over WebDriver BiDi, with some features missing ([Puppeteer tutorial](https://shareglint.com/en/guides/puppeteer-tutorial)).
- **Waiting.** Playwright's [auto-waiting](https://playwright.dev/docs/actionability) runs "a range of actionability checks on the elements before making actions" and fails with a `TimeoutError` if they do not pass. Puppeteer's locators wait too, but most Puppeteer code still waits explicitly. Neither knows when *your* data has arrived; see [waiting for the page in Puppeteer](https://shareglint.com/en/guides/puppeteer-wait-for-page-load).
- **Testing.** Playwright Test, with screenshot comparison built in, is the strongest argument for Playwright in a test suite ([visual regression](https://shareglint.com/en/guides/visual-regression-screenshots)).

## Which to pick

- **Pick Puppeteer** if you work in Node.js, need only Chrome (screenshots, PDFs, scraping), and want the library maintained by the Chrome team. Use `headless: 'shell'` when start-up time matters.
- **Pick Playwright** if you need Python, Java or .NET, need WebKit or all three engines, or are writing tests and want the runner and screenshot assertions.
- **Keep what you have** if a working script already does the job: our numbers give no reason to rewrite it for speed.

## When to use neither

Both are libraries: you also run the browsers — containers, fonts, memory, crashes, updates. If the job is screenshots of public pages or images from HTML, our [screenshot API](https://shareglint.com/en/screenshot-api) and HTML templates do it in one HTTP request, from any language, with cookie banners hidden and full-page captures handled. For tests, pages behind a login and local development, Playwright or Puppeteer on your own machine remain the right tools.

## FAQ

### Is Playwright faster than Puppeteer?

For the work itself, barely: on our machine one job (load, screenshot, full page, PDF, element) took 272–304 ms in Playwright and 257–365 ms in Puppeteer. The big difference was launch time, and it came mostly from the default headless mode: Playwright starts the lighter chrome-headless-shell by default (43–61 ms), Puppeteer the full Chrome (246–315 ms), or 118–137 ms with headless: 'shell'.

### What is the main difference between Playwright and Puppeteer?

Playwright drives Chromium, Firefox and WebKit from JavaScript, Python, Java and .NET, and comes with a test runner with auto-waiting and screenshot assertions. Puppeteer is a JavaScript library from the Chrome team for Chrome and Firefox. For browser automation in Node.js both do the same jobs with very similar code.

### Should I switch from Puppeteer to Playwright?

Only for a reason: you need WebKit (Safari's engine), Python or Java, or Playwright's test runner with screenshot comparison. For an existing Puppeteer script that takes screenshots or PDFs in Chrome, a rewrite gains little.

### Which headless mode do Playwright and Puppeteer use?

Different ones by default. Puppeteer runs Chrome's new headless mode (the full browser) unless you pass headless: 'shell'. Playwright runs chromium-headless-shell for headless Chromium unless you choose the 'chromium' channel, which is the new headless mode.
