Detect Chrome running in headless mode from JavaScript

The user agent string includes HeadlessChrome instead of Chrome. This is probably the signal that you're intended to look for, so you could use:

/\bHeadlessChrome\//.test(navigator.userAgent)

Other interesting signals include:

  • It looks like window.chrome is undefined when headless.
  • [innerWidth, innerHeight] is [800, 600] (hardcoded in headless_browser.cc), while [outerWidth, outerHeight] is [0, 0] (which shouldn't usually happen).

You can check navigator.webdriver property which is:

The webdriver read-only property of the navigator interface indicates whether the user agent is controlled by automation.

...

The navigator.webdriver property is true when in:

Chrome The --enable-automation or the --headless flag is used.
Firefox The marionette.enabled preference or --marionette flag is passed.

The W3C WebDriver Recommendation describes it as follows:

navigator.webdriver Defines a standard way for co-operating user agents to inform the document that it is controlled by WebDriver, for example so that alternate code paths can be triggered during automation.


Just read this article by Antoine Vastel which provides a few ways:

  • testing user agent with /HeadlessChrome/.test(window.navigator.userAgent), but this is easily spoofed
  • testing plugins with navigator.plugins.length == 0
  • testing languages with navigator.languages == ""
  • testing WebGL vendor and renderer info (see article for interesting details)
  • testing supported features as detected by Modernizr: it seems "hairlines" are not supported (hidpi/retina hairlines, which are CSS borders with less than 1px in width, for being physically 1px on hidpi screens). Test is !Modernizr["hairline"].
  • testing size of placeholder for missing image. Insert an image with invalid URL, and test for image.width == 0 && image.height == 0 in image.onerror (they found this one to be the most robust).

Can't speak for Google's motivations (is Headless Chrome only about facilitating tests of web applications? Hmmm...), but this could be seen as a list of bugs that might get fixed someday, so one has to wonder for how long those tests will work :)