The One Thing Most undetected-chromedriver Proxy Guides Get Wrong
undetected-chromedriver builds on Selenium and patches ChromeDriver so an automated Chromium presents a consistent, realistic fingerprint. Setting a proxy host is easy — one --proxy-server argument. What trips people up is the username and password: Chromium does not read credentials from the --proxy-server value, so the http://USER:PASS@HOST:PORT you'd use with requests silently drops the USER:PASS part, and your first navigation fails with 407 Proxy Authentication Required.
Plain undetected-chromedriver has no clean way to answer that auth challenge. The standard fix is selenium-wire, which extends Selenium's bindings and injects the credentials for you — and it ships a drop-in undetected_chromedriver wrapper, so you keep the patched driver and gain authenticated-proxy support in one import.
undetected-chromedriver is a library for reaching public data reliably, not a tool for defeating access controls. The other half of that reliability is the egress IP: a real German mobile IP with solid IP reputation is what a well-behaved crawler needs on German platforms.
Before You Start
You need four values from your GermanProxy.io account:
- Host and port of your endpoint
- Username and password
The examples use PROXY_HOST, PORT, USER and PASS as placeholders — replace them with your own. Install the libraries (Python 3.8+):
pip install undetected-chromedriver selenium-wire
selenium-wire pins blinker==1.7.0 — newer releases of that dependency break it, so install it in a clean virtual environment.
Step 1 — Set the Proxy Host (no auth)
If your endpoint uses IP-allowlist authentication, plain undetected-chromedriver is enough. The host and port go in a Chrome option:
import undetected_chromedriver as uc
from selenium.webdriver.common.by import By
PROXY_HOST = "PROXY_HOST"
PORT = "PORT"
options = uc.ChromeOptions()
options.add_argument(f"--proxy-server={PROXY_HOST}:{PORT}")
driver = uc.Chrome(options=options, use_subprocess=False)
driver.get("https://www.example.de")
print("Title:", driver.title)
driver.quit()
For a credential-based endpoint, this argument can't carry the username and password — move to selenium-wire in the next step.
Step 2 — Add Username/Password Auth with selenium-wire
Import selenium-wire's undetected_chromedriver (same patched driver, plus request handling) and pass the authenticated endpoint in seleniumwire_options:
import seleniumwire.undetected_chromedriver as uc
from selenium.webdriver.common.by import By
PROXY_HOST = "PROXY_HOST"
PORT = "PORT"
USER = "USER"
PASS = "PASS"
proxy_url = f"http://{USER}:{PASS}@{PROXY_HOST}:{PORT}"
seleniumwire_options = {
"proxy": {
"http": proxy_url,
"https": proxy_url,
"no_proxy": "localhost,127.0.0.1",
}
}
options = uc.ChromeOptions()
driver = uc.Chrome(
options=options,
seleniumwire_options=seleniumwire_options,
use_subprocess=False,
)
driver.get("https://www.example.de")
print("Title:", driver.title)
driver.quit()
selenium-wire passes the credentials for you — no auth pop-up to answer, no extension to build. For a SOCKS5 endpoint, swap the scheme to socks5 (or socks5h to resolve DNS at the proxy) in proxy_url.
Step 3 — Verify the IP Before You Scale
Confirm you're actually on a German mobile IP before you build anything on top of it. Point the driver at an IP-echo endpoint and read the result:
driver.get("https://api.ipify.org?format=json")
print("Egress IP:", driver.find_element(By.TAG_NAME, "body").text)
If it returns your own address, re-check that the scheme, host, port and credentials are all present in proxy_url. For a fuller checklist, see checking your proxy configuration. A persistent 407 points at the credentials — see how to fix 407 proxy authentication required.
Step 4 — Check for WebRTC and DNS Leaks
A proxy routes Chromium's HTTP traffic, but the browser has two side channels that can expose your real address:
- WebRTC can surface your local IP via ICE candidates even with a proxy set — see what a WebRTC leak is.
- DNS can resolve names outside the tunnel depending on configuration — see what a DNS leak is.
For data-collection work in headless mode WebRTC is usually inert, but verify it for any flow where IP consistency matters. A real German mobile IP only helps if nothing else leaks past it — walk through both with how to check a proxy for leaks.
HTTP vs. SOCKS5 in undetected-chromedriver
Both protocols come with your endpoint. Which to use depends on what you need:
| Aspect | HTTP endpoint | SOCKS5 endpoint |
|---|---|---|
| Where it goes | --proxy-server=HOST:PORT or seleniumwire_options |
--proxy-server=socks5://HOST:PORT or socks5:// URL |
| Username/password auth in Chromium | Yes, via selenium-wire | No — Chromium has no SOCKS5 user/pass auth |
| Best auth mode | Credentials | IP allowlist |
| Typical use | Default for most scraping | Lower-level / non-HTTP traffic |
For most undetected-chromedriver scraping, the HTTP endpoint with selenium-wire is the simplest path for credential auth. Reach for SOCKS5 when you specifically need it and can use IP-allowlist authentication. Background: SOCKS5 vs HTTP proxy.
Sticky Sessions vs. Rotation
With a dedicated German endpoint you control the IP at the proxy, not in your code:
- Sticky session: keep one driver open across a multi-step flow — login, navigate, paginate — and the German mobile IP stays the same.
- Rotation on demand: when you want a fresh IP, trigger rotation at the proxy and start a new driver. There's no per-request IP pool to manage.
This is why a dedicated endpoint keeps the code small: no rotation list, no health-checking, no retry-on-dead-IP loop. See sticky sessions and IP rotation explained and dedicated vs shared mobile proxy.
Why a Mobile IP for undetected-chromedriver at All
undetected-chromedriver is a common choice for JavaScript-heavy pages that a plain HTTP client can't render — product pages, SERPs, dashboards. The catch is the egress IP: datacenter ranges are widely distrusted, so even a perfectly behaved crawler can hit friction. A real German mobile IP rides on carrier-grade NAT (CGNAT), the same shared-IP space thousands of ordinary phone users sit behind, which is why it carries higher IP reputation on German platforms — the point that matters more than any browser-side setting, since websites also detect proxies by the IP itself.
For the trade-offs against other IP types, see mobile vs residential vs datacenter proxy and what is a mobile proxy.
Scrape Responsibly
A mobile proxy improves reliability for legitimate data collection — it is not a tool to circumvent access controls or platform rules. Keep your undetected-chromedriver crawl clean and defensible:
- Respect each site's terms and its
robots.txt; collect only public data you're permitted to use. - Throttle with realistic delays between navigations so you don't overload servers — a full Chromium is heavier than a plain HTTP client.
- Collect only what you need, and handle any personal data in line with the GDPR. See EU rules on scraping.
- Be honest about who you are — don't impersonate a service or misuse a target's security mechanisms.
Whether mobile proxies themselves are lawful to use: are mobile proxies legal.
FAQ
How do I set a proxy in undetected-chromedriver?
Add it to ChromeOptions: options.add_argument('--proxy-server=PROXY_HOST:PORT'), then pass options to uc.Chrome(). That covers an IP-allowlisted endpoint. For a proxy that needs a username and password, Chromium ignores credentials in the flag — use selenium-wire instead.
How does undetected-chromedriver handle username/password proxy auth?
Import seleniumwire.undetected_chromedriver as uc and pass the endpoint in seleniumwire_options under a proxy key with http and https URLs that include USER:PASS. selenium-wire injects the credentials for you, so you avoid the brittle auth pop-up that plain undetected-chromedriver can't answer.
Why does undetected-chromedriver ignore the credentials in my proxy URL?
Because Chromium does not read a username and password from the --proxy-server flag. Passing http://USER:PASS@HOST:PORT drops the credentials and your first navigation fails with 407 Proxy Authentication Required. selenium-wire handles the credentials outside the flag, which is why it is the clean path — see how to fix 407 proxy authentication required.
Can undetected-chromedriver use a SOCKS5 mobile proxy?
Yes. Use --proxy-server=socks5://PROXY_HOST:PORT in ChromeOptions. Chromium cannot do SOCKS5 username/password auth, so a SOCKS5 endpoint works best with IP-allowlist authentication; for credential auth, use the HTTP endpoint through selenium-wire. See HTTP or SOCKS5 — which fits your stack.
How do I rotate IPs with undetected-chromedriver?
With a dedicated German endpoint you rotate on demand at the proxy, not per request in code. For a sticky session, keep one driver open across the flow; to get a fresh IP, trigger rotation at the proxy and start a new driver. See sticky sessions and IP rotation explained.
Should I use nodriver instead of undetected-chromedriver?
nodriver is the newer library from the same author and drives Chromium over the DevTools Protocol without Selenium. undetected-chromedriver is still widely used and pairs cleanly with selenium-wire for proxy auth. Both present a consistent, realistic browser for reaching public data. Compare the nodriver setup and the Selenium setup.
Related guides
- nodriver Proxy Setup: Route Chrome via German Mobile IPs
- Patchright Proxy Setup: Route via German Mobile IPs
- Selenium Proxy Setup with Python: German Mobile IPs
CTA
Drive undetected-chromedriver on real German mobile IPs. Get a German mobile proxy — HTTP/SOCKS5/OpenVPN, sticky sessions, on-demand rotation, fair-use 20 GB/day, from a transparent EU provider.
Get a German mobile proxy: Real 4G/5G IPs from Germany, fair-use 20 GB/day — compare German mobile proxy plans or start with a dedicated 5G proxy.