Google changed his Headless Chrome Browser (a derivate of the Chromium browser) and removed the information about “Headless” (“HeadlessChrome”) from the User Agent. Because of that, it is no possible to detect this browser as an headless browser.
This maybe matched also the Microsoft Edge Headless Browser, because this is also a derivate of the Chromium browser.
The information about “Headless” can maybe extract from the JavaScript navigator.userAgentData
, but this is an experimental technology.
Here a solution to detect hidden headless browser.
Basic infos:
: https://developer.mozilla.org/en-US/docs/Web/API/Navigator/userAgentData
: https://developer.mozilla.org/en-US/docs/Web/API/NavigatorUAData/getHighEntropyValues
: https://learn.microsoft.com/en-us/microsoft-edge/web-platform/user-agent-guidance
: https://developer.chrome.com/docs/privacy-security/user-agent-client-hints
In the browser standards, the User Agent is saved in navigator.userAgent
as an string.
Example (headless, but out of date):
Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/100.0.4889.0 Safari/537.36
The new one is navigator.userAgentData
.
Example of navigator.userAgentData
(non headless):
// navigator.userAgentData
{
"brands": [
{
"brand": "Not_A Brand",
"version":"8"
},
{
"brand": "Chromium",
"version":"120"
},
{
"brand": "Microsoft Edge",
"version":"120"
}
],
"mobile": false,
"platform": "Windows"
}
Example of navigator.userAgentData.getHighEntropyValues()
(non headless):
// navigator.userAgentData.getHighEntropyValues(["fullVersionList"])
{
"brands":[
{
"brand":" Not A;Brand",
"version":"99"
},
{
"brand":"Chromium",
"version":"98"
},
{
"brand":"Google Chrome",
"version":"98"
}
],
"fullVersionList":[
{
"brand":" Not A;Brand",
"version":"99.0.0.0"
},
{
"brand":"Chromium",
"version":"98.0.4738.0"
},
{
"brand":"Google Chrome",
"version":"98.0.4738.0"
}
],
"mobile":false
}
A Solution for Matomo: A function to detect “Headless” in this values:
function browserheadless() {
var result = false;
if (typeof navigator !== "undefined") {
if (typeof navigator.userAgent !== "undefined") {
if (navigator.userAgent.toLowerCase().includes("headless") === true) {
result = true;
}
}
if (typeof navigator.userAgentData !== "undefined") {
if (typeof navigator.userAgentData.brands !== "undefined") {
for (var i = 0; i < navigator.userAgentData.brands.length; i++) {
if (navigator.userAgentData.brands[i].brand.toLowerCase().includes("headless") === true) {
result = true;
}
}
}
if (typeof navigator.userAgentData.getHighEntropyValues() !== "undefined") {
if (typeof navigator.userAgentData.getHighEntropyValues().brands !== "undefined") {
for (var i = 0; i < navigator.userAgentData.getHighEntropyValues().brands.length; i++) {
if (navigator.userAgentData.getHighEntropyValues().brands[i].brand.toLowerCase().includes("headless") === true) {
result = true;
}
}
}
if (typeof navigator.userAgentData.getHighEntropyValues(["fullVersionList"]).fullVersionList !== "undefined") {
for (var i = 0; i < navigator.userAgentData.getHighEntropyValues(["fullVersionList"]).fullVersionList.length; i++) {
if (navigator.userAgentData.getHighEntropyValues(["fullVersionList"]).fullVersionList[i].brand.toLowerCase().includes("headless") === true) {
result = true;
}
}
}
}
}
}
return result;
}
if (browserheadless() === false) {
// Here the Matomo Tracking Script Snippet
}
untested. use at you own risk.
consider: the used navigator.userAgentData
is an experimental technology.