A stealth browser for scraping is an automation setup changed to avoid bot detection, from TLS impersonators to patched browser builds. In 2026 the main options are nodriver, Patchright, Pydoll, Camoufox and curl_cffi, and public benchmarks show that the proxy and the target matter more than the tool.
TL;DR
- Tools fall into four families by the layer they fix: TLS impersonators, CDP drivers that avoid detectable commands, patched browser binaries, and the old JavaScript-injection plugins.
- JavaScript-injection stealth (the original
puppeteer-extraplugin) is now a negative signal. Patched binaries and clean CDP drivers are the current baseline. - No tool fixes the environment: a datacenter IP, a software GPU and a UTC timezone are outside the binary.
- Claims of "undetectable" are not reproducible. Build a harness, run it against public detector pages, and re-run monthly; results change with browser releases.
- The most careful public benchmark so far (May 2026, 7 tools, 31 live targets, 3 sweeps, one residential IP) ranked nodriver first with zero hard blocks, found
rebrowser-playwrightidentical to unpatched Playwright, and foundcurl_cffiwith no browser at all tied with a commercial anti-detect browser. Other 2026 runs with rotating residential proxies put Camoufox first. The ranking depends on the proxy and the target set more than on the tool. - The benchmark below takes an afternoon to set up and gives you a table instead of a Reddit thread.
Four families, four layers
flowchart LR
accTitle: What each family of stealth tools fixes
accDescr: TLS impersonators fix the protocol layer, clean CDP drivers fix driver side effects, patched binaries fix runtime values at the source, and JavaScript injection fixes them detectably. None of them fixes the environment.
subgraph fixes["what each family fixes"]
direction TB
F1[TLS / H2 impersonators<br/>curl_cffi, tls-client, rquest] --> L2[protocol layer]
F2[Clean CDP drivers<br/>nodriver, Patchright, Pydoll] --> L3a[driver side effects]
F3[Patched binaries<br/>Camoufox, CloakBrowser] --> L3b[runtime values at the source]
F4[JS injection<br/>puppeteer-extra-stealth, deprecated] --> L3c[runtime values, detectably]
end
ENV[environment: IP class, GPU, fonts, timezone, behavior] -.->|fixed by none of them| X[ ]
style X fill:none,stroke:none
class F1 blue
class F2 teal
class F3 violet
class F4 bad
class L3c muted
class ENV warn
No family fixes the environment row. Pick the family by the layer the target actually checks, and fix the environment separately or accept the ceiling.
Four families
TLS and HTTP impersonators. curl_cffi (Python, on curl-impersonate), tls-client (Go and bindings), rquest (Rust), and Scrapling's fetcher mode. They produce a browser-accurate handshake and H2 fingerprint from a plain HTTP client. They solve the protocol layer only. No JavaScript runs, so any site that requires a challenge token is out of reach unless a token is supplied from elsewhere.
Clean CDP drivers. nodriver (the successor to undetected-chromedriver), Patchright (a Playwright fork, releasing steadily, 1.63 in September 2026), Pydoll, and the now stale rebrowser-patches (no code commits since September 2024). They drive a stock Chrome through the DevTools Protocol while avoiding the commands that pages can observe, especially Runtime.enable (explained in the headless tells post), and they do not set the automation flag. The browser is unmodified, so property checks pass without patches. Some automation features that depended on the avoided commands are missing or reimplemented. Two 2026 findings: running on the system Chrome channel (channel="chrome") moved results more than the patches did, and nodriver's advantage is attributed to having no Playwright layer at all rather than to any specific patch.
Patched binaries. Camoufox (Firefox with fingerprint injection in C++), CloakBrowser (a Chromium build sold as an anti-detect runtime), the Chromium-based anti-detect browsers used in the multi-accounting world, and research projects such as Obscura. They change what the browser reports at the source, so JavaScript sees a consistent fake: a chosen GPU string, font list, screen, and so on, with no patched functions to detect. The price is maintenance: every upstream release has to be re-patched. In the May 2026 benchmark Camoufox was still on a Firefox 135 beta and CloakBrowser's macOS build had been pinned to Chromium 145 since March, while system Chrome was at 148. A fingerprint that is internally consistent but three versions old is its own signal. Firefox-based tools also carry a Firefox fingerprint, a smaller population to hide in, and Camoufox is the slowest and most CPU-hungry option in every 2026 comparison that measured it.
JavaScript injection. puppeteer-extra-plugin-stealth, selenium-stealth and their clones. They override properties from an init script. Detectors learned to find the overrides years ago; the maintainers of puppeteer-stealth deprecated it in February 2025. Using them today adds a recognizable signature. Listed for completeness and because they still appear in tutorials.
What a tool cannot fix
The environment is outside the tool: the exit IP class, the GPU, the fonts installed, the timezone, the locale, and whether a human ever moves the mouse. A clean driver on a cloud VM with SwiftShader at UTC is still a cloud VM. Camoufox can claim an NVIDIA renderer, but the canvas hash it produces must match what that renderer actually draws, which is the hard part of fingerprint injection and the place where injected profiles are caught.
The honest summary: tools fix the parts of the fingerprint that come from the browser being driven. They do not fix the parts that come from where it runs or who is using it.
What the 2026 benchmarks agree and disagree on
The May 2026 run by Ian Paterson is the most reproducible public dataset: seven tools, 31 targets spanning JavaScript detector panels, TLS echo endpoints, live Cloudflare and anti-bot sites and high-traffic content sites, three randomized sweeps, 651 verdicts, zero drift between sweeps, all from one residential macOS IP in headed mode.
| Tool (engine) | OK | Gated | Blocked |
|---|---|---|---|
| nodriver (system Chrome 148) | 28 | 3 | 0 |
| CloakBrowser (Chromium 145) | 26 | 3 | 2 |
curl_cffi 0.15, impersonate=chrome |
26 | 3 | 2 |
Patchright (channel=chrome, 148) |
25 | 3 | 3 |
| Camoufox (Firefox 135 beta) | 25 | 3 | 3 |
| Vanilla Playwright (Chromium 147) | 24 | 2 | 5 |
| rebrowser-playwright (Chromium 136) | 24 | 2 | 5 |
Twenty-five of the 31 targets gave the same verdict to every tool; the six that discriminated were a financial-filings site, Medium, Glassdoor, Google Search, DEV and Stack Overflow. The author's limits are explicit: one IP, one OS, one night.
Other 2026 runs disagree in instructive ways. One with rotating residential proxies reported Camoufox passing everything it tried; another scored Camoufox at 89% against Pydoll at 79% and Scrapling's stealth mode at 58%, with Camoufox averaging over 40 seconds per bypass; a third found headless Camoufox at 90% and headed Camoufox at 30%, which the author traced to proxy routing in that configuration rather than the browser. The consistent lessons: the proxy changes the ranking, patched Playwright forks do not recover the hardest gates, and a TLS impersonator with no browser process competes with full anti-detect browsers on any target that has no JavaScript challenge.
Demonstration: a reproducible stealth harness
Public detector pages print a verdict in the DOM. The harness opens each page with each tool, waits, and extracts the verdict. Use several detectors; each tests different things.
Detectors with a stable, readable result:
https://bot.sannysoft.com(classic property checks, a table of pass and fail cells)https://abrahamjuliot.github.io/creepjs/(a trust score and a "lies" count for patched functions)https://www.browserscan.net/bot-detection(a summary verdict)https://fingerprint.com/products/bot-detection/demo (a bot or human result)
Minimal harness for the Playwright family, one function per tool so the launch differs and the scoring does not:
# harness.py
import asyncio, json, sys
from playwright.async_api import async_playwright
DETECTORS = {
"sannysoft": ("https://bot.sannysoft.com", "table"),
"creepjs": ("https://abrahamjuliot.github.io/creepjs/", "#fingerprint-data"),
}
async def score(page):
out = {}
for name, (url, sel) in DETECTORS.items():
await page.goto(url, wait_until="networkidle")
await page.wait_for_timeout(4000)
text = await page.inner_text(sel)
if name == "sannysoft":
out[name] = {"failed": text.count("failed"), "passed": text.count("passed")}
else:
# creepjs prints "trust score: NN%" and "lies (N)"; grab both
import re
t = re.search(r"trust score\D*(\d+)", text, re.I)
l = re.search(r"lies\D*(\d+)", text, re.I)
out[name] = {"trust": int(t.group(1)) if t else None, "lies": int(l.group(1)) if l else None}
return out
async def run_stock_playwright():
async with async_playwright() as p:
b = await p.chromium.launch(headless=True)
page = await b.new_page()
r = await score(page); await b.close(); return r
async def run_patchright():
from patchright.async_api import async_playwright as pr
async with pr() as p:
b = await p.chromium.launch(headless=True, channel="chrome")
page = await b.new_page()
r = await score(page); await b.close(); return r
async def run_camoufox():
from camoufox.async_api import AsyncCamoufox
async with AsyncCamoufox(headless=True) as b:
page = await b.new_page()
return await score(page)
async def main():
results = {}
for name, fn in [("playwright", run_stock_playwright), ("patchright", run_patchright), ("camoufox", run_camoufox)]:
try:
results[name] = await fn()
except Exception as e:
results[name] = {"error": str(e)[:80]}
print(json.dumps(results, indent=2))
asyncio.run(main())
Install with pip install playwright patchright camoufox and playwright install chromium, camoufox fetch. Run it on your laptop, then on a cloud VM, and keep both tables.
Expected shape of the result on a laptop (numbers vary by release):
| Tool | sannysoft failed | creepjs trust | creepjs lies |
|---|---|---|---|
| stock Playwright, headless | 2 to 4 | low | 0 |
| Patchright, headless, Chrome channel | 0 to 1 | medium to high | 0 |
| Camoufox, headless | 0 | high | 0 to few |
| puppeteer-extra stealth (add it yourself) | 0 | low | many |
The last row is the lesson about JavaScript injection: it passes the simple table and fails the detector that counts lies. The cloud VM run shifts every row down because of the GPU and IP, which is the lesson about environment.
Re-run the harness after every Chrome release. A tool that was clean last month can regress when upstream adds a property the patch does not cover, and the public detectors update faster than the tools do. Add a nodriver and a curl_cffi row to the harness too; the 2026 results above suggest those two bracket the field, and the delta between them tells you whether a given target needs a browser at all.
One more category to track from 2026: the agent-identity path. A client that signs its requests with Web Bot Auth is not trying to pass these detectors and is scored by policy instead. For a crawler that can be public about what it is, that path is cheaper than any tool on this page.
Read more: picking by job
| Need | Pick |
|---|---|
| Fetch pages that have no JavaScript challenge, at volume | curl_cffi with impersonation, sticky residential IPs if the site has bot management at the edge |
| Pages needing a challenge token, moderate volume | a clean CDP driver (nodriver, Patchright) with a real Chrome channel, GPU or realistic emulation, matching timezone |
| Highest scrutiny, low volume | Camoufox or a maintained anti-detect browser, headed, under a display, on a residential or mobile exit |
| Data from sites you are logged in to as yourself | your own browser, through an extension; no stealth tooling applies or is needed |
Read more: reading a creepjs report
CreepJS computes a trust score from consistency checks and counts "lies", meaning API results that contradict the browser's own behavior, such as a toString that claims native code for a function whose descriptor shows it was redefined. The lies count is the most useful single number for comparing stealth approaches: it is near zero for an unmodified browser and for a correctly patched binary, and high for anything that injects JavaScript overrides. A low trust score with zero lies usually means an environment problem (headless window geometry, software GPU) rather than a tooling problem.
Frequently asked questions
What is the best stealth browser for web scraping in 2026?
No single tool wins everywhere. In a May 2026 benchmark of 31 live targets, nodriver had no hard blocks, while other 2026 tests with rotating residential proxies ranked Camoufox first. Test the tools against your own targets with a harness like the one in this post.
What is the difference between nodriver and Patchright?
Both drive a stock Chrome through the DevTools Protocol while avoiding detectable commands. Nodriver talks to Chrome directly with no Playwright layer. Patchright is a patched Playwright fork that keeps Playwright's API, which is convenient but adds a layer that detectors can probe.
Is Camoufox undetectable?
No tool is. Camoufox changes fingerprint values inside Firefox itself, so pages cannot find patched functions, but it carries a Firefox fingerprint, lags behind upstream releases and is slower than Chrome-based tools. It also cannot change the IP class or behavior.
When is curl_cffi enough instead of a browser?
When the target has no JavaScript challenge. curl_cffi copies a browser's TLS and HTTP/2 handshake, which passes edge fingerprinting, and in the May 2026 benchmark it matched a full anti-detect browser on most targets. It cannot obtain tokens that need JavaScript.
Sources, checked October 2026
- Anti-Detect Browser Benchmark 2026: 7 Tools, 651 Verdicts (Ian Paterson, May 2026, updated August 2026)
- Same benchmark on DEV with discussion
- I Tested 7 Stealth Browsers Against 6 Detection Pages (Ijaz Ur Rahim, 2026)
- Browser Automation Benchmark 2026 (techinz)
- Stealth browsers 2026: nodriver, Camoufox, Patchright (ProxyCove)
- Patchright vs Playwright (ScaleBrowser)
- How to Bypass Cloudflare When Web Scraping in 2026 (Scrapfly, October 2026), puppeteer-stealth deprecation note