Research · · 9 min read

From Puppeteer stealth to Nodriver: How anti-detect frameworks evolved to evade bot detection

From Puppeteer stealth to Nodriver: How anti-detect frameworks evolved to evade bot detection

Browser automation tools like Puppeteer, Playwright, and Selenium are widely used for testing, scraping, and other automation tasks. However, because they were not designed with stealth in mind, they often expose detectable traces. These can include headless browser markers, inconsistencies in JavaScript APIs, or synthetic input patterns, all of which are commonly flagged by bot detection systems.

To evade these defenses, some developers have built anti-detect automation frameworks. These are modified versions or wrappers around traditional automation libraries, engineered to obscure the signs of automation and better mimic real user behavior. They typically patch or override browser APIs, manipulate fingerprinting surfaces, and randomize execution patterns.

This article explores the evolution of anti-detect automation frameworks: how they differ from traditional browser automation tools, why fraudsters rely on them, and what techniques are used to avoid detection in 2025.

Note: This article focuses on anti-detect frameworks and the technical methods they use to bypass detection. It does not cover detection techniques in depth. For more on why traditional detection methods fall short against modern automation and what defenders can do about it, see this blog post.

What are browser automation frameworks?

Browser automation frameworks allow developers to programmatically control web browsers. Tools like Puppeteer, Playwright, and Selenium are commonly used for end-to-end testing, data scraping, and simulating user behavior in real-world environments.

Puppeteer and Playwright are maintained by Google and Microsoft, respectively. These companies invest in browser automation because it helps developers detect layout issues, rendering bugs, and functional regressions early in the development cycle.

For example, a team maintaining Hacker News could use Puppeteer to automate a check that verifies exactly 30 articles are rendered on the front page:

const puppeteer = require('puppeteer');
const assert = require('assert');

(async () => {
  const browser = await puppeteer.launch();
  const page = await browser.newPage();

  // Go to Hacker News front page
  await page.goto('https://news.ycombinator.com/', { waitUntil: 'networkidle2' });

  // Count elements matching the .submission selector
  const submissionCount = await page.$$eval('.submission', elements => elements.length);

  // Output the count (optional)
  console.log(`Found ${submissionCount} .submission elements`);

  // Assert there are exactly 30 submissions
  assert.strictEqual(submissionCount, 30, `Expected 30 submissions but found ${submissionCount}`);

  await browser.close();
})();

What are anti-detect frameworks, and why fraudsters use them

While tools like Puppeteer and Selenium are essential for testing, they are also frequently abused in large-scale fraud. Instead of logging in manually with stolen credentials, attackers use bots to automate thousands of login attempts in parallel,a technique known as credential stuffing. Any website with a login form is a potential target.

To prevent this kind of abuse, anti-bot systems scan for signs that a browser is being controlled by automation. Common signals include properties like navigator.webdriver, missing or spoofed browser features, and inconsistencies in fingerprinting surfaces such as canvas, WebGL, and device memory.

In response, attackers began modifying browser automation frameworks to evade these detections. These modified tools are known as anti-detect automation frameworks.

Anti-detect frameworks work by patching browser behavior to conceal the presence of automation. For example, they might:

As anti-bot protections have become more common and more sophisticated, anti-detect frameworks have become essential infrastructure for fraud operations. They are widely used in credential stuffing, fake account creation, promo abuse, payment fraud, and other automated attacks.

Fingerprinting evasion in action: Inside Puppeteer Extra Stealth

To see how anti-detect frameworks work in practice, let's examine a real-world patch from Puppeteer extra stealth, one of the earliest and most influential anti-detect automation projects.

While Puppeteer extra stealth is less widely used today (we explain why later), it remains a valuable case study. It extends Puppeteer with a familiar API while applying evasions to avoid detection by common fingerprinting techniques.

One of these evasions targets navigator.languages, a property often used in bot detection to infer the user’s language preferences. The plugin modifies this property before any site JavaScript runs by using evaluateOnNewDocument:

async onPageCreated(page) {
    await withUtils(page).evaluateOnNewDocument(
      (utils, { opts }) => {
        const languages = opts.languages.length
          ? opts.languages
          : ['en-US', 'en']
        utils.replaceGetterWithProxy(
          Object.getPrototypeOf(navigator),
          'languages',
          utils.makeHandler().getterValue(Object.freeze([...languages]))
        )
      },
      {
        opts: this.opts
      }
    )
  }

At a glance, this might look like a simple override. But instead of directly assigning a new value to navigator.languages, the plugin uses a JavaScript proxy to intercept the property’s getter. This approach preserves the illusion of a native implementation while returning a controlled value.

The proxy logic is implemented like this:

