ScreenshotNeo

BlogGuides

What Is a Headless Browser? A Guide for Developers

A headless browser runs without a visible user interface. Learn how Chrome’s modes differ, when to use Playwright, Puppeteer, or Selenium, and how to capture pages.

By the ScreenshotNeo team4 October 202611 min read

A headless browser runs a browser engine without displaying its normal user interface. Developers control it with command-line options or automation libraries to render pages, take screenshots, generate PDFs, run tests, and perform other browser tasks unattended.

“Headless” describes how the browser runs; it does not necessarily mean a separate or reduced browser implementation. Current Chrome Headless shares Chrome’s implementation with headful Chrome. The older Chrome Headless implementation is now a separate chrome-headless-shell binary. Headless mode also does not make automation invisible to websites or bypass access controls.

For browser automation, choose a tool and mode based on the browsers you need to cover, how closely your tests must match a branded browser, and whether the separate headless shell has the features your task requires.

What is a headless browser?

A normal browser presents a visible window with tabs, menus, an address bar, and page content. A headless browser performs browser work without showing that window. The browser still loads and renders pages, executes JavaScript, and can respond to automation commands. [Chrome Headless mode]

You can run a headless browser from a terminal or control it from code. For example, an automation script can open a page, wait for content, check an element, and save a screenshot without anyone interacting with a visible browser window.

Headless mode is not a promise that every detail matches every visible browser session. Browser build, mode, version, operating system, fonts, GPU support, and automation setup can affect behavior. It is also not a stealth feature: a site can still apply its ordinary access controls and bot checks.

What is a headless browser used for?

  • Automated testing: Load a page, exercise interactions, and check visible results or page state in a repeatable run.
  • Screenshot capture: Render a page or selected element to an image for visual review, documentation, or previews.
  • PDF generation: Render web content and save it as a PDF.
  • Web automation: Perform permitted browser actions such as navigating pages, filling forms, and collecting information you are authorized to access.
  • Continuous integration: Run browser checks in a build pipeline or other environment without a desktop session.

The appropriate setup depends on what you are automating. A screenshot task may need stable fonts, viewport and wait conditions. A cross-browser test needs the target browser engines. A production workflow may also need explicit timeouts, error handling, and limits on concurrency.

How is headless Chrome different from normal Chrome?

In current Chrome, Headless mode is unified with the headful Chrome implementation. Starting with Chrome 112, Headless creates platform windows without displaying them; other Chrome functionality remains available. Since Chrome 132.0.6793.0, the older Headless implementation is available as the separate chrome-headless-shell binary. [Chrome Headless mode]

Mode What it is When to consider it
Headful Chrome Chrome with its normal visible user interface. Manual debugging, interactive use, or checks that specifically require a visible browser.
Unified Chrome Headless Chrome’s current implementation running without visible UI. Automation that should use Chrome’s current browser implementation while running unattended.
chrome-headless-shell The older Headless implementation distributed as a separate binary. Automation that does not need the complete Chrome feature set and can use the shell’s narrower behavior.

Puppeteer describes chrome-headless-shell as not completely matching regular Chrome and says it can be more performant for automation that does not need the complete Chrome feature set. That is a task-specific trade-off, not a general speed guarantee. [Puppeteer Headless modes]

Run Chrome Headless from the command line

Chrome documents --headless for running Chrome without visible UI. This example opens a page and saves a screenshot. The exact Chrome executable name or path depends on how Chrome is installed on your system. [Chrome Headless mode]

google-chrome --headless --screenshot=page.png https://example.com

To print a page to PDF, use Chrome’s headless printing option:

google-chrome --headless --print-to-pdf=page.pdf https://example.com

These are command-line examples, not a substitute for controlling readiness in a complex page. A page may render asynchronously, require authentication, or display content only after an interaction. Use an automation library when you need to wait for a selector, interact with the page, inspect errors, or manage browser lifecycle.

Choose an automation library

There is no universally best framework in the source material. Compare the documented browser coverage, the browser build and mode used, and how well the tool fits your existing project.

Tool Documented browser choices Headless detail Good fit when
Playwright Chromium, Firefox, WebKit; also documents branded Chrome and Edge channels. Its default headless Chromium route uses a separate headless shell. Its docs describe opting into new Headless with the chromium channel. You need documented multi-engine browser projects or want to test branded Chrome or Edge channels.
Puppeteer Its headless guide centers on Chrome and Chrome Headless Shell. headless: true is the default; headless: 'shell' selects the separate shell. Your automation is centered on Chrome and the Puppeteer API fits your project.
Selenium The cited project material covers Firefox and Chromium-based browsers. Headless is selected through browser options or arguments; check current browser and Selenium documentation for the exact API. Your project already uses Selenium or requires its browser automation setup.

