๐ŸŽ‰ Premium Proxies ยท 24-Hour Free TrialClaim Now
Comparisons

Undetected-ChromeDriver vs Patchright vs Camoufox

Undetected-ChromeDriver vs Patchright vs Camoufox compared by where each patch lives, what it defeats, real release dates, proxy support and resource cost.

S SparkProxy 47 18 min read
Share
Undetected-ChromeDriver vs Patchright vs Camoufox

Camoufox is the strongest of the three because its patches are compiled into a Firefox build instead of injected as JavaScript, Patchright is the best choice if you already run Playwright on Chromium, and undetected-chromedriver is the one to stop starting new projects on because its last PyPI release shipped in February 2024.

Every comparison of undetected-chromedriver vs Patchright vs Camoufox turns into a feature list, which hides the only thing that actually matters: these three tools patch three different layers of the stack. One rewrites bytes inside the ChromeDriver binary. One rewrites the automation client so it stops sending a detectable DevTools command. One rewrites the browser's own C++ and ships a custom build. That choice of layer determines what each tool can defeat, what it can never defeat, and how fast it rots when Chrome or Firefox ships a new major version. This post compares them on layer, coverage, real release cadence pulled from the package registries in August 2026, language fit, proxy handling, and cost per concurrent session.

One scope note first. This is written for teams collecting data they are permitted to collect, such as public pricing, public listings, or their own accounts. Using these tools to get around a login wall, a rate limit you agreed to, or an explicit prohibition can breach a site's terms of service, and that is a call for your legal team, not your scraper config.

Where the patch lives, and why that is the whole argument

A browser automation stack has four layers a detector can inspect:

LayerExample artifactWho can see it
Browser binary`navigator.webdriver`, WebGL renderer string, font listAny page script
Automation protocolCDP `Runtime.enable` side effects, extra DevTools targetsAny page script, indirectly
Driver processThe `window.cdc_...` variables ChromeDriver injectsAny page script
Client libraryLaunch flags such as `--enable-automation`Any page script, via their effects

The three tools each attack a different row. undetected-chromedriver patches the driver process. Patchright patches how the client uses the automation protocol. Camoufox patches the browser binary itself.

That ordering matters because a patch applied above the browser has to express itself as JavaScript running inside the page, and JavaScript that redefines a native property is itself detectable. A getter written in JS has a different Function.prototype.toString output, a different property descriptor shape, and a different position in the prototype chain than the native one it replaced. Detection vendors have shipped checks for exactly that for years. A patch compiled into the browser has no such tell, because there is nothing to override: the value the page reads is the value the engine holds. Camoufox states this directly in its README, describing its injection as done "in the C++ implementation level" so that "all of the hijacked objects and properties appear native."

That is the structural reason Camoufox sits in a stronger position than any JS-injection stealth layer. It is not a claim about win rates. It is a claim about what is observable.

Undetected-ChromeDriver: patching the driver binary

undetected-chromedriver (uc) is a Selenium drop-in. You import it in place of selenium.webdriver.Chrome, and it downloads ChromeDriver, edits the executable on disk, then launches real Chrome with a sanitised set of flags.

The core trick is small enough to read in one screen. ChromeDriver injects a block of JavaScript into every document that defines variables prefixed with cdc_, which is trivially detectable with a loop over window. uc opens the driver executable in binary mode and rewrites that block, as you can see in patcher.py:

match_injected_codeblock = re.search(rb"\{window\.cdc.*?;\}", content)
if match_injected_codeblock:
    target_bytes = match_injected_codeblock[0]
    new_target_bytes = (
        b'{console.log("undetected chromedriver 1337!")}'.ljust(
            len(target_bytes), b" "
        )
    )

Usage is genuinely two lines, which is a large part of why the project has 12.8k stars:

import undetected_chromedriver as uc

driver = uc.Chrome(headless=False, use_subprocess=True)
driver.get("https://www.sparkproxy.io")
print(driver.title)
driver.quit()

What it fixes