utils.replaceGetterWithProxy = (obj, propName, handler) => {
  const fn = Object.getOwnPropertyDescriptor(obj, propName).get
  const fnStr = fn.toString() // special getter function string
  const proxyObj = new Proxy(fn, utils.stripProxyFromErrors(handler))

  utils.replaceProperty(obj, propName, { get: proxyObj })
  utils.patchToString(proxyObj, fnStr)

  return true
}

This patch performs three key steps:

  1. Wraps the original getter in a proxy to intercept calls.
  2. Replaces the getter on the prototype with the proxy.
  3. Patches the proxy’s toString() method to return the original function’s signature.

The result is a navigator.languages property that appears native to detection scripts but returns spoofed values. This kind of high-fidelity mimicry is critical to bypassing modern fingerprinting defenses.

While this article does not focus on detection techniques, it’s worth noting that proxies can still be detected indirectly. For example, subtle differences in error stack traces or exception types can leak the presence of a proxy, even when there is no official API to inspect one.

The new generation of anti-detect frameworks

In November 2022, Google unified the codebases of headful and headless Chrome. Previously, headless Chrome lacked several features and exhibited subtle differences: certain APIs were unsupported, rendering behavior could vary, and runtime features behaved slightly differently. These inconsistencies made headless environments easier to detect using fingerprinting techniques.

That’s no longer true. Since the unification, headless Chrome uses the same codebase as standard Chrome. Aside from a few minor quirks, detailed in this article, the fingerprint of headless Chrome now matches that of a regular browser. This marks a significant shift: traditional fingerprint-based detection techniques, which relied on subtle API discrepancies, are now largely ineffective.

From patching to protocol-level evasion

This shift has forced anti-detect framework developers to evolve. Earlier frameworks focused heavily on patching JavaScript-exposed APIs, modifying values like navigator.webdriver, navigator.languages, or screen.colorDepth to mimic genuine browser environments. But these patches are now less useful. Worse, they sometimes introduce their own inconsistencies and detectable side effects, especially when overwritten naively, which is often the case when the lies are applied at the JavaScript level.

Modern anti-detect frameworks are more targeted. Rather than applying dozens of evasions, they focus on a smaller set of powerful, low-level signals, primarily those introduced by browser automation protocols like the Chrome DevTools Protocol (CDP)

Chrome DevTools Protocol (CDP) and browser automation

Before we dive into how CDP became a fingerprinting vector, it's helpful to understand its role in browser automation.

The Chrome DevTools Protocol (CDP) is a low-level interface that lets external programs inspect and control Chromium-based browsers. Originally built to support Chrome’s built-in developer tools, CDP exposes granular control over browser internals: developers can manipulate the DOM, simulate user interactions, monitor network requests, inject scripts, and much more. This level of access makes CDP a foundational layer for popular automation tools like Puppeteer, Playwright (when run in Chromium mode), and Selenium (via ChromeDriver).

These frameworks communicate with the browser by sending JSON-formatted commands over a WebSocket. For example, to navigate to a page, an automation client might send the following CDP command:

{
  "id": 1,
  "method": "Page.navigate",
  "params": {
    "url": "https://example.com"
  }
}

View the ull documentation for Page.navigate

This kind of direct, low-level control is what enables powerful automation, but it also introduces detectable artifacts, which we’ll explore next.

CDP as a fingerprinting vector

CDP gives automation frameworks deep control over Chrome, but it may also create detectable artifacts. One common example involves how CDP frameworks use WebSocket connections to communicate with the browser. These communications often involve object serialization, which introduces observable side effects.

Several bot detection vendors have adopted what’s now known as CDP serialization detection. The idea is simple:

  1. Trigger object serialization, which only occurs if CDP is active.
  2. Detect serialization using JavaScript hooks.

Example: triggering serialization with Error.stack

One reliable way to trigger serialization is by logging an error object to the console:

