Are Headless Chrome bots instrumented with Puppeteer detected by Fingerprint Scan?
In this article, we explore various versions of Headless Chrome bots powered by Puppeteer to assess their detection by the Fingerprint Scan bot detection test. We begin with a basic bot that runs without any fingerprint modifications, serving as a baseline. Then, we incrementally apply changes to its fingerprint, aiming to make the bot appear more human-like and evade detection more effectively.
Bot 1: Unmodified Headless Chrome and Puppeteer vs Fingerprint Scan
We create a simple bot that uses Puppeteer with Headless Chrome. The bot doesn’t apply any modification to its fingerprint.
const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto('https://fingerprint-scan.com/');
await new Promise(resolve => setTimeout(resolve, 1000));
await page.screenshot({path: 'screenshot.png', fullPage: true});
await browser.close();
})();
We see that the bot is properly detected by Fingerprint Scan with a bot score of 100/100.

By default, Headless Chrome with Puppeteer has a
discriminating user agent that contains the HeadlessChrome
substring, such as
Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/133.0.0.0 Safari/537.36
,
as well as navigator.webdriver = true
, which makes it straightfoward to detect.
Bot 2: User agent modified Puppeteer vs Fingerprint Scan
We modify our Puppeteer bot to lie about the user
agent. We change the user agent to
Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36
to remove the presence of HeadlessChrome
in the user agent.
const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.setUserAgent('Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36');
await page.goto('https://fingerprint-scan.com/');
await new Promise(resolve => setTimeout(resolve, 1000));
await page.screenshot({path: 'screenshot.png', fullPage: true});
await browser.close();
})();
This improved version of our bot is also detected by
Fingerprint Scan, with a score of 100/100. In particular, it is detected because of the presence of
navigator.webdriver = true
.

Bot 3: navigator.webdriver modified Puppeteer vs Fingerprint Scan
We modify our previous Puppeteer bot version to both
lie about the user agent and remove the presence of navigator.webdriver = true
, which is
highly discriminating.
const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch({args: ['--disable-blink-features=AutomationControlled']});
const page = await browser.newPage();
await page.setUserAgent('Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36');
await page.goto('https://fingerprint-scan.com/');
await new Promise(resolve => setTimeout(resolve, 1000));
await page.screenshot({path: 'screenshot.png', fullPage: true});
await browser.close();
})();
This improved version of our bot is also detected by
Fingerprint Scan with a score of 100/100. Indeed, it still triggers detection tests like side effects
linked to CDP
(Chrome Devtools Protocol) or because the bot still has the default screen resolution
(800x600
pixels) linked to Headless Chrome.

Note that the bot detection cat-and-mouse game doesn’t stop here. It’s still possible to continue to improve the quality of the bot, e.g. by changing the screen resolution. You can start from here and continue to improve the fingerprint of the Puppeteer with Headless Chrome bots to see if improved versions can still be detected by Fingerprint Scan.