Headless browser vs real browser: the short answer
A headless browser is the same rendering engine running with no window: it still parses HTML, runs JavaScript, loads CSS and writes cookies to disk. A real browser is the visible application — tabs, address bar, toolbar, DevTools. That is the entire headless browser vs real browser distinction. Which one you want depends on whether your job is throughput or fidelity: headless for volume and CI, headed for anything a human would log into or judge by eye.
📌 TL;DR Executive Summary
- Core Takeaway: Since Chrome 112, headless mode is the real Chrome engine — but Playwright 1.57 still ships a separate chrome-headless-shell binary for headless runs, so the two modes are further apart in practice than the marketing suggests.
- Key Risk/Challenge: Headless CI runs miss OS-level variables (fonts, native controls, viewport, GPU paths, clipboard), and a fresh headless context re-authenticates on every run, so tests pass while logged-in account work fails.
- Recommended Solution: Run headless on every commit, confirm release candidates in a real headed browser, and use persistent isolated profiles with residential proxies for anything login-dependent or multi-account.
Here is the whole comparison in one table.
| Dimension | Headless (chrome-headless-shell / new headless) | Real headed browser | Send.win isolated profile |
|---|---|---|---|
| Window / GUI | None — no window, no tabs, no visible DevTools | Full app: tabs, toolbar, address bar, DevTools | Full Chromium engine — local desktop app or a cloud node |
| Speed and memory | Fastest: skips GUI rendering, uses less CPU and RAM | Heaviest per step | Not a speed play — it exists for identity and persistence |
| Rendering fidelity | Can diverge on fonts, viewport sizing, GPU/compositing, text wrapping, downloads, clipboard | Matches what a user actually sees | Same engine, with canvas, WebGL, audio, fonts and hardware spoofed at engine level |
| OS-level signals | A Linux container often exposes missing fonts, no native scrollbars, no date picker | Your real desktop OS, real fonts, real screen resolution | Profile-level OS, fonts and hardware kept coherent with the proxy’s exit IP |
| Session persistence | Fresh context each run unless you save storage state | Persistent profile directory — cookies, logins, extensions | Persistent profile with encrypted cloud sync on Pro and Team; shared profiles open already signed in |
| Detection surface | Automation flags plus environment gaps | Robot-speed behaviour still gets flagged | No two profiles share a fingerprint; timezone, locale, WebRTC and geolocation follow the proxy |
| CI fit | Native — no display server needed | Needs a desktop session or virtual display | Desktop app on Windows, macOS or Linux — or 10 free cloud minutes a day |
What actually changes at the engine level
For most of the last decade, “headless” meant a stripped-down fork of Chrome with no window layer at all. That changed with Chrome 112, when the new headless mode shipped as the real Chrome browser engine rather than a lighter implementation. On paper, the headless browser vs real browser gap closed.
In practice it reopened somewhere else. The old headless implementation still ships as a standalone binary called chrome-headless-shell, published through Chrome for Testing from Chrome 120 onward — the same channel that publishes versioned chrome, chromedriver and platform builds for Windows, macOS and Linux on x64 and arm64, with a JSON API you can query from a build script. As of October 2026 the stable channel sits at Chrome 155.0.8059.39.
Then Playwright 1.57 made the split explicit: headless runs launch chrome-headless-shell, headed runs launch the full chrome binary. The switch is no longer only a display toggle — it is a different executable. That is why code which behaves in CI and misbehaves on your laptop is so common. If you are new to the mode itself, this explanation of headless browser automation covers the mechanics before you go further.
Speed, memory and cost: where headless wins
Headless mode skips GUI rendering, so it uses less CPU and memory than a headed browser executing the same steps. One vendor comparison puts headless runs anywhere from 2x to 15x faster — treat that as a vendor figure rather than a benchmark, because the spread depends on whether your job is CPU-bound or waiting on the network. For a scraping loop that spends most of its time waiting for responses, the multiplier collapses toward 1x.
The bigger structural win is where headless can run. No display server and no desktop session means GitHub Actions, GitLab CI and Jenkins runners execute it directly. There is nothing to spin up, nothing to keep alive, and no virtual framebuffer to configure.
Real-browser grids invert that trade. Because screenshots and commands travel across a network, managed grids meter sessions and cost more per step than a local headless run. You are buying realism, the maintenance you avoid, and parallelism on demand — a fair purchase for release testing and an expensive one for a nightly scrape of ten thousand pages.
The rendering gaps that make headless tests pass and headed tests fail
Headless and headed can diverge on font availability, viewport sizing, GPU and compositing paths, text wrapping, and download or clipboard behaviour. In a Linux container you also lose OS-level variables a desktop browser exposes: native scrollbars, native form controls, date pickers, installed fonts and the actual screen resolution reported to the page.
Those are not cosmetic details. Text wrapping decides whether your layout assertion passes. Font fallback decides whether a button is 88px or 96px wide. Clipboard and download behaviour decides whether a file-open step silently no-ops. If your suite checks pixels, timing or file handling, a container headless run is measuring a slightly different browser than your users have.
Detection: headless is not a flag, headed is not a shield
The common assumption is that headless equals detectable and headed equals safe. Neither holds. Headless is not automatically detectable, and a headed browser driven at robot speed still gets flagged. What triggers scrutiny is the combination of automation flags your framework leaves in the page, the environment signals the browser reports, and the rhythm of your actions.
On the environment side, a headless run from a cloud container often reports a viewport no human has, fonts the OS does not ship, and a GPU string that does not match the platform. On the behaviour side, forms filled in milliseconds and clicks landing on exact pixel centres are more damning than any navigator.webdriver value. Sites read both, and the environment signals are usually the cheaper thing to fix. The techniques that actually move the needle are covered in this breakdown of headless browser detection bypass.
For multi-account work the calculus changes again. You are not trying to look like a generic human — you are trying to look like one specific, consistent machine across dozens of sessions. That is a fingerprint-coherence problem, and it is why spoofing canvas, WebGL, audio, fonts and hardware at the engine level beats injecting scripts that patch values after the page has already read them.
Sessions, logins and profile persistence
This is where the two modes stop being interchangeable. A headless run usually starts from a clean browser context. Cookies, localStorage and session tokens are gone the moment the process exits, unless you deliberately save and restore storage state. That is perfect for a test suite and painful for anything that requires a login.
A real headed browser keeps a profile directory. Logins survive restarts, extensions stay installed, and the site sees the same client it saw last week. If your work involves dashboards, seller accounts, ad managers or social platforms, that continuity is the whole ballgame — every re-authentication from a fresh context is a security event the platform may score against you.
Send.win takes the persistent-profile model and makes it portable. Each profile is a separate identity with its own stored logins, and encrypted cloud sync on Pro and Team carries those logins across devices. Sharing a profile with a paid teammate opens it already signed in — no password changes hands. The cloud browser runs those same logged-in sessions on Send.win’s cloud nodes with nothing to install, and every plan ships built-in residential proxies, so timezone, locale, WebRTC and geolocation follow the exit IP automatically.
launch_persistent_context(user_data_dir=...) so cookies and localStorage survive between runs — the same principle a real profile directory uses.
from playwright.sync_api import sync_playwright
CDP_URL = "http://127.0.0.1:PORT" # copy it from the profile's automation settings
with sync_playwright() as p:
browser = p.chromium.connect_over_cdp(CDP_URL)
context = browser.contexts[0]
page = context.pages[0] if context.pages else context.new_page()
page.goto("https://example.com")
print(page.title())
That attach-over-CDP pattern is what the local Automation API on the Team plan is for — it lets Selenium, Puppeteer and Playwright drive a profile that already carries its own fingerprint and logins, instead of launching a bare browser with neither.
Playwright, Puppeteer, Selenium and Cypress in 2026
All four mainstream tools run headless, and all four let you switch to headed. The differences matter at the edges.
| Tool | Engines | Mode switching | Where it fits |
|---|---|---|---|
| Playwright | Chromium, Firefox, WebKit | Headless by default; headless: false for headed. Since 1.57 headless uses chrome-headless-shell, headed uses the full chrome binary |
Cross-engine suites that need both modes from one config |
| Puppeteer | Chrome and Chromium via the Chrome DevTools Protocol | Headless by default, headed on a launch flag | Scraping, PDF generation, tight CDP-level control |
| Selenium | Browser-specific drivers, often via Grid | Browser-specific flags let existing suites run headlessly with minimal edits | Large legacy frameworks that cannot be rewritten |
| Cypress | Its own runner with a visual UI | cypress run executes headlessly for CI |
Fast regression suites where developers want the visual runner locally |
Playwright remains the common default for dual-mode cross-engine work, and it is the tool that made the binary split visible. Puppeteer is the tighter, narrower instrument: if you only care about Chrome and you want to talk to the DevTools Protocol directly, it gets out of your way. Selenium is the tool you keep when a suite already exists and the cheapest change is a launch flag. Options beyond the default set are covered in this roundup of headless Chrome alternatives.
from playwright.sync_api import sync_playwright
with sync_playwright() as p:
# Headless: fast, no window, the right default for every-commit CI runs
fast = p.chromium.launch(headless=True)
print(fast.version)
fast.close()
# Headed: the full chrome binary, what a user actually sees
visible = p.chromium.launch(headless=False)
page = visible.new_page()
page.goto("https://example.com")
print(page.title())
visible.close()
# Same installed Google Chrome build in both modes
pinned = p.chromium.launch(channel="chrome", headless=True)
print(pinned.version)
pinned.close()
What each option actually costs
Open-source frameworks are free; what you pay for is machines, sessions or identities.
| Option | Cost basis | Published price |
|---|---|---|
| Headless, self-managed | Open-source frameworks plus your own compute and CI minutes | No licence fee; you pay for infrastructure |
| Real headed browser, self-managed | A desktop or a VM with a display session | No licence fee; you pay for the machine and the maintenance |
| Managed real-browser cloud grid | Metered per session, per parallel and per device | Pricing varies by vendor; one major grid advertises 3,500+ real devices and OS combinations with guaranteed Day 0 access to new devices |
| Send.win | Per plan, with proxies and profiles included; add-ons metered | Free 30-day trial ($0 today, card required, continues on Pro after day 30) · Pro $19/mo or $6.99/mo billed annually ($83.88/yr) · Team $49/mo or $20.99/mo billed annually ($251.88/yr) · $6 per GB of proxy bandwidth · $0.05 per extra profile · 7-day money-back guarantee |
Read the third row closely, because it decides the case. A metered grid charges for realism per session — right when you validate a release twice a week, wrong when you hold forty logged-in accounts open all day. A per-profile model charges for identity instead: flat, predictable, and sized to how many accounts you actually run.
Honest pros and cons of every option
Headless browsing
- Pros: fastest and lightest per step, no display server needed, trivially parallel, free frameworks; ideal for scraping, PDF generation and regression checks.
- Cons: fresh context per run by default; diverges on fonts, viewport, GPU paths, clipboard and downloads; a Linux container reports environment signals no real desktop matches.
Automate Headless Browser Vs Real Browser With Send.win
Send.win pairs isolated, fingerprint-managed browser profiles with a full Automation API, so your scripts run in profiles that look and behave like real, separate users:
- Selenium, Puppeteer & Playwright support – drive any profile programmatically (Team plan)
- Isolated profiles – each with its own fingerprint, cookies, and storage
- Built-in residential proxies – with automatic timezone, locale, and WebRTC matching
- Desktop app for Windows, macOS & Linux – plus cloud sessions when you don’t want a local install
Try the instant cloud browser demo — no install, straight from your browser. Then compare plans: a 30-day free trial with no credit card, and paid plans from $6.99/month billed annually.
Real headed browser
- Pros: you see what the user sees; a persistent profile keeps logins and extensions; native controls, fonts and screen resolution are genuinely present; DevTools step-through debugging is something a headless run cannot give you.
- Cons: slowest and heaviest per step, needs a desktop session, hard to parallelise on one machine — and going headed fixes none of the behaviour signals that get automation flagged.
Managed real-browser cloud grids
- Pros: real browsers and devices with zero infrastructure to maintain; test videos, logs and parallel scaling on demand; device and OS combinations you do not own.
- Cons: metered cost that scales with every session and step; the vendors publishing these comparisons run the competing cloud, so read their benchmarks accordingly; you are working inside someone else’s browser profile, which is the wrong shape for account-level work.
Send.win isolated profiles
- Pros: persistent isolated identities with encrypted cloud sync on paid plans; residential proxies on every plan with timezone, locale, WebRTC and geolocation following the exit IP; engine-level fingerprint spoofing instead of patched scripts; profile sharing that opens already signed in; local Automation API for Selenium, Puppeteer and Playwright on Team.
- Cons: a headed environment, so it is not the tool for a nightly 100,000-page scrape; the Automation API is Team only, not Free or Pro; the desktop app needs a real install on Windows, macOS or Linux.
Which should you pick?
Use a decision rule, not a preference. Split your work into two buckets: checks that run constantly, and evidence that decides a release or protects an account.
| Your job | Pick this | Why |
|---|---|---|
| Smoke tests on every commit | Headless | Fast, no display server, cheap to parallelise in CI |
| Visual, download, clipboard or file-upload checks | Real headed browser | These are exactly where headless and headed diverge |
| Release-candidate sign-off | Real headed browser, or a managed real-device grid if you do not own the devices | You want the environment a customer has, not an approximation |
| Scraping public pages at volume | Headless — with the caveat that it is not detection-proof | Throughput is the goal and there is no session to keep |
| Anything behind a login | A persistent isolated browser profile | Re-authenticating from a clean context on every run is the failure mode |
| Running many accounts on one platform | Isolated profiles with residential proxies | Each identity needs its own coherent fingerprint and its own exit IP |
The workflow most teams land on is a funnel: headless on every commit, headed on the release candidate, persistent isolated profiles for the account work neither mode was designed for. If your question is really about where the run happens rather than whether a window exists, this comparison of headless browser vs cloud browser picks up where this one stops.
channel="chrome" and part of your detection problem turns out to be a build mismatch.
🏆 Send.win Verdict
Headless is the right answer to throughput and the wrong answer to identity. The moment your work involves a login, an account you care about, or the same platform twice, you need a persistent browser that reports a coherent machine — a different product category from an automation framework. Send.win is a headed, isolated profile environment: canvas, WebGL, audio, fonts and hardware spoofed at engine level, residential proxies on every plan, timezone, locale, WebRTC and geolocation following the proxy’s exit IP automatically, and profiles that stay logged in across restarts, devices and paid teammates. The local Automation API on Team means you can still drive those profiles with Selenium, Puppeteer or Playwright when you want code involved. It will not beat chrome-headless-shell on a 100,000-page scrape, and it should not try to — it is built for the jobs headless was never able to hold.
Try Send.win free today — 30 days, $0 today, cancel anytime, with 10 isolated profiles and built-in residential proxies to test your real-browser workflow against your headless one.
Frequently Asked Questions
Is a headless browser faster than a real browser?
Yes, consistently, because it skips GUI rendering and uses less CPU and memory for the same steps. Vendor comparisons quote anything from 2x to 15x, but the real gain depends on your workload: a job that mostly waits on network responses will not speed up anywhere near that much.
Can a website detect that I’m using a headless browser?
Not automatically, and not because of the mode itself. Detection comes from automation flags your framework leaves behind, environment signals that do not match a real desktop, and behaviour at robot speed. A headed browser driven the same way gets flagged just as fast.
Do headless and headed browsers render pages the same way?
Usually close, sometimes not. Font availability, viewport sizing, GPU and compositing paths, text wrapping, downloads and clipboard behaviour can all differ, and in a Linux container you also lose native scrollbars, form controls and date pickers.
Does headless mode still run JavaScript and load CSS?
Yes. A headless browser parses HTML, executes JavaScript, applies stylesheets and handles cookies and local storage exactly as a headed one does. The window layer is missing, not the rendering or scripting engine.
Is headless Chromium the same as real Chrome?
Since Chrome 112 the new headless mode runs the real Chrome engine rather than a separate lighter implementation. The old implementation still ships as a standalone binary, chrome-headless-shell, and Playwright 1.57 uses it by default for headless runs — so in practice the two modes can still be different executables.
Why do my tests pass headless but fail in a real browser?
Three usual causes: a rendering difference such as fonts or layout timing, a resource that loads faster in a container than on a real network, or an OS-level feature the container does not have. Re-run the same suite with the same binary in both modes before you change any test logic.
Can I run Selenium tests in headless mode?
Yes. Browser-specific flags let an existing suite run headlessly with minimal changes, which is why it is the cheapest migration for large legacy frameworks. You still need to run the suite headed before release, because headless will not tell you how the page looks.
When should I switch from headless to a real browser?
Switch for release candidates, anything visual, anything involving downloads or the clipboard, and any workflow behind a login. If the task needs a session to persist, a fresh headless context is the wrong starting point no matter how fast it is.