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

MySQL 5.7.17 winx64 installation and configuration method graphic tutorial

Windows installation mysql-5.7.17-winx64.zip meth...

Detailed explanation of monitoring Jenkins process based on zabbix

1. Monitoring architecture diagram 2. Implementat...

Node.js returns different data according to different request paths.

Table of contents 1. Learn to return different da...

Analysis of the principle of centering elements with CSS

It is a very common requirement to set the horizo...

Docker-compose one-click deployment of gitlab Chinese version method steps

1. Introduction to gitlab Gitlab official address...

MySQL common backup commands and shell backup scripts sharing

To back up multiple databases, you can use the fo...

Summary and practice of javascript prototype chain diagram

Table of contents Prototype chain We can implemen...

A brief introduction to the general process of web front-end web development

I see many novice students doing front-end develop...

Detailed explanation of MySQL user and permission management

This article uses examples to describe the manage...

JavaScript to implement search data display

This article shares the data display code for Jav...

Analysis of the principle of Vue nextTick

Table of contents Event Loop miscroTask (microtas...

Detailed explanation of GaussDB for MySQL performance optimization

Table of contents background Inspiration comes fr...

Detailed steps to install and uninstall Apache (httpd) service on centos 7

uninstall First, confirm whether it has been inst...

Complete steps to use vue-router in vue3

Preface Managing routing is an essential feature ...