Documentation Blog Free tools [email protected]Log in

How to use undetected-chromedriver in Python: setup, proxies and limits

undetected-chromedriver patches the Selenium tells but IP reputation and behavior remain outside its reachUC patchescdc_ automation varsnavigator.webdriverSelenium fingerprintspasses Cloudflare JSthe driver-level tellsStill visibledatacenter IPrequest rate / behaviorTLS fingerprintwhat UC can't reachAdd to surviveresidential proxyhuman pacing= real-user profile

undetected-chromedriver is a Python library that launches a patched Selenium Chrome driver engineered to evade the bot detection that flags vanilla Selenium. You install it, swap your driver for its Chrome(), and it strips the automation tells that give Selenium away — enough to pass many Cloudflare-style JavaScript checks. It is not magic, though: IP reputation and behavior are outside what it can fix.

What it is and why it exists

Vanilla Selenium is trivially detectable. It sets navigator.webdriver to true, injects tell-tale cdc_ variables into the page, and carries ChromeDriver fingerprints that anti-bot scripts specifically look for. undetected-chromedriver patches these at the driver level — it modifies the ChromeDriver binary and runtime so those signals look like a normal Chrome. The result passes the automated-browser checks that block standard Selenium instantly, which is why it became the go-to for Selenium users hitting Cloudflare and similar walls.

Setup

Install and use it as a near drop-in for the standard driver:

pip install undetected-chromedriver
import undetected_chromedriver as uc

driver = uc.Chrome(headless=False)   # patched driver
driver.get("https://example.com")
print(driver.title)
driver.quit()

That is the whole basic integration — the API mirrors Selenium's, so existing scripts mostly work by swapping the import and the Chrome() constructor. One important note: run it headed where you can (or headless with a virtual display like Xvfb on a server). Pure headless mode leaks additional signals that undo much of the patching, so headless-by-default is a common reason it "stops working."

Adding a proxy

Proxies pass through Chrome options, the same as normal Selenium:

options = uc.ChromeOptions()
options.add_argument("--proxy-server=http://pr.quanticdata.io:7777")
driver = uc.Chrome(options=options, headless=False)

Authenticated proxies are the friction point — Chrome's --proxy-server flag doesn't take user:pass@, so you either use a proxy extension for credentials or an endpoint that authenticates by IP allowlist. The cleaner path for scraping is a rotating endpoint that hands out a fresh IP per request, so a single proxy argument gives you rotation without extension gymnastics.

Version pinning: the maintenance reality

One practical detail that catches everyone: undetected-chromedriver is tightly coupled to your installed Chrome version, and it auto-downloads a matching driver. When Chrome updates, the pairing can break, and you'll see the driver fail to start or suddenly get detected again. Pin your Chrome version in production, or pin undetected-chromedriver to a release known to work with it, and treat Chrome updates as a change that needs re-testing rather than something to apply blindly. Teams that skip this discover it the hard way when an unattended Chrome update silently breaks a scraper overnight. The library is actively maintained, but the Chrome-driver-detector triangle means you own the job of keeping those three in sync.

What it can't do — the ceiling

undetected-chromedriver patches driver- and browser-level tells. It has no effect on the signals detectors weight most:

SignalCan UC fix it?
Selenium/ChromeDriver fingerprints, navigator.webdriverYes — this is its whole job
IP reputation (datacenter ranges, request rate)No — that's your network
Behavior (robotic timing, mouse, scroll)No — you generate that
TLS fingerprintNo — below the browser layer

So the pattern teams hit: undetected-chromedriver passes the JavaScript challenge, then they still get blocked because they're hammering from a flagged datacenter IP at machine speed. The fix is not more UC — it's the layers UC can't reach. Route through residential proxies so the IP looks like a real home user, and pace requests like a human. UC plus a residential IP plus realistic timing is genuinely hard to distinguish from a person; it's the same three-part recipe we describe for Playwright stealth, and it applies to Selenium here.

Using undetected-chromedriver is not itself illegal — it's an open-source tool, and evading bot detection to scrape public data sits in the same legal space as any scraping: generally lawful for public, non-personal data, riskier when you circumvent authentication, ignore a cease-and-desist, or harvest personal data. The tool doesn't change the legality of the activity, only the technical outcome. For where those lines actually sit, see is web scraping legal. As always, this is information, not legal advice.

When to stop maintaining it

undetected-chromedriver works, but it's a moving target: detectors update, the library races to keep up, and your success rate silently drops until you upgrade. That maintenance — plus running a browser fleet and proxies — is real engineering time spent on evasion instead of data. Past some volume it's cheaper to offload the whole fight: a scraping API handles the browser, residential proxies, fingerprint and anti-block server-side and returns clean Markdown or JSON. Keep undetected-chromedriver for the interactive or logged-in flows where you need a real browser under your control; hand the high-volume, gets-blocked scraping to an API built to win that arms race so you don't have to fight it every week.

Sources & further reading

FAQ

Quick answers on how to use undetected chromedriver python.

Something else? Ask us →

Does undetected-chromedriver still work in 2026?

Yes, against the detection layer it targets — driver and browser fingerprints, navigator.webdriver, the cdc_ variables — it still passes many Cloudflare-style JavaScript checks. But it's an arms race: detectors update and the library lags, so success rates drift and you need to keep it upgraded. It doesn't beat IP-reputation or behavioral detection at all.

How do I add a proxy to undetected-chromedriver?

Pass it through Chrome options: options.add_argument('--proxy-server=http://host:port'). Authenticated proxies are the friction point because Chrome's flag doesn't accept user:pass@ — use a proxy extension for credentials, or an endpoint that authenticates by IP allowlist. A rotating endpoint is cleanest, giving per-request IPs from one proxy argument.

Why does undetected-chromedriver get detected anyway?

Two common reasons. First, running pure headless — it leaks signals that undo the patching, so run headed or with a virtual display. Second, the layers it can't touch: a flagged datacenter IP and robotic timing still identify you as a bot. Add residential proxies and human-like pacing, not more UC.

Is undetected-chromedriver legal to use?

The tool itself is legal open-source software. Using it to scrape public, non-personal data sits in the same legal space as any scraping — generally lawful, but riskier if you circumvent authentication, ignore a cease-and-desist, or collect personal data. Evading bot detection doesn't change the legality of the underlying activity. Not legal advice.

Should I run undetected-chromedriver headless?

Prefer headed, or headless with a virtual display like Xvfb on a server. Pure headless mode leaks additional signals that undo much of the driver's patching, which is a frequent reason it appears to stop working. If you must run headless, expect to add more layers — residential proxies and realistic behavior — to compensate.

Stop fighting the detection arms race weekly

Hand high-volume scraping to an API that runs the browser, residential proxies and anti-block for you — clean Markdown or JSON out, pay per success. $2 of free usage every month.

Related reading