Jun 7, 2026 · 8 min read · Cluster A · Stealth

Why Stealth Plugins Break in Production (2026)

Line-art illustration of a cracked browser window with a stealth plugin puzzle piece falling out

Bottom line

Last updated: June 7, 2026.

Jump to: the 5 reasons they break · a quick diagnosis · what to use instead · migration code · FAQ. If you are specifically on Playwright and already past the basics, read Playwright stealth not working in 2026 next.

The plugins everyone starts with

If you have ever scraped a protected site with a headless browser, you have almost certainly typed one of these:

# Puppeteer
npm i puppeteer-extra puppeteer-extra-plugin-stealth

# Playwright
npm i playwright-extra puppeteer-extra-plugin-stealth

Note that the Playwright stack reuses the same Puppeteer stealth plugin — playwright-extra-plugin-stealth is, under the hood, the Puppeteer plugin wired into playwright-extra. That shared lineage matters: both ecosystems inherit the same evasion list and the same blind spots.

These plugins were excellent. From roughly 2019 to 2022 they were the correct answer to "make my headless browser look real." They hide navigator.webdriver, fake the Chrome runtime object, patch the famous iframe.contentWindow leak, normalize the permissions API, and a few dozen other things. You added three lines and your scraper passed. The problem is not that the work was bad. The problem is what changed underneath it.

5 reasons stealth plugins break in production

1. Monkey-patching can't reach the leak that matters now

The single most important detection signal in 2026 is the CDP Runtime.enable leak. When Puppeteer or Playwright drives Chromium, it speaks the Chrome DevTools Protocol. Enabling the runtime domain — which the automation libraries do by default — leaves a side-channel that anti-bot scripts can probe from inside the page. This signal is emitted by the protocol layer, before any of your page JavaScript runs. A stealth plugin runs as page JavaScript. By definition it is too late and in the wrong place to patch it. This is the architectural ceiling: no amount of clever monkey-patching can fix a leak that lives below the layer the plugin operates in.

Line-art illustration of a radar dish detecting a hidden beacon emitting a signal — the CDP runtime leak probed from inside the page

2. The evasion list went stale — and stale patches become tells

Anti-bot vendors stopped scoring individual leaks years ago. Cloudflare Bot Management, DataDome, and PerimeterX now score combinations of signals. That flips the economics of a stealth plugin: a patch that makes one value look "correct" in isolation can create a combination no real browser ever produces — a too-perfect navigator sitting next to a default container timezone, say. The detector does not need to know your specific patch; it just learns that "this exact bundle of values = automation." An unmaintained plugin freezes its bundle in place while detectors keep moving. By 2026, puppeteer-extra-plugin-stealth has gone without a substantive evasion update long enough that several of its patches are now signals in their own right.

3. You only patched the browser — and the browser is one third of the problem

This is the big one, and it is why the plugin gets blamed for failures that are not its fault. Modern anti-bot runs three checks, roughly in this order:

Line-art cross-section of three stacked layers — IP reputation, browser fingerprint, and behavior
IP reputationRuns first, before a single byte of JS. Datacenter ASN = blocked. The plugin does nothing here.
TLS / JA4 fingerprintYour TLS handshake identifies the client stack. Stock Node/Chromium handshakes are flagged. The plugin does nothing here.
Browser fingerprint + behaviorThe only layer the plugin touches — and only the static part, not the behavioral part.

If you deploy a stealth-patched browser on a datacenter IP, you fail at step one and never even reach the layer your plugin was working on. This is the most common production failure we see, and it looks exactly like "the stealth plugin stopped working" when it is really "the IP was never going to pass."

4. Your dev environment lied to you

Stealth plugins pass on your laptop for reasons that evaporate in production:

None of that is the plugin's job to fix, which is precisely why "it works on my machine" is the most misleading sentence in scraping.

5. Behavior is unpatchable by a plugin entirely