The cdc_ variables go away. The --enable-automation switch and the "Chrome is being controlled by automated test software" infobar are suppressed, and navigator.webdriver is neutralised, which is the flag the W3C WebDriver specification requires a conforming implementation to expose. Because uc drives stock Chrome rather than bundled Chromium, the user agent, codec list, and WebGL strings are the real ones from a real consumer browser. That is a genuine advantage over headless Chromium.

What it does not fix

The replacement string is a fixed literal, so the patch is itself a static signature rather than a randomised one. More importantly, uc leaves the protocol layer completely untouched. ChromeDriver still speaks CDP to Chrome, so every DevTools-level tell that Patchright exists to remove is still present in a uc session. uc is also blunt about what it will not do for you. Its own README says, in bold: "THIS PACKAGE DOES NOT, and i repeat DOES NOT hide your IP address, so when running from a datacenter (even smaller ones), chances are large you will not pass!"

Free trial

Scraping at scale? Skip the blocks.

Fast, unblockable datacentre proxies with unlimited bandwidth.

Patchright: patching the CDP client

Patchright is a drop-in fork of Playwright. Change one import and the rest of your code is unchanged:

from patchright.sync_api import sync_playwright

with sync_playwright() as p:
    ctx = p.chromium.launch_persistent_context(
        user_data_dir="./profile",
        channel="chrome",
        headless=False,
        no_viewport=True,
        proxy={
            "server": "http://gateway.sparkproxy.io:11000",
            "username": "USER",
            "password": "PASS",
        },
    )
    page = ctx.new_page()
    page.goto("https://www.sparkproxy.io")
    print(page.title())
    ctx.close()

The headline patch is the removal of Runtime.enable. Standard Playwright calls the CDP Runtime.enable method to obtain the execution context IDs it needs for page.evaluate(). Enabling that domain changes browser behaviour in a way a page can observe: with the Runtime domain live, objects passed to console methods get serialised for the debugger, so a page can plant a getter on a property, log an object, and watch whether the getter fires. If it fires, a DevTools client is attached. Patchright sidesteps this by evaluating scripts in isolated execution contexts and never enabling the domain.

The documented cost is real and worth reading twice: Patchright disables the Console API, so console output does not work inside Patchright pages. If your scraper pipes browser console logs into your own logging, that breaks.

Patchright also rewrites the launch flags, removing --enable-automation, --disable-popup-blocking, --disable-component-update, --disable-default-apps, and --disable-extensions, and adding --disable-blink-features=AutomationControlled. As a side benefit that has nothing to do with stealth, normal locators and XPath can reach into closed shadow roots, which is useful on component-heavy sites.

The maintainers are explicit about the configuration that works: use channel="chrome" rather than bundled Chromium, run with headless=False, do not override user_agent or headers, and use no_viewport=True with a persistent context. Patchright is Chromium only. Firefox and WebKit are not patched.

Camoufox: patching the browser source

Camoufox is not a library that wraps a browser. It is a browser. The project maintains a patch set against Firefox, builds it, and ships archives per platform, currently on the Firefox 152 line as v152.0.4-beta.28, published 19 July 2026. The Python package is a thin launcher that downloads the matching build and hands you a Playwright browser object over Firefox's juggler protocol.

from camoufox.sync_api import Camoufox

with Camoufox(
    headless="virtual",
    humanize=True,
    geoip=True,
    block_webrtc=False,
    os=["windows", "macos"],
    proxy={
        "server": "http://gateway.sparkproxy.io:11000",
        "username": "USER",
        "password": "PASS",
    },
) as browser:
    page = browser.new_page()
    page.goto("https://www.sparkproxy.io")
    print(page.title())

Because the changes are compiled in, Camoufox covers surfaces a JS shim cannot reach cleanly: navigator and screen properties, WebGL vendor and renderer pairs, AudioContext sample rates, font enumeration, WebRTC address handling at the protocol level rather than by blocking it wholesale, and cursor movement implemented in C++ rather than as scripted mouse events. Fingerprint values come from BrowserForge, which samples from a distribution of real device characteristics so the generated identity is internally consistent instead of a random pile of individually plausible strings. Inconsistency is what usually gets a spoofed fingerprint caught, a point we cover in more depth in our guide to browser fingerprinting.

