ChromeHeadless is the single most commonly used browser configuration in modern Karma setups. This lesson goes deeper into exactly how it behaves and how to configure it reliably for CI.
What Headless Chrome Actually Is
Headless Chrome is the real Chrome rendering and JavaScript engine, running without ever drawing a visible window. It's not a separate, lighter-weight browser — it's the same engine your users run, minus the GUI overhead, which is exactly why it's trusted for accurate test results in CI environments with no display server.
--no-sandbox is required in most Docker/container CI runners.
--disable-dev-shm-usage avoids crashes tied to a small /dev/shm in constrained containers.
--disable-gpu avoids issues on machines without a usable GPU driver.
--disable-extensions guarantees a clean, extension-free environment, matching most CI expectations.
ChromeHeadless Flags Cheat Sheet
The flags you'll reach for most often when tuning headless Chrome for CI.
Flag
Why You'd Add It
--no-sandbox
Required in most containerized CI runners
--disable-gpu
Avoids GPU driver issues on headless machines
--disable-dev-shm-usage
Prevents crashes from small shared memory in containers
--disable-extensions
Ensures a clean, predictable browser environment
--window-size=1280,720
Sets a consistent viewport for layout-sensitive tests
--remote-debugging-port=9222
Enables attaching devtools to the headless instance
Headless vs. Visible Chrome: What Actually Differs
For the overwhelming majority of tests, ChromeHeadless and Chrome produce identical results, since they share the same rendering engine. The differences that do exist are narrow: headless mode has no visible window (so tests relying on actual OS-level focus/visibility behavior can differ), and some GPU-accelerated rendering paths behave slightly differently.
Both use the exact same Blink rendering engine and V8 JavaScript engine.
Headless mode has no real OS window, which can affect document.hasFocus()-style assertions.
Visible Chrome is primarily useful for local debugging with real devtools attached.
For CI, headless is strongly preferred for speed and compatibility with display-less machines.
Attaching DevTools to a Headless Instance
Because headless Chrome exposes a remote debugging protocol, you can attach real Chrome DevTools to it even without a visible window — useful when a CI-only failure needs deeper investigation than console logging alone provides.
customLaunchers: {
ChromeHeadlessDebug: {
base: 'ChromeHeadless',
flags: ['--remote-debugging-port=9222']
}
}
// Then open chrome://inspect in a local Chrome browser
// and connect to the remote debugging port.
Common Mistakes
Assuming headless and visible Chrome are two entirely different browsers with different bugs, rather than the same engine.
Not adding container-safe flags (--no-sandbox, --disable-dev-shm-usage) before running in Docker-based CI.
Debugging a CI-only failure purely by guesswork instead of attaching devtools via remote debugging.
Setting an inconsistent viewport size across environments, causing layout-dependent tests to behave differently.
Key Takeaways
ChromeHeadless runs the real Chrome engine without a visible window — it's not a separate, lesser browser.
Container-safe flags like --no-sandbox and --disable-dev-shm-usage are essential for Docker-based CI.
Remote debugging can attach real DevTools to a headless instance for deep CI failure investigation.
Headless and visible Chrome produce nearly identical results for the vast majority of test suites.
Pro Tip
Keep --remote-debugging-port available as a documented, ready-to-enable option in your team's Karma setup notes. The one time a CI-only failure resists every other debugging technique, having this ready saves real time.
You now understand ChromeHeadless deeply. Next, learn how to build fully custom launchers for more specialized needs.