How to detect if the current browser is a headless browser with JavaScript

How to detect if the current browser is a headless browser with JavaScript

What is a headless browser?

A headless browser is a browser that can run in a graphical interface. I can programmatically control the headless browser to automatically perform various tasks, such as doing tests, taking screenshots of web pages, etc.

Why is it called a "headless" browser?

The word "headless" comes from the original "headless computer". Wikipedia entry on "headless computer":

A headless system is a computer system or device that has been configured to operate without a monitor (i.e., "head"), keyboard, and mouse. Headless systems are usually controlled via a network connection, but some headless system devices also require RS-232 serial connection for device management. Servers are often run in headless mode to reduce operating costs.

Why detect headless browsers?

Besides the two harmless use cases mentioned previously, headless browsers can be used to automate malicious tasks. The most common forms are web crawlers, disguising traffic, or detecting website vulnerabilities.

A very popular headless browser is Phantomjs. Because it is based on the Qt framework, it has many different features compared to our common browsers, so there are many ways to identify it.

However, starting with Chrome 59, Google released a headless Google Chrome browser. It is different from Phantomjs. It is developed based on the orthodox Google Chrome, not based on other frameworks, which makes it difficult for the program to distinguish whether it is a normal browser or a headless browser.

Below, we will introduce several methods to determine whether the program is running in a normal browser or a headless browser.

Detecting headless browsers

Note: These methods have only been tested on four machines (2 Linux, 2 Mac), that said, there are certainly many other ways to detect headless browsers.

User agent

First, let's introduce the most common method of determining the type of browser, which is to check the User agent. The User agent value of the Chrome version 59 headless browser on a Linux computer is:

“Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (Khtml, like Gecko) HeadlessChrome/59.0.3071.115 Safari/537.36”

So, we can detect whether it is a headless Chrome browser like this:

if (/HeadlessChrome/.test(window.navigator.userAgent)) {
  console.log("Chrome headless detected");
 }

User agent can also be obtained from HTTP headers. However, both of these scenarios are easy to fake.

Plugins

navigator.plugins will return an array containing the plugin information in the current browser. Usually, regular Chrome browsers have some default plugins, such as Chrome PDF viewer or Google Native Client. In contrast, in headless mode, without any plugins, an empty array is returned.

if (navigator.plugins.length == 0) {
  console.log("It may be Chrome headless");
}

language

In Google Chrome, there are two JavaScript properties that can get the current browser language settings: navigator.language and navigator.languages. The first one refers to the language of the browser interface, and the second one returns an array that stores all the secondary languages ​​​​selected by the browser user. However, in headless mode, navigator.languages ​​returns an empty string.

if (navigator.languages ​​== "") {
  console.log("Chrome headless detected");
}

WebGL

WebGL provides a set of APIs that can perform 3D rendering in HTML canvas. Through these APIs, we can query the vendor and renderer of the graphics driver.

In a regular Google Chrome browser on Linux, we get the renderer and vendor values ​​as: “Google SwiftShader” and “Google Inc.”.

And in headless mode, the one we get is "Mesa OffScreen" - which is the name of the rendering technology that doesn't use any window system, and "Brian Paul" - the original programmer of the open source Mesa graphics library.

 var canvas = document.createElement('canvas');
 var gl = canvas.getContext('webgl');
  
 var debugInfo = gl.getExtension('WEBGL_debug_renderer_info');
 var vendor = gl.getParameter(debugInfo.UNMASKED_VENDOR_WEBGL);
 var renderer = gl.getParameter(debugInfo.UNMASKED_RENDERER_WEBGL);
  
 if (vendor == "Brian Paul" && renderer == "Mesa OffScreen") {
  console.log("Chrome headless detected");
 }

Not all versions of headless browsers have the same values ​​for these two. However, currently in headless browsers the values ​​are "Mesa Offscreen" and "Brian Paul"

Browser Features

Modernizr can detect the current browser's support for various features of HTML and CSS. The only difference I found between regular Chrome and headless Chrome is that in headless mode there is no hairline feature, which is used to detect if hidpi/retina hairlines are supported

if (!Modernizr["hairline"]) {
  console.log("It may be Chrome headless");
}

Failed to load image

Finally, the last method I found, and the one that seems to work the best, is to check the height and width of the image that is not loading properly in the browser.

In normal Chrome, the size of the image that failed to load successfully is related to the browser's zoom, but it is definitely not zero. In the headless Chrome browser, the width and height of this image are both 0.

var body = document.getElementsByTagName("body")[0];
var image = document.createElement("img");
image.src = "http://iloveponeydotcom32188.jg";
image.setAttribute("id", "fakeimage");
body.appendChild(image);
image.onerror = function(){
	if(image.width == 0 && image.height == 0) {
		console.log("Chrome headless detected");
	}
}

The above is the details of how to use JavaScript to detect whether the current browser is a headless browser. For more information about JavaScript, please pay attention to other related articles on 123WORDPRESS.COM!

You may also be interested in:
  • Differences between this keyword in NodeJS and browsers
  • JavaScript determines whether the browser is IE
  • Example code for JavaScript to realize automatic scrolling and clicking of browser web pages
  • How to use the webcam in your browser using JavaScript
  • How to use JavaScript to manipulate the browser history API
  • Detailed explanation of JS cross-browser XML application process
  • Mobile browser invokes WeChat sharing (JS)
  • The browser JavaScript debugging function cannot be used. Solution
  • Summary of commonly used JavaScript tool functions (browser environment)
  • Example of judging browser type based on js

<<:  Write a mysql data backup script using shell

>>:  How to set a fixed IP in Linux (tested and effective)

Recommend

Detailed graphic explanation of how to use svg in vue3+vite project

Today, in the practice of vue3+vite project, when...

Two tools for splitting the screen in the Linux command line terminal

Here are two terminal split screen tools: screen ...

Detailed explanation of JavaScript primitive data type Symbol

Table of contents Introduction Description Naming...

HTML table markup tutorial (16): title horizontal alignment attribute ALIGN

By default, the table title is horizontally cente...

Better looking CSS custom styles (title h1 h2 h3)

Rendering Commonly used styles in Blog Garden /*T...

Nginx installation detailed tutorial

1. Brief Introduction of Nginx Nginx is a free, o...

Detailed explanation of CSS3 rotating cube problem

3D coordinate concept When an element rotates, it...

Comprehensive understanding of HTML basic structure

Introduction to HTML HyperText Markup Language: H...

Detailed explanation of Grid layout and Flex layout of display in CSS3

Gird layout has some similarities with Flex layou...

JavaScript to achieve calendar effect

This article shares the specific code for JavaScr...

Drop-down menu and sliding menu design examples

I found a lot of websites that use drop-down or sl...

JS interview question: Can forEach jump out of the loop?

When I was asked this question, I was ignorant an...

Detailed tutorial on installing MySQL 5.7.20 on RedHat 6.5/CentOS 6.5

Download the rpm installation package MySQL offic...

Example code for CSS pseudo-classes to modify input selection style

Note: This table is quoted from the W3School tuto...