References: Playwright browser documentation, Puppeteer Headless modes, and Selenium’s headless-mode background. Selenium’s cited post dates from 2023, so verify current flags and APIs against current Selenium and browser documentation.

Runnable examples

Playwright with Node.js

Install Playwright and its Chromium browser in a Node.js project:

npm install playwright
npx playwright install chromium

Save as capture.mjs and run with node capture.mjs. Playwright launches headless by default. This example sets a viewport, navigates, waits for the document load event, and saves a full-page screenshot.

import { chromium } from 'playwright';

const browser = await chromium.launch({ headless: true });
try {
  const page = await browser.newPage({ viewport: { width: 1440, height: 900 } });
  await page.goto('https://example.com', { waitUntil: 'load', timeout: 30_000 });
  await page.screenshot({ path: 'page.png', fullPage: true });
} finally {
  await browser.close();
}

To opt into Chrome’s new Headless mode in Playwright, its browser documentation shows the chromium channel. That route and Playwright’s default Chromium headless shell can differ in some cases. [Playwright browser documentation]

const browser = await chromium.launch({ channel: 'chromium', headless: true });

Puppeteer with Node.js

Install Puppeteer, which downloads a compatible browser as part of its installation workflow:

npm install puppeteer

Save as capture-puppeteer.mjs and run node capture-puppeteer.mjs. Puppeteer’s current default is Headless mode.

import puppeteer from 'puppeteer';

const browser = await puppeteer.launch({ headless: true });
try {
  const page = await browser.newPage();
  await page.setViewport({ width: 1440, height: 900 });
  await page.goto('https://example.com', { waitUntil: 'load', timeout: 30_000 });
  await page.screenshot({ path: 'page.png', fullPage: true });
} finally {
  await browser.close();
}

To use the separate shell when it is available, Puppeteer documents headless: 'shell'. Confirm that the shell’s feature set and behavior suit the page you need to automate. [Puppeteer Headless modes]

const browser = await puppeteer.launch({ headless: 'shell' });

Selenium with Python

Install Selenium with Python:

python -m pip install selenium

Save as capture_selenium.py and run python capture_selenium.py. Selenium’s Chrome options pass the headless argument to the browser. Browser and driver setup can depend on your Selenium and Chrome versions; consult current Selenium documentation for installation and configuration details.

from selenium import webdriver
from selenium.webdriver.chrome.options import Options

options = Options()
options.add_argument('--headless')
options.add_argument('--window-size=1440,900')

driver = webdriver.Chrome(options=options)
try:
    driver.set_page_load_timeout(30)
    driver.get('https://example.com')
    driver.save_screenshot('page.png')
finally:
    driver.quit()

This Selenium example saves the current viewport. Full-page screenshot support varies by browser and driver; if you need a full-page capture, confirm the supported API for your chosen browser or use a framework with a documented full-page screenshot option.

cURL for a direct headless Chrome run

cURL itself is not a browser automation library. It can download a Chrome binary or call a browser service, but it cannot make a headless browser render a page on its own. For a command-line Chrome capture, invoke Chrome directly as shown above.

Configure reliable captures and tests

  • Set a viewport: Define width and height explicitly so responsive layouts render consistently.
  • Choose a readiness condition: A document load event may be enough for a simple page. JavaScript-heavy pages may need a selector or a page-specific condition. Avoid relying on a fixed sleep when a meaningful condition is available.
  • Set timeouts: Give navigation and application readiness finite limits so stalled pages do not hang a job indefinitely.
  • Close the browser: Use cleanup logic such as finally so browser processes are released after errors.
  • Pin versions in repeatable jobs: Keep framework and browser versions controlled in CI, and update them deliberately.
  • Match the target browser: If the issue occurs in branded Chrome or Edge, test the relevant channel instead of assuming a bundled Chromium build behaves identically.
  • Use explicit test data and state: Control cookies, storage, locale, and authentication where the task requires them; avoid sharing mutable sessions across unrelated jobs.

Playwright’s documentation specifically cautions that its default Chromium headless shell can differ from Chrome or Edge’s new Headless mode. Use the browser build that answers the question your test is intended to answer. [Playwright browser documentation]