var e = new Error();
Object.defineProperty(e, 'stack', {
   get() {
       console.log('Headless Chrome detected!);
   }
});

// The console.log statement is part of the detection
console.log(e);

This approach hinges on how CDP’s Runtime.consoleAPICalled works. This event is only emitted when the automation client explicitly enables the Runtime domain via Runtime.enable. If the domain isn’t enabled, Chrome silently discards the console output. But once CDP is listening, objects like e are serialized and streamed across the WebSocket, triggering the custom get stack() handler.

This technique, along with related variants, became widely adopted. As a result, bot developers began avoiding CDP-heavy tools like ChromeDriver and Selenium altogether.

Toward minimal-CDP or CDP-free automation

Modern anti-detect frameworks increasingly sidestep detection methods that rely on CDP artifacts by minimizing or eliminating their use of CDP altogether. Rather than patching over telltale signs, these tools avoid triggering them in the first place, either by skipping CDP commands known to produce side effects or by restricting CDP usage to non-sensitive domains. For example, some frameworks:

This shift has given rise to “CDP-minimal” or “CDP-optional” frameworks like nodriver and selenium-driverless, which abandon traditional protocols and instead emulate real user behavior through native OS-level inputs or stealthy browser control mechanisms.

The result is a fundamental change in the anti-detect ecosystem. It’s no longer just about masking automation through evasive patches—it’s about rethinking automation architecture to avoid detection at the protocol level entirely.

Top anti-detect frameworks in 2025

While Puppeteer extra stealth once dominated the anti-detect automation landscape, the ecosystem has since diversified. A new generation of frameworks has emerged, many designed to evade detection not just by patching browser APIs, but by avoiding automation protocols altogether or emulating real user behavior more closely.

The table below highlights some of the most widely used open-source anti-detect frameworks in 2025, along with their core capabilities and repository links.

Name Description Link
Puppeteer-extra-stealth JavaScript plugin for Puppeteer that applies multiple evasion techniques to make headless automation less detectable. Includes integrations with CAPTCHA-solving services. https://github.com/berstend/puppeteer-extra/tree/master/packages/puppeteer-extra-plugin-stealth
Nodriver Python framework that eliminates all CDP usage, mimicking regular browser sessions via OS-level input to avoid detection. https://github.com/ultrafunkamsterdam/nodriver
Selenium Driverless Python variant of Selenium that bypasses traditional WebDriver bindings, avoiding navigator.webdriver indicators. https://github.com/kaliiiiiiiiii/Selenium-Driverless
Patchright Python scriptable browser automation framework focused on patching fingerprinting leaks and mimicking user environments. https://github.com/Kaliiiiiiiiii-Vinyzu/patchright-python
Camoufox JavaScript anti-detect automation framework that removes known static fingerprinting attributes like navigator.webdriver. https://github.com/daijro/camoufox
SeleniumBase Python-based automation framework built on Selenium, offering features like CAPTCHA bypass, stealth modes (UC/CDP), and extensive testing utilities. https://github.com/seleniumbase/SeleniumBase
Rebrowser Playwright JavaScript drop-in replacement for Playwright, patched to pass modern automation detection tests. Designed to work without changing existing codebases. https://github.com/rebrowser/rebrowser-playwright
Rebrowser Puppeteer JavaScript drop-in replacement for Puppeteer, patched to pass modern automation detection tests. Maintains compatibility with existing Puppeteer codebases. https://github.com/rebrowser/rebrowser-puppeteer
Puppeteer Real Browser JavaScript package designed to bypass Puppeteer's bot-detecting CAPTCHAs such as Cloudflare. Acts like a real browser and can be managed with Puppeteer. https://github.com/ZFC-Digital/puppeteer-real-browser
BotBrowser Cross-platform stealth browser that modifies Chromium's C++ source code to eliminate fingerprint leaks and automation traces, enabling undetectable browsing and automation. https://github.com/MiddleSchoolStudent/BotBrowser

Commercial anti-detect browsers

Alongside open-source tools, a growing market of commercial anti-detect browsers has emerged. These products are designed to help users manage multiple browser profiles while avoiding detection. Common features include:

Originally, these browsers were built for manual use. Users could simulate different identities by combining proxy IPs with spoofed browser fingerprints. But in recent years, many vendors have added support for automation. Bots can now control these browsers directly using vendor-specific libraries or remote APIs.

Examples of widely used tools include:

As described in our guide to anti-detect browsers, these tools are often marketed for use cases like affiliate marketing, e-commerce operations, and social media management. In practice, they are also widely used in fraud operations, including fake account creation, social engineering, ad-fraud, scalping, and at-scale abuse.

We’ve published several articles detailing how these browsers work and the challenges involved in detecting them:

Conclusion

Anti-detect automation frameworks are no longer niche tools. They have become core infrastructure for modern bot operations. Fraud actors use them to scale abuse, bypass fingerprinting, and evade detection protocols.

As headless Chrome has become harder to fingerprint, the techniques used by these frameworks have evolved. Instead of modifying JavaScript-exposed APIs, modern tools now target low-level protocol signals, rebuild automation logic outside of CDP, or emulate user behavior in ways that produce fewer detectable traces.

At the same time, commercial anti-detect browsers with built-in automation support have lowered the barrier to entry. Fraud at scale no longer requires deep technical knowledge, just access to the right tools.

For defenders, staying ahead means understanding how these frameworks operate under the hood. Detection strategies must adapt to new techniques, revisit old assumptions, and account for how automation has changed in 2025.

Read next