Compiling a Fingerprint Browser - Bypassing Common Headless Detection

JANSON

This article explains the concept of headless browsers and details methods for bypassing headless detection.

What is a Headless Browser?

A headless browser is a browser without a graphical user interface. However, when used for web scraping, it exhibits certain characteristics that can be identified by websites, revealing its automated nature. This guide focuses on making deep-level modifications to the Chromium source code to thoroughly eliminate these identifiable traits.

How to Bypass Headless Detection?

1.Modify the webdriver property
Open the file: third_party\blink\renderer\core\frame\navigator.cc

c Copy
bool Navigator::webdriver() const {
  return false;
}

2.Modify rtt (Round-Trip Time)
Open the file: third_party/blink/renderer/modules/netinfo/network_information.ccc
c

c Copy
uint32_t NetworkInformation::rtt() {
  return 150;
}

3.Modify Notification.permission
Open the file: third_party/blink/renderer/modules/notifications/notification.cc

c Copy
String Notification::PermissionString(
    mojom::blink::PermissionStatus permission) {
  switch (permission) {
    case mojom::blink::PermissionStatus::GRANTED:
      return "granted";
    case mojom::blink::PermissionStatus::DENIED:
      //return "denied";
      return "default";
    case mojom::blink::PermissionStatus::ASK:
      return "default";
  }

  NOTREACHED();
  //return "denied";
  return "default";
}

4.Modify the User-Agent (Specifically for HeadlessChrome)
Open the file: C:\src\chromium\src\headless\lib\browser\headless_browser_impl.cc
Modify the relevant line:

c Copy
const char kHeadlessProductName[] = "Chrome";

5.Address Plugin Detection for Headless Mode
Modify third_party\blink\renderer\modules\plugins\navigator_plugins.cc

c Copy
DOMPluginArray* NavigatorPlugins::plugins(Navigator& navigator) {
  DOMPluginArray* pluginsArray = NavigatorPlugins::From(navigator).plugins(navigator.DomWindow());
  pluginsArray->UpdatePluginData();
  return pluginsArray;
}

Then modify: third_party\blink\renderer\modules\plugins\dom_plugin_array.cc

c Copy
void DOMPluginArray::UpdatePluginData() {
  if (should_return_fixed_plugin_data_) {
    dom_plugins_.clear();
    //if (IsPdfViewerAvailable()) {
      // See crbug.com/1164635 and https://github.com/whatwg/html/pull/6738.
      // To reduce fingerprinting and make plugins/mimetypes more
      // interoperable, this is the spec'd, hard-coded list of plugins:
      Vector<String> plugins{"PDF Viewer", "Chrome PDF Viewer",
                             "Chromium PDF Viewer", "Microsoft Edge PDF Viewer",
                             "WebKit built-in PDF"};
      for (auto name : plugins)
        dom_plugins_.push_back(MakeFakePlugin(name, DomWindow()));
    //}
    return;
  }
Update Time:Feb 03, 2026

Comments

Tips: Support some markdown syntax: **bold**, [bold](xxxxxxxxx), `code`, - list, > reference