The geoip=True flag deserves attention. It looks up the exit IP of your proxy and sets timezone, locale, and geolocation to match it. That one option removes the most common self-inflicted mismatch in proxy-based scraping, which is a German residential IP reporting America/New_York.

Two caveats. Camoufox is Firefox, so your traffic sits in a smaller share of real-world browsers and some targets simply behave differently. And the humanize option adds real wall-clock delay to every cursor movement by design, so it is a throughput cost you opt into.

Side-by-side comparison table

undetected-chromedriverPatchrightCamoufox
Patch layerChromeDriver binary on diskPlaywright client, CDP usageFirefox C++ source, compiled
BrowserReal Chrome / ChromiumReal Chrome (recommended)Custom Firefox build
FrameworkSeleniumPlaywrightPlaywright API
LanguagesPythonPython, Node.jsPython (Node via launcher)
Removes `cdc_` varsYesNot applicableNot applicable
Avoids `Runtime.enable`NoYesYes (juggler, not CDP)
Fingerprint spoofingNoneNone by designFull, native level
Proxy authExtension or wrapperNative `proxy` optionNative `proxy` option
Timezone and locale matchingManualManual`geoip=True`
Latest release3.5.5, 17 Feb 20241.62.1, 17 Aug 20260.5.5 launcher, 18 Aug 2026
Drop-in difficultyImport swapImport swapNew browser, new profile model

Maintenance and abandonment risk, with real dates

Staleness is the deciding factor in this category, and it is measurable rather than a matter of opinion. Here is what the registries showed on 18 August 2026.

undetected-chromedriver. The latest release on PyPI is 3.5.5, uploaded 17 February 2024. That is roughly two and a half years old. The repository has exactly one commit newer than that release, from 5 July 2025, a merged community pull request adding Python 3.13 compatibility, and it was never cut into a release. So the artifact pip install undetected-chromedriver gives you predates Chrome 122. Chrome stable is 152.0.7977.42 as of 15 August 2026. The issue tracker sits at 1,141 open issues. The author has moved on and says so: the README of nodriver declares it "the official successor of the Undetected-Chromedriver python package," and nodriver 0.50.3 shipped 13 May 2026. If you are on uc today, nodriver is the migration path the author intends, not a newer uc.

Patchright. Version 1.62.1 landed on PyPI on 17 August 2026, and on npm the same day. Upstream Playwright 1.62.0 was published 31 July 2026. That is a patched fork tracking upstream inside about two and a half weeks, and the same pattern holds across 1.58, 1.59, 1.60, and 1.61. Open issues on the Python repo: 2. This is the healthiest cadence of the three by a wide margin, which matters because a Playwright fork that falls behind upstream stops working with current browser builds.

Camoufox. More nuanced, and worth knowing before you commit. The browser releases run v133 in December 2024, then v135.0.1-beta.24 on 15 March 2025, then nothing until FF146-BETA on 7 January 2026. The PyPI launcher shows the same shape: 0.4.11 on 29 January 2025, then a jump straight to 0.5.3 on 15 July 2026. Camoufox went quiet for most of 2025. It came back hard, with v150, v152.0.2-alpha, and three beta builds in July 2026 alone, plus launcher 0.5.5 on 18 August 2026. The maintainer acknowledges the gap in the README. Read that as a single-maintainer project with real revival risk, currently in a healthy phase, and plan a fallback path rather than assume continuity.

One more calibration point for Camoufox: Firefox stable is 153.0.4, released 14 August 2026, and Camoufox is on the 152 line. Trailing stable by one major version is normal for a project that has to rebase a patch set, and it is a very different situation from trailing by twenty.

What each tool actually defeats

Be precise about the categories, because "gets past Cloudflare" is not a specification.

