← All articles

Education

What Is a Headless Browser? Complete 2026 Guide

Daniel K. · May 10, 2026 · 9 min read


Quick verdict: A headless browser is a real web browser (Chrome, Firefox, Safari) running without a graphical window. Same JavaScript engine, same DOM, same network stack — you just cannot see the page. Used for testing (run E2E tests in CI), scraping (handle JavaScript-rendered sites), automation (fill forms, take screenshots, generate PDFs), and security research. Main tools in 2026: Playwright, Puppeteer, Selenium. Most scrapers should default to HTTP clients (requests, httpx) and only reach for headless when JavaScript rendering is required — headless browsers use 100-200x the memory of plain HTTP.

The Definition

A normal browser launches a GUI window, renders pages, and accepts user input. A headless browser does everything except the window:

From the destination server's perspective, a request from a headless Chrome looks identical to one from regular Chrome — same User-Agent, same TLS fingerprint, same HTTP/2 settings. Modern detection systems try to distinguish them via JavaScript checks (presence of WebDriver flag, navigator properties), but the network layer is identical.

Why Headless Browsers Exist

Three driving use cases:

1. Web Scraping (JavaScript-rendered pages)

Many modern sites are Single Page Applications — the initial HTML is mostly empty, content gets injected by JavaScript after page load. curl https://example.com returns the empty shell; a headless browser runs the JS and exposes the populated DOM.

Examples: React/Vue admin dashboards, Twitter feeds, Reddit listings, modern e-commerce sites.

2. Automated Testing

End-to-end tests need to simulate real user interactions in a real browser. Running browsers headlessly lets CI servers run tests without a display:

# GitHub Actions example
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: npx playwright test  # runs headless by default in CI

3. Automation Tasks

Anything that needs a real browser but is not a user-facing flow:

The 3 Main Tools in 2026

ToolMakerBrowsersLanguageBest for
PlaywrightMicrosoftChromium, Firefox, WebKitPython, Node, Java, .NETModern default; cross-browser
PuppeteerGoogleChromium (some Firefox)Node (community Python: pyppeteer)Chrome-specific work
SeleniumOpen sourceAll majorPython, Java, Ruby, C#, JSLegacy compatibility, broad browser support

Playwright is the modern default — cleaner API, faster, more reliable cross-browser support. Puppeteer is fine if you only need Chromium. Selenium is the legacy choice with the largest ecosystem but slower and clunkier than the alternatives.

Code Example: Playwright in Python

pip install playwright
python -m playwright install chromium
from playwright.sync_api import sync_playwright

with sync_playwright() as p:
    browser = p.chromium.launch(headless=True)
    page = browser.new_page()
    page.goto("https://example.com/spa-page")
    page.wait_for_selector("div.content-loaded")
    title = page.title()
    html = page.content()
    browser.close()

print(title)

That launches headless Chromium, navigates to a SPA, waits for client-side content to render, then captures the title and HTML. Same code works headed by passing headless=False — useful for debugging.

The Cost: Memory + Speed

Headless browsers are 100-200x heavier than HTTP clients:

ApproachMemory per requestPages/second per worker
Plain Python requests~2 MB100+ (network-bound)
aiohttp / httpx async~2 MB500+ (concurrent)
curl_cffi (TLS-impersonated requests)~3 MB100+
Headless Chrome via Playwright~250 MB1-2 (CPU-bound)
Headless Firefox via Playwright~300 MB1-2

The takeaway: only use a headless browser when JavaScript rendering is REQUIRED. For static HTML, plain HTTP wins by orders of magnitude.

When You Do NOT Need Headless

Many scrapers reach for Playwright by default. Often the right answer is "spend 30 min in DevTools finding the real endpoint and use plain HTTP" — faster, lighter, and more resilient.

When You DO Need Headless

Headless + Proxies

Most scraping with headless browsers needs proxies:

browser = p.chromium.launch(
    headless=True,
    proxy={
        "server": "http://gw.spyderproxy.com:8000",
        "username": "USER",
        "password": "PASS",
    },
)

For sites with strong anti-bot, Premium Residential ($2.75/GB) is the default. For account-based workflows, LTE Mobile ($2/IP) has the lowest detection rate. Plain datacenter IPs are blocked instantly by most sites that justify a headless browser in the first place.

Headless Browser Detection

Modern anti-bot systems try to distinguish headless from regular browsers:

For tough targets, use playwright-stealth, undetected-chromedriver (Selenium fork), or pair with an antidetect browser for maximum stealth.

Related: Headless browser in Python, Cheerio vs Puppeteer, Puppeteer vs Playwright vs Selenium.

Try it yourself from $1.75/GB

See residential proxies ↗Start now ↗