Or skip the browser setup

If your goal is a website screenshot rather than browser automation, ScreenshotNeo is a website screenshot API and MCP server. One GET request returns a PNG, JPEG, WebP, or PDF. It can accept cookie consent and remove more than 60 known consent platforms, newsletter popups, and chat widgets before capture; each step can be turned off. Bot checks, blank pages, timeouts, failed loads, and cache hits cost nothing, and response headers report the page verdict and billing status.

cURL:

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://example.com -o shot.webp

Python:

import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://example.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)

Node.js:

const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://example.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`);
await import('node:fs/promises').then(fs => fs.writeFile('shot.webp', Buffer.from(await res.arrayBuffer())));

See the ScreenshotNeo API documentation for request options. The API also supports full-page and element captures, device presets, custom waits and scripts, PDF output, caching, asynchronous jobs, and bulk capture. Its MCP server provides take_screenshot, get_page_info, and capture_pdf for AI agents. The free plan includes 1,000 shots a month with no card; paid plans start at $5 for 3,000 shots.

Sign up for 1,000 free screenshots a month, with no card required.

Troubleshooting

Symptom Likely cause What to try
Chrome or the driver cannot be found The browser is missing, not on the expected path, or incompatible with the automation setup. Install the browser required by your framework and follow its current browser or driver setup instructions. Check the executable path and version compatibility.
The page is blank or the screenshot is incomplete Capture happened before client-rendered content appeared, navigation failed, or the site intentionally serves a different response. Check navigation status and browser logs. Wait for a page-specific selector or readiness condition, and verify the URL in a visible browser where appropriate.
Navigation times out The site is slow, blocked, waiting on long-running requests, or unreachable from the execution environment. Check connectivity and permissions, set an appropriate finite timeout, and use a readiness condition that matches the task rather than waiting for every request to finish.
Layout differs from a local visible browser Viewport, fonts, device scale, browser build, or headless mode differs. Set viewport and scale explicitly, install required fonts, and compare the same browser channel and version. Playwright documents differences between the default headless shell and new Chrome or Edge Headless.
Element is missing in a test The selector is wrong, content has not rendered, or the element is inside a frame or shadow root. Inspect the page structure, wait for the correct selector, and use the framework’s frame or shadow DOM APIs when relevant.
Automation is rejected or challenged The site applies bot checks or access controls. Use an authorized integration or request access from the site owner. Headless mode is not a way to bypass those controls.
Browser processes accumulate after failures Cleanup is skipped when an exception occurs. Close pages and browsers in a guaranteed cleanup path such as Python finally or JavaScript finally.

Performance, reliability, and cost

Headless execution removes the need to display a normal browser interface, which makes it practical for unattended jobs. It does not establish a universal performance advantage over headful browsing. Puppeteer describes its shell mode as potentially more performant for automation that does not require Chrome’s complete feature set; measure your own workload if execution time matters. [Puppeteer Headless modes]

For reliability, control browser versions, set explicit timeouts, wait for application-specific readiness, collect useful browser errors, and always release processes. Parallel jobs can improve throughput but also consume more CPU and memory and can increase load on the target site. Set concurrency according to your machine, the site’s rules, and your workload.

Frameworks and browser binaries are software dependencies; their operational cost includes the machines and engineering time needed to install, update, run, and debug them. A screenshot API can reduce browser setup for screenshot-only workflows, but has its own plan limits and request behavior. ScreenshotNeo offers 1,000 shots per month free with no card, then plans from $5 for 3,000; every feature is available on every plan. Review current terms and options in its documentation.

Frequently asked questions

Does headless mean the browser is invisible to a website?

No. It means the browser has no visible user interface for the person running it. It does not guarantee that a website cannot recognize automation or apply access controls.

Is Chrome Headless a different browser from Chrome?

Current Chrome Headless shares Chrome’s implementation. The older Headless implementation is available separately as chrome-headless-shell from Chrome 132.0.6793.0 onward.

Is Playwright’s headless Chromium the same as Chrome Headless?

Playwright’s default headless Chromium route uses a separate headless shell. Its docs explain how to opt into new Headless with the chromium channel and note that behavior can differ.

Which framework should I choose?

Choose based on browser coverage, browser fidelity needs, and compatibility with your project. The documented options do not establish one framework as universally best.

Can I use headless mode to generate a PDF?

Yes. Chrome’s command line includes --print-to-pdf, and browser automation libraries can also drive print or PDF workflows where supported.