Headless Chrome is Google Chrome, or Chromium, running without a visible window under the control of a program, used to render pages for screenshots, PDFs, tests and scraping.
Chrome added a headless mode in version 59, in 2017, and it replaced PhantomJS as the default engine for screenshot tools within a year or two. Today "headless Chrome" can mean two different programs, and the difference shows up in your screenshots. This entry is part of the screenshot and rendering glossary. For the general idea, start with headless browser.
A plain explanation
There are two ways to run Chrome headless:
- New headless (
--headless). The full Chrome binary, with the window turned off. It shares its code with the Chrome on your desktop, so pages behave the same. Chrome introduced it in version 112 and made it the meaning of--headlesslater. - Headless shell (
chrome-headless-shell). A separate, slimmer binary that keeps the original headless implementation. Since Chrome 132 the old mode is no longer in the main Chrome binary and ships only as this shell.
Neither one is "better". New headless is closer to what visitors see. The shell is smaller and starts fast, which is why some test tools default to it.
What a page can see in each mode
We started both modes from Puppeteer 24.43.1 with Chrome 148 and read a few values from inside a page. We also checked Playwright 1.64.1's two Chromium options.
| Setup | Version string the browser reports | navigator.userAgent token |
navigator.webdriver |
navigator.plugins.length |
|---|---|---|---|---|
Puppeteer headless: true (new headless) |
Chrome/148.0.7778.97 |
HeadlessChrome/148.0.0.0 |
true |
5 |
Puppeteer headless: 'shell' |
HeadlessChrome/148.0.7778.97 |
HeadlessChrome/148.0.7778.97 |
true |
0 |
Playwright default chromium.launch() |
156.0.8078.4 |
HeadlessChrome/156.0.8078.4 |
n/a | n/a |
Playwright channel: 'chromium' |
156.0.8078.4 |
HeadlessChrome/156.0.0.0 |
n/a | n/a |
New headless reports a reduced version (.0.0.0) in the user agent, like desktop Chrome does, and exposes the usual PDF viewer plugins. The shell reports the full build number and no plugins. Both keep the HeadlessChrome token, and both set navigator.webdriver under automation, so neither mode is invisible to bot detection.
One first-hand note from writing this page: on our test Mac, Page.captureScreenshot timed out in new headless with Puppeteer while the shell captured the same page in 51 ms. We have not isolated the cause. If screenshots hang only in one mode, try the other before you change anything else.
How it works technically
Headless Chrome runs the normal multi-process architecture: a browser process and one renderer process per site, plus GPU and network services. Without a window, frames are composited into an offscreen surface. Automation libraries connect over the Chrome DevTools Protocol, either through a WebSocket (--remote-debugging-port) or a pipe, and send commands such as Page.navigate and Page.captureScreenshot.
How to choose and use it in Puppeteer, Playwright and RenderScreenshot
Puppeteer. headless: true is new headless. headless: 'shell' uses chrome-headless-shell, which npx puppeteer browsers install chrome-headless-shell downloads. This script prints the table rows above.
import puppeteer from 'puppeteer'; for (const headless of [true, 'shell']) { const browser = await puppeteer.launch({ headless }); try { const page = await browser.newPage(); await page.goto('data:text/html,<title>t</title>'); const seen = await page.evaluate(() => ({ userAgent: navigator.userAgent, webdriver: navigator.webdriver, plugins: navigator.plugins.length, })); console.log({ headless, binary: await browser.version(), ...seen }); } finally { await browser.close(); } }
Playwright. Headless Chromium uses the shell by default. Pass channel: 'chromium' to get new headless.
import { chromium } from 'playwright'; for (const options of [{}, { channel: 'chromium' }]) { const browser = await chromium.launch(options); try { const page = await browser.newPage(); const ua = await page.evaluate(() => navigator.userAgent); console.log(JSON.stringify(options), '->', ua.match(/HeadlessChrome\/[\d.]+|Chrome\/[\d.]+/)[0]); } finally { await browser.close(); } }
Command line. No library needed for a one-off capture. With the shell binary:
chrome-headless-shell --screenshot=page.png --window-size=1280,800 --hide-scrollbars https://example.com
With the full Chrome binary, add --headless. On macOS the binary is inside the app bundle, for example "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome".
chrome --headless --screenshot=page.png --window-size=1280,800 --hide-scrollbars https://example.com
The command-line screenshot guide covers the other flags.
RenderScreenshot. We run headless Chromium on Cloudflare's Browser Rendering platform, so you do not choose a mode, download binaries or track Chrome releases. You choose the result: viewport, wait condition, colour scheme and output format.
curl --get https://api.renderscreenshot.com/v1/screenshot \ -H "Authorization: Bearer $RS_API_KEY" \ --data-urlencode 'url=https://example.com' \ -d width=1280 -d height=800 -d dark_mode=false \ --output page.png
Tested on 2026-10-15 with Node 22.18, Puppeteer 24.43.1 (Chrome and chrome-headless-shell 148.0.7778.97) and Playwright 1.64.1 (Chromium 156.0.8078.4). The chrome-headless-shell command wrote a 79,353-byte PNG. The full-Chrome --headless command and the curl request were not run for this page.
Common mistakes
- Mixing modes between environments. A baseline from the shell and a check from new headless differ in fonts, colour scheme and plugins. Pin the mode with the version.
- Inheriting the host's dark mode. New headless can follow the operating system's appearance. Set the colour scheme explicitly.
- Using old flags.
--headless=oldno longer exists in recent Chrome. Installchrome-headless-shellinstead. - Running as root without a sandbox plan. In containers, prefer a non-root user to adding
--no-sandbox.
Related terms
- Headless browser: the general concept and the other engines.
- Puppeteer: Google's library for driving Chrome.
- Playwright: Microsoft's library, with its own Chromium builds.
- Device pixel ratio: one of the settings to pin with the mode.
For the measured difference between headless and a real window, read headless vs headful Chrome. To use headless Chrome without running it, get a free API key.