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-chromedriverimport 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:
| Signal | Can UC fix it? |
|---|---|
Selenium/ChromeDriver fingerprints, navigator.webdriver | Yes — 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 fingerprint | No — 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.
Is it legal to use?
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.