Detection categoryucPatchrightCamoufox
`navigator.webdriver` flagYesYesYes
ChromeDriver `cdc_` injectionYesNot applicableNot applicable
Automation launch flagsPartlyYesYes
CDP `Runtime.enable` probeNoYesYes
Canvas, WebGL, audio fingerprintNoNoYes
Font enumerationNoNoYes
Timezone vs IP mismatchNoNoYes, via `geoip`
WebRTC local IP leakNoNoYes
TLS and JA3 fingerprintReal ChromeReal ChromeReal Firefox
IP reputationNoNoNo

Note the bottom two rows, because that is where most real failures come from. All three drive a real browser, so the TLS handshake is genuine and TLS fingerprinting is not the problem it is for a raw HTTP client. And none of them touch IP reputation. A perfectly spoofed browser arriving from a flagged datacenter range fails on the first request, which is exactly the point uc's README makes in capital letters. Our writeup on headless browser detection walks through the specific signals detectors combine here.

These three are also a different category from the commercial products covered in our antidetect browser roundup. Those sell managed profile storage and a GUI for account management. These are open-source patches you wire into a scraper.

Proxy support compared

Proxy handling is where the practical gap shows up fastest.

Patchright and Camoufox both inherit Playwright's proxy option, so authenticated upstream proxies work with a dict and nothing else. Both support per-context proxies, so you can run many isolated sessions inside one browser process, each on its own exit IP.

undetected-chromedriver inherits Selenium's weakness here. Chrome's --proxy-server switch takes no credentials, so authenticated proxies need either an IP-allowlisted endpoint or a generated Chrome extension that answers the auth challenge. uc ships helper code for this, but it is a per-browser setting rather than per-context, so N concurrent identities means N browser processes.

Camoufox adds the piece the other two lack, which is coherence between the proxy and the fingerprint:

from camoufox.sync_api import Camoufox

proxy = {
    "server": "http://gateway.sparkproxy.io:11000",
    "username": "USER-country-de-session-a1b2c3",
    "password": "PASS",
}

with Camoufox(proxy=proxy, geoip=True, locale="de-DE", humanize=True) as browser:
    page = browser.new_page()
    page.goto("https://www.sparkproxy.io/pricing")

With a sticky session on a German residential exit, geoip=True sets timezone and geolocation to match that exit automatically. Getting the same result in Patchright or uc means looking up the IP yourself and overriding timezone through CDP, on every rotation. If you are deciding which pool to point these at, residential vs datacenter proxies covers the tradeoff.

Resource cost and concurrency

Concrete numbers vary too much by target and hardware to quote as benchmarks, so here is the structural cost instead.

uc is the most expensive per identity. No per-context proxies means one Chrome process per identity, and Chrome with a fresh profile is the heaviest of the three. It also patches the driver binary on first run, which adds start-up time and needs write access to the driver path, something container images with a read-only filesystem will refuse.

Patchright costs what Playwright costs, plus the overhead of the maintainers' recommended configuration, which is the real story. headless=False means you need Xvfb or a real display on Linux, and a persistent context per identity means disk churn for profile directories. Headed browsers use noticeably more RAM than headless ones.

Camoufox ships a debloated Firefox and the project claims roughly a 200MB memory footprint per instance, which is a project claim rather than an independent measurement. It also offers headless="virtual", which manages a virtual display for you on Linux instead of making you wire up Xvfb yourself. Against that, humanize adds latency by design, and every launch loads a generated fingerprint.

Rough ordering on a fixed box: Camoufox and Patchright land in similar territory, with Camoufox usually lighter per instance and Patchright usually faster per page, while uc costs the most per concurrent identity because of the process-per-proxy constraint.

How to choose in 2026

Choose Patchright if your codebase is already Playwright, you need Node.js as well as Python, or you need Chrome specifically because the target renders differently on Firefox. It is the lowest-friction change on this page: one import, plus moving to channel="chrome" and a persistent context.

Choose Camoufox if fingerprint surfaces are what is getting you caught, if you rotate identities across geographies and need timezone and locale to follow the exit IP, or if you want the patch to live somewhere a page script cannot inspect. Accept that you are on Firefox and that the project has one primary maintainer.

