2026 · Novus Stream SolutionsAbout 8 min readNovus Stream Solutions
Why Playwright ships its own Chromium instead of using your Chrome
Installing Playwright downloads a browser even though you already have one. That is deliberate: a pinned Chromium build makes tests reproducible in a way an auto-updating Chrome cannot. But Chromium is not Chrome, headless is not headed, and WebGPU sits right on the fault line between them.
Advertisement
Contents
Overview
Install Playwright and the first thing it does is download a browser. On this machine that meant about 115 MB of Chromium landing in a cache directory, on a laptop that already had Chrome, Edge, and Firefox installed. It looks wasteful, and it is one of the more common questions people ask when they first add browser testing to a project.
It is not wasteful, and the reasoning behind it explains a fair amount about what browser automation can and cannot do — particularly around GPU-backed features like WebGPU, which is where the abstraction gets thin.
What actually gets installed
Playwright pins browser builds to Playwright releases. Each version of the library knows exactly which Chromium, Firefox, and WebKit revisions it was tested against, and `npx playwright install` fetches those specific builds into a shared cache — on Windows that is under `%LOCALAPPDATA%\ms-playwright`, on macOS `~/Library/Caches/ms-playwright`, on Linux `~/.cache/ms-playwright`.
Looking in that directory on a machine that has been through a few upgrades is instructive. Ours holds several numbered Chromium revisions side by side, a matching `chromium_headless_shell` for each, a WebKit build, and a bundled `ffmpeg` used for video recording. Nothing there is the browser you browse with. They are versioned artifacts that belong to the test runner.
That is also why old revisions accumulate: each Playwright upgrade pulls a new pinned build and leaves the previous one in place, so a project pinned to an older Playwright still works. `npx playwright uninstall --all` clears them out when the disk starts to notice.
- Builds are pinned per Playwright release, not per machine.
- They live in a shared cache, separate from any installed browser.
- Multiple revisions coexist so older projects keep working.
- A bundled ffmpeg handles video recording, so that is not a system dependency either.
Advertisement
The actual reason: your Chrome will not hold still
Chrome auto-updates. That is excellent for users and hostile to a test suite. A run that passed on Tuesday and fails on Thursday, on a codebase nobody touched, is the least useful kind of failure — and if the browser silently moved underneath you, that is exactly what you get.
Pinning removes that variable. A given Playwright version runs the same browser build on your laptop, on your colleague's, and in CI, this month and next year. When a test starts failing, the browser is one of the few things you can rule out immediately, which is worth a great deal when you are trying to work out what broke.
There is a second, less discussed reason: Playwright needs capabilities that a stock browser does not necessarily expose in the way it wants. The bundled builds are produced with the automation surface the library depends on, and shipping them removes an entire class of "works on my machine because my Chrome is configured differently" problems.
But it can drive real Chrome, and sometimes should
The bundled build is a default, not a limitation. Playwright can drive the branded browser already installed on the machine by setting a channel — `channel: 'chrome'` for Google Chrome, `'msedge'` for Edge, plus beta and dev variants. It launches the real thing rather than the pinned build.
The case for doing that is compatibility testing. If what you need to know is "does this work in the browser our users actually have", then testing against the browser our users actually have is the honest answer, and the reproducibility argument loses to the realism argument.
A reasonable split, and the one most teams land on: pinned Chromium for the everyday suite where determinism matters most, and a smaller branded-channel run for the things where the difference between Chromium and Chrome is the point.
Chromium is not Chrome
It is worth being precise about the relationship, because "Chrome is just Chromium with a logo" is a common and slightly wrong summary. Chromium is the open-source project. Chrome is Google's distribution built on top of it, and the additions are not only cosmetic.
The differences that actually affect testing are media and DRM. Chrome licenses proprietary codecs — H.264/AVC and AAC being the ones people hit most — and ships the Widevine content decryption module for DRM-protected playback. Open-source Chromium builds do not universally include those, which means a test that plays an H.264 MP4 can pass in Chrome and fail in a bundled Chromium for reasons that have nothing to do with your code.
Beyond that, Chrome adds Google API keys and account sync, auto-update machinery, crash and usage reporting, and branding. None of those matter to a test suite. The codecs frequently do, and it is the single most common reason to reach for the branded channel.
- Proprietary codecs (H.264, AAC) — licensed in Chrome, not guaranteed in Chromium builds.
- Widevine DRM — Chrome only; protected playback will not work in a plain Chromium.
- Google account sync, API keys, auto-update, crash reporting — Chrome only, irrelevant to tests.
- Everything else — rendering, JavaScript, layout, the DOM — is the same engine.
Headless is a third thing again
The Chromium-versus-Chrome axis is the one people know about. The headless-versus-headed axis catches more people out, and Playwright installs a separate binary for it: alongside each Chromium revision sits a `chromium_headless_shell`. That is a build optimised for running without a display, and it is smaller and faster to start than driving a full browser in headless mode.
Chrome also has a "new headless" mode, where the ordinary browser binary runs without a visible window. The distinction matters because the two are not equivalent: a dedicated headless shell trades fidelity for speed, while the browser running headless is the browser. If a bug reproduces headed and vanishes headless, that difference is usually where the answer is.
The practical advice is to know which one your configuration is using rather than to prefer one universally. Fast feedback wants the shell. Anything that depends on real browser behaviour — and especially anything touching the GPU — wants the full browser, headed if you can manage it.
WebGPU: where the abstraction gets thin
This is the part that matters most for the apps in this portfolio, because several of them lean on the GPU. The Background Remover runs its matting models through WebGPU with a WebAssembly fallback. Novus Visualizers renders through Canvas and WebGL via Three.js and exports with WebCodecs. Those are exactly the features that behave differently — or simply do not exist — inside a headless test browser.
The reason is structural rather than a Playwright shortcoming. WebGPU needs an adapter, an adapter needs a GPU and a working driver, and a headless CI container typically has neither. `navigator.gpu.requestAdapter()` returning `null` in that environment is not a bug; it is an accurate report that there is nothing to adapt to. Chromium can fall back to a software backend, but that has to be deliberately enabled with launch flags and it is slow enough that it changes what a timing-sensitive test means.
A related trap: the presence of `navigator.gpu` tells you the API exists, not that an adapter can be acquired. Feature-detecting on the object and then assuming a device is available is a mistake that shows up in production too, on machines with blocklisted drivers. The correct check is to request an adapter and handle `null` — which is worth writing regardless of testing, because real users hit it.
- Headless environments usually have no GPU, so no adapter is available.
- Software fallback exists but must be enabled with flags, and it is slow.
- Check `requestAdapter()` for null, not just `navigator.gpu` for existence.
- Timing-sensitive GPU assertions are the least portable tests you can write.
What we test instead
The pragmatic answer is to stop trying to assert on GPU output in CI and test the things around it. Does the page load and mount the right components? Does the fallback path engage when no adapter is available — and is the fallback correct, given that plenty of real users will take it? Does the interface report an unsupported environment honestly rather than hanging?
That last one is not a consolation prize. An app that says "your browser cannot do this" is behaving well; an app that spins forever because it assumed an adapter is behaving badly, and the no-GPU headless environment is the cheapest possible way to catch the difference. The constraint that makes GPU output untestable is the same constraint that makes the degraded path easy to exercise.
For anything where the actual rendered pixels matter, the honest options are a headed run on real hardware, a self-hosted runner with a GPU, or a human looking at it. Pretending a software rasterizer in a container proves the WebGPU path works is worse than admitting the gap.
The short version
Playwright bundles Chromium so that the browser is a fixed, known quantity rather than a moving one — which is the whole point of a test. It can drive your real Chrome when realism matters more than repeatability, and it is worth using both. Chromium differs from Chrome mainly in proprietary codecs and DRM, which is a real difference if you test video and irrelevant otherwise.
And GPU features remain genuinely hard to put under automated test, because the thing they depend on is not present in the environments where automated tests like to run. That is not a tooling failure so much as an accurate reflection of the fact that a GPU is hardware, and CI is a container.
Frequently asked questions
Quick answers to common questions about this topic.
Why does Playwright download a browser when I already have Chrome?
Because your Chrome auto-updates and a test suite needs the browser to hold still. Playwright pins a specific Chromium build per release, so the same test runs against the same browser on every machine and in CI, this month and next year.
Can Playwright use my installed Chrome instead?
Yes. Set a channel — `channel: 'chrome'`, or `'msedge'` for Edge, plus beta and dev variants — and it launches the branded browser already on the machine. Useful when compatibility with what users actually run matters more than reproducibility.
What does Chrome have that Chromium does not?
Licensed proprietary codecs (notably H.264 and AAC), the Widevine module for DRM playback, Google account sync and API keys, auto-update, crash reporting, and branding. The rendering engine, JavaScript engine, layout, and DOM are the same.
What is the chromium_headless_shell binary for?
It is a build optimised for running without a display — smaller and faster to start than driving the full browser headless. It trades some fidelity for speed, which is why a bug that reproduces headed and vanishes headless is often explained by which binary was used.
Can I test WebGPU in headless Playwright?
Usually not meaningfully. WebGPU needs an adapter, an adapter needs a GPU and driver, and headless CI containers generally have neither, so `requestAdapter()` returns null. A software backend can be enabled with launch flags but is slow enough to distort timing-sensitive tests. Test the fallback path and the unsupported-environment messaging instead, and use headed runs on real hardware when the pixels matter.
How do I clear out old Playwright browser builds?
`npx playwright uninstall --all` removes the cached builds. They accumulate because each upgrade fetches a new pinned revision and leaves the old one, so projects pinned to an older Playwright keep working.
Advertisement
Published by
Novus Stream Solutions
Free Apps · Better Features
Novus Stream Solutions builds free apps that rival paid alternatives. We publish practical guides, product updates, and field notes from the NSS Background Remover, Novus Visualizers, Novus PDF Studio, and Novus Convert.
About us →Share this post