What actually replaces puppeteer-extra-plugin-stealth?
A puppeteer stealth alternative only helps if it fixes the layer your traffic actually fails at. The stealth plugin patches JavaScript properties inside the page, while current detection reads TLS handshakes, CDP transport artifacts and engine-level rendering first. Your realistic options are a patched driver such as rebrowser-puppeteer or Patchright, a driverless CDP client such as nodriver, or running your existing script against an anti-detect browser profile where the fingerprint, IP and timezone already agree.

📌 TL;DR Executive Summary
- Core Takeaway: Patched drivers (rebrowser-puppeteer, Patchright) close the CDP leaks; driverless clients (nodriver, Zendriver) remove the WebDriver layer. Neither changes your machine’s fingerprint or TLS signature.
- Key Risk/Challenge: Edge services read your TLS fingerprint before page JavaScript runs, and enabling the CDP Runtime domain leaves a trace in page script. A JavaScript-only plugin reaches neither layer.
- Recommended Solution: Match the tool to the layer that fails. When several accounts must look like separate machines, connect your Puppeteer or Playwright script to a Send.win profile over its local CDP endpoint (automation API is on the Team plan).
Every option below is sorted by the layer it addresses. Tools that only patch in-page JavaScript will not save you from a TLS check, and tools that only remove the WebDriver layer will not stop two accounts from sharing one machine fingerprint.
| Tool | Layer it fixes | What it does not fix | Language / licence |
|---|---|---|---|
| puppeteer-extra-plugin-stealth | In-page JS properties: navigator.webdriver, plugins, WebGL vendor, user agent | TLS, IP reputation, behaviour, CDP artifacts | Node.js, free |
| rebrowser-puppeteer | CDP protocol artifacts | Browser fingerprinting | Node.js, free |
| Patchright | CDP leaks plus Playwright’s default launch arguments | The fingerprint engine | Python, free |
| nodriver / Zendriver | Removes the WebDriver layer entirely | Canvas, WebGL, navigator values, TLS | Python, free, AGPL-3.0 |
| Camoufox | Fingerprints injected into a modified Firefox engine | Speed and memory per session | Free, open source |
| SeleniumBase UC mode | Driver and CDP modes aimed at challenge pages | Not built as a per-profile identity system | Python, free |
| Send.win | Engine fingerprint and network identity per profile | You are not writing your own patches | Selenium, Puppeteer, Playwright via local automation API (Team) |
The pattern is worth reading twice. Every free puppeteer stealth alternative on that list stops at the driver boundary, and the engine fingerprint — canvas, WebGL, fonts, hardware — stays untouched. Only two rows reach the layer below it.
What puppeteer-extra-plugin-stealth actually patches
The plugin is a bundle of evasion modules that override in-page signals: navigator.webdriver, window.chrome, navigator plugins and languages, WebGL vendor strings, permission queries, media codec lists and the user agent. Every patch is applied through evaluateOnNewDocument, so it executes inside the page’s own JavaScript context once the document starts loading.
Automate Puppeteer Stealth Alternative With Send.win
Send.win pairs isolated, fingerprint-managed browser profiles with a full Automation API, so your scripts run in profiles that look and behave like real, separate users:
- Selenium, Puppeteer & Playwright support – drive any profile programmatically (Team plan)
- Isolated profiles – each with its own fingerprint, cookies, and storage
- Built-in residential proxies – with automatic timezone, locale, and WebRTC matching
- Desktop app for Windows, macOS & Linux – plus cloud sessions when you don’t want a local install
Try the instant cloud browser demo — no install, straight from your browser. Then compare plans: a 30-day free trial with no credit card, and paid plans from $6.99/month billed annually.
Two things follow from that design. First, the patches run in the same sandbox as the detection script looking for them, so any check that inspects property descriptors or the toString() output of a function can spot a non-native override. Second, the plugin never touches anything outside the page: no TLS handshake, no IP reputation, no CDP transport, no behaviour timing. Published module counts do not even agree with each other — one breakdown lists 11, another 17. The plugin stealth reference walks through each override if you need the detail.
The maintenance picture matters as much as the code. Version 2.11.2 shipped in March 2023 and no later release appears in the published history, yet the package still pulls more than 600,000 npm downloads a week. That gap tells you how much production scraping quietly depends on a bundle nobody is updating.
Why page-level patches fail now
The Runtime.enable leak
When a CDP client attaches and enables the Runtime domain, the call leaves a side effect that page JavaScript can observe. Detection scripts use it as a cheap test for “an automation controller is attached to this browser”, and it fires before any stealth override has a chance to matter. It is a transport artifact, not a page property, which is exactly why defineProperty cannot hide it. The patched-driver projects exist mainly to close this one hole.
TLS and IP reputation are read before your script runs
Cloudflare and similar edge services evaluate the TLS handshake — the JA3/JA4 fingerprint of your client — before they serve HTML. A handshake that does not resemble a normal Chrome build triggers a challenge while your page code is still waiting for a response. Nothing injected via evaluateOnNewDocument is loaded at that point. IP reputation works the same way: a datacenter address with a clean browser still gets a harder time than a residential address with an average one.
navigator.webdriver.
Headless rendering still differs
Even with --headless=new, the rendering path is not identical to headed Chrome. Font metrics, GPU-backed canvas output and screen-dimension APIs return measurably different values. Canvas and WebGL hashes computed in headless often land outside the cluster of real desktop sessions, and no property override normalises that, because the difference comes from the compositor rather than from a JavaScript object.
Patchright: closes the CDP leak, under one exact launch config
Patchright is a patched Playwright: pip install patchright, then patchright install chromium. It runs injected JavaScript in isolated execution contexts rather than the page’s main context, which neutralises the Runtime.enable leak, and it supports Closed Shadow Roots. It also disables the Console API entirely to close the Console.enable leak — and that has a concrete cost, because page console logging stops working while you debug against a live target.
On launch arguments it adds --disable-blink-features=AutomationControlled and removes --enable-automation, --disable-popup-blocking, --disable-component-update, --disable-default-apps and --disable-extensions — all things you would otherwise patch by hand. Its documentation, refreshed in September 2026, lists pass targets across Cloudflare, Kasada, Akamai, DataDome, CreepJS, Sannysoft, Browserscan and Pixelscan, but only when you launch with a persistent context, channel="chrome", headed mode, and no custom user agent or extra headers.
from patchright.sync_api import sync_playwright
with sync_playwright() as p:
context = p.chromium.launch_persistent_context(
user_data_dir="./profile-01",
channel="chrome", # real Chrome channel, not bundled Chromium
headless=False, # headed is part of the documented config
no_viewport=True,
)
page = context.new_page()
page.goto("https://example.com")
context.close()
Step outside that configuration and none of the documented results apply. Patchright does not change the fingerprint engine either, so two profiles on one laptop still share canvas, WebGL and font output. The Patchright vs Playwright stealth comparison covers where the two diverge in practice, and the project page on PyPI carries the exact launch configuration.
nodriver and Zendriver: no WebDriver layer at all
nodriver drives stock Chrome directly over CDP from async Python. There is no Selenium and no chromedriver in the stack, so the WebDriver-shaped signals that Selenium-based automation leaks do not exist. The project sits at roughly 4,800 GitHub stars and about 280,000 PyPI downloads a month, with version 0.50.3 shipping in May 2026.
It is a driver, not an engine. Canvas, WebGL, navigator values and the TLS handshake stay at the host machine’s real values, so every session you launch looks like the same computer — fine for scraping public pages, useless for keeping ten accounts apart. It accepts a custom browser path, which lets you point it at another Chromium binary. The licence is AGPL-3.0, network copyleft, and that is a real blocker for some commercial and SaaS teams.
import asyncio
import nodriver as uc
async def main():
browser = await uc.start(
browser_executable_path="/path/to/your/chrome",
)
page = await browser.get("https://example.com")
await page.sleep(3)
browser.stop()
asyncio.run(main())
Zendriver is a community fork that merges fixes faster than upstream and adds typing, linting and Docker support. The CDP approach is identical, so the fingerprint limitation is identical too. If you are weighing this route against the other Python tools, the rundown of stealth headless browsers puts Camoufox, SeleniumBase UC mode and the CDP clients side by side.
rebrowser-puppeteer: the smallest possible diff
rebrowser-puppeteer is upstream Puppeteer with the rebrowser patches applied. Major and minor versions track the original and only the patch version differs, so you are not adopting a fork that drifts. You install it under its own name and change one import line. It targets CDP protocol artifacts — the same class of Runtime.enable leak — and it does not touch browser fingerprinting.
// npm i rebrowser-puppeteer
const puppeteer = require('rebrowser-puppeteer');
(async () => {
const browser = await puppeteer.launch({ headless: false });
const page = await browser.newPage();
await page.goto('https://example.com', { waitUntil: 'networkidle2' });
console.log(await page.title());
await browser.close();
})();
If your Puppeteer script already handles proxies, timings and retries, this is the lowest-effort upgrade available: one dependency swap, and the leak detection scripts test for is closed. Releases are published on the rebrowser-puppeteer repo. What it will not do is make two profiles on one laptop look like two machines.
Where Send.win fits: engine-level fingerprints plus proxy coherence
Everything above operates at the driver or page layer and leaves the host fingerprint intact. Send.win takes the other route. Sendwin Browser is a patched-Chromium desktop app for Windows, macOS and Linux, with the Sendwin Stealth engine built in: canvas, WebGL, audio, fonts and hardware are spoofed at the engine level rather than through script injection, and the values are kept coherent, so no two profiles share a fingerprint. Because the spoofing is not a JavaScript override, there is no toString() mismatch to find.
The network side is handled in the same place. Built-in residential proxies ship on every plan, bring-your-own HTTP/SOCKS5 is supported, and timezone, locale, WebRTC and geolocation follow the proxy’s exit IP automatically. That coherence matters more than most people expect: a profile claiming Frankfurt while its clock and WebRTC candidates say São Paulo gets flagged long before anyone reads a canvas hash. Profiles can also run on Send.win’s EU and US cloud nodes from any device, with a 10-minute daily free preview.
Automation is deliberately narrow. Send.win’s local automation API for Selenium, Puppeteer and Playwright is listed on the Team plan. You copy the CDP endpoint from the profile’s automation settings and connect your existing script to that running profile, so your code and the profile’s fingerprint and proxy work together instead of fighting each other.
from playwright.sync_api import sync_playwright
CDP_URL = "http://127.0.0.1:PORT" # copy it from the profile's automation settings
with sync_playwright() as p:
browser = p.chromium.connect_over_cdp(CDP_URL)
context = browser.contexts[0]
page = context.new_page()
page.goto("https://example.com")
print(page.title())
browser.close() # disconnects the script; the profile keeps running
If that pattern is new, the Puppeteer with an anti-detect browser walkthrough covers the connect step and the profile settings that have to line up. For account work rather than scraping, this is the layer that separates ten logins from one flagged machine. The trade-off is honest: you get a managed engine instead of the ability to write your own patches, and automation sits on Team rather than Free or Pro.
The hidden cost: update lag, not licences
Every open-source puppeteer stealth alternative here shifts cost from a subscription to engineering time. You watch releases, re-test fingerprints after a Chrome update, and re-run your own detection suite. How fast a project absorbs those changes decides how much of that work lands on you.
| Project | Update position | What it costs you |
|---|---|---|
| puppeteer-extra-plugin-stealth | Last release 2.11.2, March 2023 | You own every future breakage |
| nodriver | 0.50.3 shipped May 2026 | Actively maintained, younger API surface |
| Zendriver | Fork merging fixes faster than upstream | Same CDP approach, faster patch cadence |
| Patchright | Docs refreshed September 2026 | Results tied to one documented launch config |
| Send.win | Engine updates ship through the product changelog | Subscription instead of maintenance |
None of that appears in a licence comparison, and it is why a team that saves a subscription can still spend more on a quarter of rework.
Which one should you pick?
Work from the failure, not from the tool list. The right puppeteer stealth alternative depends on which layer rejects you, and four cases cover most setups.
You have a Puppeteer codebase
Swap in rebrowser-puppeteer first. It is a one-line change and it closes the CDP leak most detection scripts test for. Only consider a rewrite if you are still failing after that.
You are on Playwright
Try Patchright and commit to the documented launch configuration: persistent context, the real Chrome channel, headed mode, no custom headers. If you need page console output while debugging, develop against plain Playwright and switch only for production runs.
You are in Python and want no driver
nodriver is the pragmatic choice, or Zendriver if you want faster-merged fixes and Docker support. Confirm the AGPL-3.0 terms fit your distribution model first. Camoufox is the option when hard fingerprinting is the wall and you can afford the resources; SeleniumBase UC mode fits teams already living in Selenium who only fight challenge pages.
One machine has to look like many
Driver patches cannot help here, because every session shares the host fingerprint, and that is the wall most multi-account work hits. Use browser profiles that each carry their own engine fingerprint, proxy, timezone and locale. A CDP endpoint belongs to a browser rather than to a language, so a Python client and a Node service can attach to the same profile — just decide who owns the session and who closes it.
How to test whether you are still detected
Build a repeatable check before you tune anything. Load bot.sannysoft.com, Pixelscan, BrowserScan and CreepJS in the exact session you plan to automate, then repeat in a plain Chrome window on the same connection as a baseline. Differences in canvas or WebGL hashes, missing plugins, or a navigator object that reports differently between headed and headless runs all point at the layer that needs work.
Then test through the proxy, not around it. Run the same pages with the proxy attached and confirm the reported timezone, language and geolocation match the exit IP. Those mismatches are cheaper to detect than any deep fingerprint anomaly, and they are the most common reason a technically solid setup still gets challenged.
🏆 Send.win Verdict
Driver patches solve the CDP transport problem and nothing above it. If your work is scraping public pages from one machine, rebrowser-puppeteer or nodriver is the cheap, correct answer. If your work is running many accounts that each need to look like a separate real computer — with an IP, timezone and fingerprint that agree — Send.win covers the engine and network layers no plugin can reach, and on Team your existing Selenium, Puppeteer or Playwright script connects to a profile over its local CDP endpoint instead of replacing it.
Try Send.win free today — the desktop app is free for 30 days with $0 due today, ten isolated profiles and ten residential proxies included, and your local profiles stay on your machine.
Frequently Asked Questions
Does puppeteer-extra-plugin-stealth still work in 2026?
It still removes the most obvious in-page signals, so it is not useless. But the published release history stops at version 2.11.2 in March 2023, and the plugin cannot touch TLS, IP reputation, CDP artifacts or headless rendering differences. On lightly protected sites it may still be enough. Treat it as a partial fix rather than a complete puppeteer stealth alternative.
What is the Runtime.enable CDP leak?
Enabling the Runtime domain over CDP creates a side effect that page JavaScript can observe. Detection scripts use it to infer that an automation controller is attached, before any stealth patch matters. Patched drivers such as rebrowser-puppeteer and Patchright exist mainly to close that specific leak.
Which puppeteer stealth alternative passes Cloudflare?
No tool guarantees a pass, and every published pass list is self-reported by its vendor. Patchright documents results against Cloudflare only when launched with a persistent context, the real Chrome channel, headed mode and no custom headers; outside that configuration the results do not apply. Your TLS fingerprint and IP reputation often decide the outcome before page JavaScript runs.
Is Patchright better than Playwright for stealth?
It is better against CDP-shaped detection, because injected JavaScript runs in isolated contexts and the default launch arguments are adjusted. It is worse for debugging, because the Console API is disabled. It does not change the browser fingerprint, so it is not a substitute for per-profile identity.
Does Patchright break console logging?
Yes. Disabling the Console API is part of how it closes the Console.enable leak, so page-level console output stops reaching you. Work around it by logging at your application layer, or keep plain Playwright for local debugging and use Patchright only for production runs.
Should I use nodriver or Patchright for Python?
Choose Patchright to stay inside the Playwright API with auto-waiting locators, if you can live with the strict launch configuration. Choose nodriver for stock Chrome with no WebDriver layer and a younger API surface. Neither changes canvas, WebGL, navigator values or TLS.
Can a stealth plugin hide my TLS fingerprint?
No. The plugin runs inside the page, after the TLS handshake has already been evaluated by the edge server. If your client’s JA3/JA4 fingerprint does not resemble a normal Chrome build, you can be challenged before a single line of page JavaScript executes.
How do I test if my automation is detected?
Run bot.sannysoft.com, Pixelscan, BrowserScan and CreepJS in the exact session you plan to automate, and repeat in plain Chrome on the same connection as a baseline. Then attach the proxy and confirm timezone, language and geolocation match the exit IP. Those mismatches are easier to catch than deep fingerprint anomalies.