Bot Management increasingly scores how you act: mouse paths, dwell time, scroll cadence, the gap between page load and first interaction. A stealth plugin is a static shim — it has no notion of behavior. A scraper that loads a page and fires a click 40ms later, with no mouse movement, is behaviorally a bot no matter how clean its navigator object looks.

Diagnose it in two minutes

Before you rewrite anything, find out which layer is actually leaking. Run your production browser config (not your laptop) against a fingerprint endpoint:

Then check the other two layers separately: curl -s https://api.ipify.org through your scraper's proxy and look up the ASN — if it says your cloud provider, that is your problem, not the plugin. If the fingerprint tests pass but real targets still block you, you are failing on IP or behavior.

What to use instead

Replace the stealth plugin with a maintained, protocol-patched browser, then add back the layers it never covered.

The catch is that this is now four moving parts — a patched browser, a proxy contract, a CAPTCHA path, and behavioral code — each with its own bill and its own way of breaking. That stitching is itself a maintenance burden, and it is the reason managed stacks exist.

The managed alternative

Human Browser ships all four layers behind one endpoint: a protocol-patched engine (both Chromium and Firefox), residential IPs, CAPTCHA handling, and an agent loop with behavioral pacing built in. It is the "maintained alternative" answer to the stealth-plugin problem — instead of pinning a dead npm package and bolting three vendors onto it, you make one API call and the evasion stack is kept current for you. Pay-as-you-go, try it for $1, then top up from $5. Try Human Browser.

Migration: from stealth plugin to a patched browser

The good news: Patchright keeps the Playwright API, so for most scripts the migration is a couple of lines. Before:

// Before — playwright-extra + stealth plugin
const { chromium } = require('playwright-extra');
const stealth = require('puppeteer-extra-plugin-stealth')();
chromium.use(stealth);

const browser = await chromium.launch({ headless: true });
const page = await browser.newPage();
await page.goto('https://target-site.com');

After:

// After — Patchright (CDP Runtime.enable patched) + residential proxy
const { chromium } = require('patchright');

const browser = await chromium.launch({
  headless: true,
  proxy: {
    server: process.env.PROXY_SERVER,    // residential endpoint
    username: process.env.PROXY_USER,
    password: process.env.PROXY_PASS,
  },
});
const page = await browser.newPage();
// pace it like a human: wait, move, then act
await page.goto('https://target-site.com', { waitUntil: 'domcontentloaded' });
await page.waitForTimeout(800 + Math.floor(Math.random() * 1200));

Or skip the assembly entirely and let the managed stack carry the browser, IP, and behavior:

// Managed — one call, all four layers handled
const { launchHuman } = require('@virixlabs/humanbrowser');

const { page } = await launchHuman();   // patched engine + residential IP + pacing
await page.goto('https://target-site.com', { waitUntil: 'networkidle' });
const html = await page.content();

Two migration gotchas worth knowing: Patchright bundles its own patched Chromium, so do not point it at a stock Chromium binary; and any code that called the raw Runtime.enable CDP command directly will need to move to higher-level APIs, since that is exactly the leak the fork closes.

The honest summary

Stealth plugins are not a scam and they were not badly built. They are a 2020 answer to a 2026 problem. They patch a frozen list of JavaScript signals, they cannot reach the protocol-level leak that detectors now lean on, and they only ever addressed one of the three layers that decide whether you get blocked. Swap the plugin for a maintained patched browser, add a residential IP and realistic behavior, and you have a stack that survives the trip from your laptop to production — or hand the whole stack to a managed service and stop maintaining it yourself.

Human Browser — the maintained stealth stack

Protocol-patched Chromium & Firefox + residential IPs + CAPTCHA handling + behavioral pacing, behind one API. Pay-as-you-go: $0.10/hr browser time + $0.02 per agent step (AI included) + $4/GB residential proxy, no subscription, try it for $1, then top up from $5.

Human Browser — pay as you go, no subscription
Top up — $20

Loading secure checkout…

More coins →