Choose undetected-chromedriver only if you have an existing Selenium codebase that already works and you are maintaining rather than building. For anything new, go to nodriver from the same author, or to Patchright.

Run two of them if the target justifies it. A useful production pattern is Patchright as the default because it is cheaper per page, with a Camoufox fallback triggered by a challenge response, so you only pay the heavier cost on the requests that need it.

When you should not run a stealth browser at all

A patched browser is the right tool when the data only exists after JavaScript runs and the target actively fingerprints. It is the wrong tool when you are paying browser costs for HTML you could have fetched, and it always leaves behind the one problem none of these three solve, which is IP reputation and the operational work of keeping a pool healthy.

If you would rather not maintain browser builds, patch sets, and a proxy pool, SparkProxy's Scraping API does the rendering and the exit IP in one call:

curl -G "https://scrape.sparkproxy.io/api/v1" \
  -H "X-API-Key: YOUR_API_KEY" \
  --data-urlencode "url=https://www.sparkproxy.io/pricing" \
  --data-urlencode "render_js=true" \
  --data-urlencode "stealth=true" \
  --data-urlencode "premium_proxy=true" \
  --data-urlencode "country_code=DE"

The same thing in Python, with a sticky session so a multi-step flow stays on one exit IP:

import requests

params = {
    "url": "https://www.sparkproxy.io/pricing",
    "render_js": "true",
    "stealth": "true",
    "premium_proxy": "true",
    "country_code": "DE",
    "session_id": "de-run-01",
    "wait_for": "#pricing-table",
    "format": "md",
}

r = requests.get(
    "https://scrape.sparkproxy.io/api/v1",
    headers={"X-API-Key": "YOUR_API_KEY"},
    params=params,
    timeout=120,
)
r.raise_for_status()
print(r.text[:500])

stealth=true adds 5 credits and a premium proxy with JS rendering costs 25, so this is not free, and self-managed browsers plus your own pool are cheaper at high volume on easy targets. The tradeoff is covered properly in web scraping API vs self-managed proxies.

Frequently asked questions

FAQ

Not actively. The last PyPI release is 3.5.5 from 17 February 2024, and the repository has one commit since then, from July 2025, that was never released. The author now points users to nodriver as the official successor.

Patchright is a fork of Playwright itself, so it changes how the client talks to the browser and can remove protocol-level tells such as Runtime.enable. Stealth plugins run JavaScript inside the page to redefine properties, which sits a layer above and is itself detectable through property descriptors and toString output.

Mostly yes. Camoufox exposes the Playwright API through Firefox's juggler protocol, so page, locator, and context calls carry over. What does not carry over is anything Chromium-specific, including CDP sessions, Chrome extensions, and channel="chrome" launch options.

Both accept Playwright's proxy dictionary with server, username, and password, per browser or per context. undetected-chromedriver cannot do this natively, because Chrome's --proxy-server switch takes no credentials, so it needs an IP allowlist or a generated auth extension.

Camoufox, because it modifies navigator, screen, WebGL, audio, font, and WebRTC surfaces inside the browser's C++ rather than by injecting JavaScript, so the values read as native. undetected-chromedriver and Patchright do not spoof fingerprints at all; they remove automation tells and leave the real browser's fingerprint in place.

No. None of these tools change your IP, and undetected-chromedriver's own README warns in bold that requests from a datacenter range will usually fail regardless of how clean the browser looks. Fingerprint work and IP reputation are separate problems that have to be solved together.

Special Discount ยท 20% off

Get 20% off your first month

Premium datacentre proxies with unlimited bandwidth. Use the code at checkout.

Save up to 15% more on quarterly, half-yearly and yearly plans

Claim Discount

About the Author

The SparkProxy Technical Team builds and operates SparkProxy's datacenter proxies, residential proxies, and Scraping API. We test browser automation stacks against live anti-bot deployments as part of maintaining our own rendering infrastructure, and the release data in this article was pulled from PyPI, npm, and the GitHub releases API on 18 August 2026. Questions or corrections: support@sparkproxy.io.

Keep reading

Related articles