undetected-chromedriver vs nodriver vs SeleniumBase: Which to Use in 2026 (with Proxies)

Developer guide · Last reviewed 20 October 2026 · 17 min read

undetected-chromedriver, nodriver and SeleniumBase all answer the same question: how do you drive a real Chrome from Python without the browser announcing that it is being automated? They answer it in different ways. undetected-chromedriver patches ChromeDriver, nodriver drops WebDriver and talks to Chrome over the DevTools Protocol, and SeleniumBase wraps both ideas in a full framework. This comparison explains why stock Selenium is easy to spot, how each tool works, how well each one is maintained in October 2026, and how to run each behind an authenticated ProxyEmpire proxy with one sticky IP per browser.

The short version

For new projects in 2026, pick SeleniumBase or nodriver. Treat undetected-chromedriver as legacy. undetected-chromedriver’s last PyPI release is 3.5.5 from February 2024. nodriver, from the same author, is its official successor: async, no WebDriver, and it can run an authenticated proxy per browser context through a built-in local forwarder. SeleniumBase is the most actively maintained of the three and the only one with a documented proxy="user:pass@host:port" argument. Its UC Mode and CDP Mode give you the same stealth ideas with a synchronous API. Chrome’s --proxy-server flag can’t take a username and password, so how each tool gets around that is often what decides it.

Key takeaways

  • A stock ChromeDriver session leaves visible traces: navigator.webdriver, automation launch switches, injected driver variables and side effects of DevTools Protocol use.
  • undetected-chromedriver patches the driver. nodriver removes the driver entirely. SeleniumBase offers both styles (UC Mode and CDP Mode) inside a test and automation framework.
  • undetected-chromedriver has had no PyPI release since February 2024. nodriver and SeleniumBase both shipped releases in October 2026.
  • Chrome’s --proxy-server switch has no field for credentials. SeleniumBase accepts user:pass@host:port directly, and nodriver accepts credentials in create_context(proxy_server=...). With undetected-chromedriver you have to bring your own workaround.
  • Use the http:// proxy URL with all three. Chromium does not do username/password authentication on SOCKS5 proxies.
  • Map one ProxyEmpire sticky session (sid) to one browser or browser context, so cookies and IP stay consistent.
  • Stealth tooling doesn’t replace permission. Use it for public data and for systems you are allowed to test.

Why Default Selenium and ChromeDriver Are Easy to Detect

The browser tells on itself

Selenium drives Chrome through ChromeDriver, which speaks the W3C WebDriver protocol to your script and the Chrome DevTools Protocol (CDP) to the browser. That arrangement was built for testing, where nobody wants to hide automation. Several signals follow from it, and anti-bot systems read all of them:

  • The WebDriver flag. The WebDriver specification says a browser under automation should report navigator.webdriver as true. Any script on the page can read it.
  • Launch switches. When ChromeDriver launches Chrome it adds automation-related switches and preferences. These change small details of browser behavior and UI that a page can notice.
  • Driver artifacts. ChromeDriver has historically injected helper variables into pages. SeleniumBase’s documentation calls them the “Chrome DevTools Console variables” that UC Mode renames, because a plain Selenium session exposes them.
  • CDP side effects. Enabling some DevTools domains has side effects that page JavaScript can observe. Detection scripts probe for them. Our explainer on WebDriver BiDi vs CDP covers how the two protocols differ.
  • Headless differences. Older headless modes differed from headed Chrome in user agent, rendering and available APIs. The headless browsers primer walks through the differences.
  • Network identity. None of the above concerns your IP address. A perfect browser fingerprint still looks wrong coming from a datacenter range that has sent a million requests today.

You can see the first signal in four lines:

Example 1 — a stock Selenium session reports itself (Python)
from selenium import webdriver

driver = webdriver.Chrome()  # Selenium Manager fetches a matching chromedriver
try:
    driver.get("https://example.com")
    print(driver.execute_script("return navigator.webdriver"))  # True
finally:
    driver.quit()

Commercial bot-management products combine these browser signals with TLS and HTTP fingerprints, behavior over time and IP reputation. Our DataDome bot detection explainer describes one vendor’s layered model in neutral terms. The tools below work on the browser layer only. None of them changes the network layer. The undetected-chromedriver README says plainly that the package doesn’t hide your IP, and that runs from datacenter or low-reputation addresses will probably still fail.

How Each Tool Approaches the Problem

Patch the driver, drop the driver, or wrap both
Figure 1 — three control paths into Chrome
Stock Selenium
  script --WebDriver--> chromedriver --CDP--> Chrome   (launched by the driver)

undetected-chromedriver
  script --WebDriver--> patched chromedriver --CDP--> Chrome
                        (driver binary patched, browser started with
                         a cleaner launch, Selenium API kept)

nodriver
  async script ------------------CDP websocket------> Chrome
                        (no chromedriver, no Selenium)

SeleniumBase
  UC Mode:   script --WebDriver--> uc_driver --> Chrome
             (driver disconnects during sensitive steps)
  CDP Mode:  script --CDP (MyCDP)--> Chrome
             (activate_cdp_mode() hands control to CDP;
              sb_cdp / cdp_driver skip WebDriver entirely)

undetected-chromedriver: a patched ChromeDriver

undetected-chromedriver (imported as undetected_chromedriver, usually aliased uc) keeps the Selenium API you already know. When it starts it downloads a ChromeDriver binary, patches it and launches Chrome in a way that avoids the usual automation markers. In the 3.4.0 rewrite, according to its changelog, the package stopped renaming the driver’s variables after the fact and started preventing them from being injected at all. You get a uc.Chrome object that is a Selenium WebDriver, so existing locators, waits and page objects mostly carry over. The cost is that WebDriver is still connected the whole time, and everything depends on a patch that has to keep up with Chrome releases.

nodriver: no WebDriver, CDP directly, async

nodriver is by the same author and is described in its README as the official successor of undetected-chromedriver. It has no ChromeDriver binary and no Selenium dependency. It starts Chrome (or Chromium, Edge or Brave) and talks CDP over a websocket. The API is fully asyncio: await uc.start(), await browser.get(url), await tab.select("css"), await tab.find("text"). Element lookup retries until a timeout, so you write fewer explicit waits. Each run gets a fresh profile that is cleaned up on exit unless you pass user_data_dir. With no WebDriver layer there is nothing WebDriver-shaped to detect. Detection scripts can still look for CDP side effects, though, so “no WebDriver” does not mean invisible.

SeleniumBase: a framework with UC Mode and CDP Mode

SeleniumBase is a complete Python framework for testing and automation: a pytest plugin, context managers, a recorder, reporting, and hundreds of helper methods. Its stealth features come in layers:

  • UC Mode (SB(uc=True) or Driver(uc=True)) started out from undetected-chromedriver. The UC Mode docs name three techniques. It renames the driver’s console variables, launches Chrome before attaching the driver, and disconnects the driver during sensitive actions.
  • CDP Mode (sb.activate_cdp_mode(url)) disconnects WebDriver and drives the browser over CDP using SeleniumBase’s MyCDP library. The docs present it as the successor to plain UC Mode. In CDP Mode, many sb.* methods redirect to their sb.cdp.* versions.
  • Pure CDP Mode (from seleniumbase import sb_cdp, then sb_cdp.Chrome(url)) skips WebDriver entirely. There is also an async form, cdp_driver.start_async(), whose method names closely follow nodriver’s.

In practice, SeleniumBase gives you the ideas behind undetected-chromedriver and nodriver with a synchronous API and much more around them, including the most complete proxy handling of the three.

undetected-chromedriver vs nodriver vs SeleniumBase: Comparison Table

Verified against repositories and PyPI on 20 October 2026
Criterionundetected-chromedrivernodriverSeleniumBase
ApproachPatched ChromeDriver, Selenium APINo WebDriver; CDP over websocketFramework: UC Mode (patched driver) + CDP Mode
API styleSelenium WebDriverOwn API: start, get, select, findSB() context manager, Driver(), sb_cdp, pytest
AsyncNoYes, async onlySync by default; async via cdp_driver
Latest PyPI release3.5.5 (17 Feb 2024)0.50.6 (8 Oct 2026)4.56.2 (16 Oct 2026)
Proxy authNot built inPer context: create_context(proxy_server="http://user:pass@...")Built in: proxy="user:pass@host:port"
Learning curveLow if you know SeleniumMedium: asyncio and a new APILow to start, large surface area
LicenseGPL-3.0AGPL-3.0MIT
Best forKeeping existing uc scripts aliveAsync pipelines, many contexts per browserNew projects, teams, built-in proxy auth

Licensing matters more than people expect. nodriver is AGPL-3.0 and undetected-chromedriver is GPL-3.0. If you ship software that bundles either one, or run nodriver inside a network service you expose to others, get your legal team’s view on the AGPL’s obligations. SeleniumBase is MIT.

Maintenance Status in October 2026

Release dates matter more than star counts

Stealth tools go stale quickly. Chrome ships a new major version roughly every four weeks, and detection vendors update their scripts continuously. A tool that was excellent eighteen months ago may now fail on the first page load. Here is what the GitHub API and PyPI showed on 20 October 2026:

  • undetected-chromedriver. Last push to the repository: 5 July 2025, a merged pull request that replaces distutils for Python 3.12 and 3.13 compatibility. Last PyPI release: 3.5.5, published 17 February 2024. The repository is not archived, but the issue tracker has more than 1,000 open issues and pull requests. The published 3.5.5 package imports distutils, which Python 3.12 removed. On current Python versions you will typically need setuptools installed or an install from the GitHub master branch.
  • nodriver. Last push: 8 October 2026, after protocol and bug-fix commits that same week. Latest PyPI release: 0.50.6, published 8 October 2026. PyPI declares requires_python >=3.9, but 0.50.6 fails to import on Python 3.9 because it uses str | Path type syntax at runtime. Plan on Python 3.10 or newer.
  • SeleniumBase. Last push: 19 October 2026. Latest release: v4.56.2, published 16 October 2026. It requires Python 3.10 or newer. Commits land several times a week, and the source contains explicit workarounds for recent Chrome changes, including a comment about a Chrome 142 extension fix.

Check before you commit. These dates will be out of date soon. Run curl -s https://api.github.com/repos/OWNER/REPO and look at pushed_at, then check the release history on PyPI. A stealth library with no release in a year is a maintenance liability, however good its README looks.

The Proxy-Authentication Problem

Chrome’s proxy flag has no password field

Every one of these tools ends up launching Chrome, and Chrome takes its proxy from the --proxy-server switch. That switch accepts a scheme, host and port, such as http://host:port. It does not accept a username and password. When an authenticated proxy answers with 407 Proxy Authentication Required, Chrome expects someone to answer the challenge: a person at a login dialog, an extension, or an automation client listening for the auth event.

ProxyEmpire authenticates by username and password, and does not use IP whitelisting. The username also carries your targeting and session settings. So “just whitelist the server IP and skip credentials” is not an option here, and it would be a poor fit for rotating cloud workers anyway. There are four common ways to supply credentials:

Runtime extensionGenerate a small extension that sets the proxy and answers the auth challenge. SeleniumBase does this for you. Branded Chrome keeps tightening how extensions load from the command line, so this route needs maintenance.
CDP auth handlingEnable the DevTools Fetch domain with auth handling and answer Fetch.authRequired with the credentials. SeleniumBase’s CDP driver does this.
Local forwarderRun an unauthenticated proxy on 127.0.0.1 that adds the Proxy-Authorization header upstream, and point Chrome at it. nodriver does this inside create_context().
Use the frameworkLet a maintained library own the plumbing. In 2026 this is the main reason to choose SeleniumBase or nodriver over undetected-chromedriver.

Before you debug any browser code, check the credentials on their own. Copy the username and password from Proxy Manager → Connection Builder in the ProxyEmpire dashboard and run:

Example 2 — confirm the proxy works outside the browser (shell)
curl -x http://USERNAME:[email protected]:5000 https://api.ipify.org

If that prints an IP, the proxy is fine and any remaining problem is in the browser setup. If it returns a 407, fix the credentials first. Our guide to proxy error codes lists the usual causes. Use the http:// form in the browser as well. Chromium does not do username/password authentication on SOCKS5 proxies. The SOCKS vs HTTP comparison explains why you lose little by using HTTP here.

undetected-chromedriver with a Proxy

Workable, but you bring the auth layer

undetected-chromedriver has no proxy parameter. You pass Chrome switches through uc.ChromeOptions(), the same way you would with plain Selenium. The project’s own README shows only an unauthenticated proxy (a local Tor SOCKS port). Because --proxy-server cannot carry credentials, the clean pattern is to point Chrome at a local forwarder on 127.0.0.1 that holds the ProxyEmpire credentials:

Example 3 — undetected-chromedriver behind a local forwarder (Python)
import undetected_chromedriver as uc

# Chrome takes host:port only. 127.0.0.1:8899 is a local forwarder you run,
# which adds your ProxyEmpire username and password to the upstream
# connection to v2.proxyempire.io:5000.
LOCAL_FORWARDER = "http://127.0.0.1:8899"


def main():
    options = uc.ChromeOptions()
    options.add_argument(f"--proxy-server={LOCAL_FORWARDER}")
    driver = uc.Chrome(options=options)  # version_main=NNN pins a Chrome major
    try:
        driver.get("https://api.ipify.org?format=json")
        print(driver.find_element("tag name", "body").text)
    finally:
        driver.quit()


if __name__ == "__main__":
    main()  # uc starts Chrome in a subprocess; keep the main guard

Where does the forwarder come from? There are three honest answers:

  1. Your own infrastructure. Many teams already run a forward proxy such as Squid next to their workers, configured with an authenticated upstream (parent) proxy. Chrome connects without credentials and the forwarder adds them. Bind it to localhost only, so you aren’t running an open proxy.
  2. A runtime extension. You can generate an extension that calls chrome.proxy.settings and answers onAuthRequired, then load it with --load-extension. This is the approach SeleniumBase automates. Recent branded Chrome releases restrict command-line extension loading, so test against the exact Chrome version you deploy, or use Chromium or Chrome for Testing.
  3. Move to SeleniumBase UC Mode. It descends from undetected-chromedriver, keeps a Selenium-style API, and takes proxy="user:pass@host:port" directly. For most uc users this is the least effort.

For the plain-Selenium side of this problem, including extension-based auth in detail, see our Selenium proxy with ChromeDriver and Python guide. The same techniques apply to uc.Chrome, because it is a Selenium driver underneath.

nodriver with a Proxy

Authenticated proxies per browser context

nodriver’s start() has no proxy argument. You could pass --proxy-server in browser_args, but that is limited to unauthenticated proxies. The useful feature is Browser.create_context(). It creates a new, isolated browser context (separate cookies and storage) with its own proxy, and opens a tab in it. In nodriver 0.50.6, if the proxy_server string contains credentials, nodriver starts a small local forwarder on a free port. The forwarder adds the Proxy-Authorization header upstream and points the new context at itself. The method’s docstring covers both http://USERNAME:PASSWORD@SERVER:PORT and socks://... forms. The docs mark the proxy parameters as experimental.

Example 4 — nodriver with an authenticated ProxyEmpire context (Python)
import os

import nodriver as uc

PROXY_URL = "http://{user}:{password}@v2.proxyempire.io:5000".format(
    user=os.environ["PE_USER"],  # copied from the Connection Builder
    password=os.environ["PE_PASS"],
)


async def main():
    browser = await uc.start()
    # The default context is NOT proxied. Do all work in the proxied one.
    tab = await browser.create_context(
        "https://api.ipify.org?format=json",
        proxy_server=PROXY_URL,
    )
    await tab.sleep(2)
    print(await tab.evaluate("document.body.innerText", return_by_value=True))
    browser.stop()


if __name__ == "__main__":
    # The README uses nodriver's own loop helper rather than asyncio.run()
    uc.loop().run_until_complete(main())

Three details from reading nodriver’s source, worth knowing before you go to production:

  • The first window goes direct. Only the context you create with proxy_server is proxied. The default context that start() opens is not, so don’t navigate in it.
  • HTTPS only, through the HTTP forwarder. The built-in HTTP forwarder handles CONNECT tunnels and rejects plain-HTTP proxy requests. That covers https:// pages, which is nearly everything, but an http:// URL in that context will fail.
  • Credentials are parsed with urlparse and are not URL-decoded. Avoid @, : and / in the password rather than relying on percent-encoding.

Because each context has its own proxy, one nodriver browser can host several isolated sessions, each with its own exit IP. That is covered under sticky sessions below.

SeleniumBase with a Proxy

One argument, three entry points

SeleniumBase is the only one of the three with a first-class, documented proxy argument. SB(), Driver() and the CDP launchers all accept proxy="SERVER:PORT" or proxy="USER:PASS@SERVER:PORT". Under the hood it generates a Manifest V3 extension that answers the auth challenge. In CDP Mode it also answers Fetch.authRequired over the DevTools Protocol. You never touch either.

SB() with UC Mode and CDP Mode

Example 5 — SB(uc=True) plus CDP Mode through ProxyEmpire (Python)
import os

from seleniumbase import SB

PROXY = "{}:{}@v2.proxyempire.io:5000".format(
    os.environ["PE_USER"], os.environ["PE_PASS"]
)

with SB(uc=True, proxy=PROXY, locale="en") as sb:
    # Disconnects WebDriver and continues over CDP
    sb.activate_cdp_mode("https://api.ipify.org?format=json")
    print(sb.cdp.get_text("body"))

activate_cdp_mode() can be called with or without a URL. Recent versions also switch to CDP Mode when you call sb.goto(url) from UC Mode. Once WebDriver is disconnected, sb.reconnect() brings it back for WebDriver-only methods. SeleniumBase’s docs warn that reconnecting makes you detectable again, so do it only when needed.

Driver() for Selenium-style code

Example 6 — Driver(uc=True) with an authenticated proxy (Python)
import os

from seleniumbase import Driver

PROXY = "{}:{}@v2.proxyempire.io:5000".format(
    os.environ["PE_USER"], os.environ["PE_PASS"]
)

driver = Driver(uc=True, proxy=PROXY)
try:
    # Opens the URL with WebDriver disconnected, then reconnects after 4 s
    driver.uc_open_with_reconnect("https://api.ipify.org?format=json", 4)
    print(driver.get_text("body"))
finally:
    driver.quit()

Driver() returns a Selenium driver with SeleniumBase’s extra methods attached, which suits teams moving off raw undetected-chromedriver. On headless Linux servers the docs recommend the SB manager instead, because it brings a virtual display (Xvfb) by default.

Pure CDP Mode

Example 7 — sb_cdp.Chrome, no WebDriver at all (Python)
import os

from seleniumbase import sb_cdp

PROXY = "{}:{}@v2.proxyempire.io:5000".format(
    os.environ["PE_USER"], os.environ["PE_PASS"]
)

sb = sb_cdp.Chrome("https://api.ipify.org?format=json", proxy=PROXY)
print(sb.get_text("body"))
sb.quit()

SeleniumBase parses the proxy string by splitting on @ and :, so the same rule applies as with nodriver: keep those characters out of the password.

One Sticky Session per Browser

Keep IP, cookies and fingerprint aligned

A browser session builds up state: cookies, local storage, a consent choice, maybe a logged-in account you are authorized to use. If the exit IP changes mid-session, the site sees one browser jump between cities or networks. That is unusual for a real user and a common reason flows break. The rule is simple. One sticky session per browser, or per browser context, for the life of that session.

Figure 2 — mapping sessions to browsers
ProxyEmpire Connection Builder / proxy list (host:port:user:pass)
   |            |            |
 sid A        sid B        sid C          (each username = one sticky IP)
   |            |            |
 browser 1    browser 2    browser 3      SeleniumBase / uc: one process each
   or
 context 1    context 2    context 3      nodriver: one Chrome, many contexts

In ProxyEmpire, a sticky session is a session ID (sid) inside the proxy username. You can generate sessions in the Connection Builder, create your own 8-digit session IDs, or export many sessions at once as a proxy list in host:port:user:pass format. Rotation can be Same IP (sticky), a new IP on every request, or a custom rotation time of up to 2 hours. For browser work, use sticky, with a rotation time longer than your longest session. The sticky sessions documentation has the dashboard steps, and sticky vs rotating proxies covers when each mode fits.

With nodriver, a single browser can host one context per exported session:

Example 8 — one nodriver context per sticky session from a proxy list (Python)
import nodriver as uc


def load_proxies(path):
    """Read an exported host:port:user:pass list into http:// proxy URLs."""
    urls = []
    with open(path) as fh:
        for line in fh:
            line = line.strip()
            if not line:
                continue
            host, port, user, password = line.split(":", 3)
            urls.append(f"http://{user}:{password}@{host}:{port}")
    return urls


async def main():
    proxies = load_proxies("proxyempire_sessions.txt")[:3]
    browser = await uc.start()
    tabs = []
    for proxy_url in proxies:
        tab = await browser.create_context(
            "https://api.ipify.org?format=json",
            proxy_server=proxy_url,
        )
        tabs.append(tab)
    await tabs[-1].sleep(3)
    for i, tab in enumerate(tabs):
        ip = await tab.evaluate("document.body.innerText", return_by_value=True)
        print(f"context {i}: {ip}")
    browser.stop()


if __name__ == "__main__":
    uc.loop().run_until_complete(main())

With SeleniumBase, run one SB or Driver per session. When several threads use different authenticated proxies at once, pass multi_proxy=True so each browser gets its own auth extension. Also add sys.argv.append("-n") as the UC Mode docs describe for concurrent.futures, so SeleniumBase applies its thread locking. With pytest, pytest --uc -n 4 handles that for you.

Some sizing advice that applies to all three tools. Each real Chrome instance costs real memory and CPU, so size concurrency from measurements on your own hardware, not from guesses. When you outgrow a single machine, our write-up on designing a browser cluster covers scheduling and session lifecycles. For the network side, residential IPs suit most consumer-facing sites. Mobile 4G proxies help where carrier IPs are the norm, such as mobile-first apps.

Responsible Use

Stealth is not permission

All three projects advertise CAPTCHA and challenge handling. nodriver has a cf_verify() helper and SeleniumBase has solve_captcha(). We don’t cover those here, on purpose. A challenge is the site telling you it has doubts about your traffic. The sustainable response is to slow down, reduce concurrency, use an official API or data feed if one exists, or get permission, not to escalate.

Legitimate uses of these tools include end-to-end testing of your own sites behind bot protection, QA of localized pages and prices, ad and affiliate verification, accessibility and uptime monitoring, and collecting public, non-personal data at modest rates. In every case:

  • Read the target’s terms of service and robots.txt, and respect rate limits.
  • Prefer official APIs where they exist.
  • Don’t automate logins to accounts you don’t own or aren’t authorized to operate. Don’t collect personal data without a lawful basis.
  • Run security and bot-detection testing only against systems you are allowed to test.
  • Store proxy credentials in a secret manager or environment variables, never in code or logs.

These tools make an automated browser behave more like a real one. They don’t make an unauthorized workload acceptable.

Which One Should You Use in 2026?

Recommendation by use case
Your situationPickWhy
New project, sync Python, authenticated proxiesSeleniumBaseBuilt-in proxy="user:pass@host:port", UC and CDP Modes, active releases, MIT
Async pipeline, many isolated sessionsnodriverNative asyncio and a per-context authenticated proxy in one Chrome process
Existing undetected-chromedriver codebaseSeleniumBase Driver(uc=True)Closest API to uc, adds proxy auth, actively maintained
QA team already using pytestSeleniumBasepytest plugin, --uc, --proxy and -n on the command line
Low-level CDP controlnodriverThe whole CDP surface through nodriver.cdp, minimal abstraction
Licensing-sensitive productSeleniumBaseMIT, compared with GPL-3.0 and AGPL-3.0
Must stay on Python 3.9Plain Selenium or PlaywrightSeleniumBase needs 3.10+, nodriver 0.50.6 fails to import on 3.9, uc is unmaintained

When should you not use any of them? If your workload doesn’t need Chrome at all, an HTTP client is cheaper and faster. Our Python scraping with residential proxies guide covers requests, httpx and Scrapy. If you work in Node.js, the equivalent decisions are in the Puppeteer proxy authentication guide. And if you just need managed rendering with proxies attached, the ProxyEmpire Scraping API removes the browser fleet from your side entirely.

Frequently Asked Questions

undetected-chromedriver, nodriver and SeleniumBase, in short
Is undetected-chromedriver still maintained in 2026?

Barely. Its last PyPI release is 3.5.5 from 17 February 2024, and the last commit to the repository was in July 2025. The repository is not archived, but its author describes nodriver as the official successor. For new work, use nodriver or SeleniumBase’s UC Mode, which descends from undetected-chromedriver.

What is the difference between undetected-chromedriver and nodriver?

undetected-chromedriver patches ChromeDriver and keeps the synchronous Selenium API. nodriver removes ChromeDriver and Selenium entirely, talks to Chrome over the DevTools Protocol, and is fully asynchronous. They have the same author, and nodriver is the official successor.

What is SeleniumBase UC Mode vs CDP Mode?

UC Mode (SB(uc=True) or Driver(uc=True)) uses a modified driver that launches Chrome first and disconnects WebDriver during sensitive steps. CDP Mode (sb.activate_cdp_mode(url)) disconnects WebDriver and drives the browser over the DevTools Protocol. SeleniumBase’s documentation presents it as the successor to plain UC Mode. Pure CDP Mode (sb_cdp.Chrome()) skips WebDriver from the start.

How do I use an authenticated proxy with SeleniumBase?

Pass it as proxy="USER:PASS@HOST:PORT" to SB(), Driver() or sb_cdp.Chrome(). For ProxyEmpire that is your Connection Builder username and password with v2.proxyempire.io:5000. SeleniumBase handles the authentication challenge itself. Add multi_proxy=True when several threads use different authenticated proxies.

Does nodriver support proxies with a username and password?

Yes, per browser context. await browser.create_context(url, proxy_server="http://USER:PASS@HOST:PORT") starts a local forwarder that adds the credentials upstream. The default context created by start() is not proxied, and the HTTP forwarder handles HTTPS (CONNECT) traffic only.

Why can’t I put my proxy password in –proxy-server?

Chrome’s --proxy-server switch accepts only a scheme, host and port. Credentials have to be supplied when the proxy sends its authentication challenge. That means an extension, a DevTools auth handler, or a local forwarder that adds them for you.

Do these tools hide my IP address?

No. They change how the browser presents itself, not where its traffic comes from. undetected-chromedriver’s own README warns that datacenter or low-reputation IPs will likely still be blocked. Pair any of them with an appropriate proxy and use one sticky session per browser.

Give every browser its own sticky IP

ProxyEmpire’s gateway at v2.proxyempire.io:5000 serves rotating and sticky residential, mobile and datacenter IPs over HTTP, HTTPS and SOCKS5, with country, region, city, ZIP, ISP and ASN targeting. Plug it into SeleniumBase’s proxy= argument or nodriver’s create_context() in one line.

ProxyEmpire proxy types and prices

ProxyEmpire

Proxies for data collection at scale.

Residential, mobile, ISP and datacenter proxies for scraping, ad verification, SEO monitoring and multi-account work. Choose from 30M+ ethically sourced residential IPs and 4M+ 4G/5G mobile IPs in 170+ countries, target by country, city, ZIP, ISP or carrier, and connect over HTTP(S) or SOCKS5 with 99.9% uptime. Try residential and mobile proxies for $1.97.

🏘️ Rotating Residential Proxies
  • 30M+ Premium Residential IPs
  •  170+ Countries
    Every residential IP in our network corresponds to an actual desktop device with a precise geographical location. Our residential proxies are fast and reliable, with 99.9% uptime, and work for a wide range of use cases. You can use country, region, city, ZIP, ISP, ASN and OS fingerprint targeting for our rotating residential proxies, at no extra charge.

See our Rotating Residential Proxies

📍 Static Residential Proxies
  • 24 Countries
    Buy a dedicated static residential IP from one of the 24 countries that we offer proxies in. Keep the same IP for a month or longer, while benefiting from their fast speed and stability.

See our Static Residential Proxies

📳 Rotating Mobile Proxies
  • 4M+ Premium Mobile IPs
  •  170+ Countries
    Access millions of clean mobile IPs with precise targeting by country, region, city, ZIP, mobile carrier, ASN and OS fingerprint, at no extra charge. Get far fewer IP blocks and CAPTCHAs with our 4G and 5G proxies.

See our Mobile Proxies

📱 Dedicated Mobile Proxies
  • 4 Countries
  • 50+ Locations
    Get your own dedicated mobile proxy in one of our supported locations, with unlimited bandwidth and unlimited IP changes on demand. A great choice when you need a small number of mobile IPs and a lot of proxy bandwidth.

See our 4G & 5G Proxies

🌐 Rotating Datacenter Proxies
  • 197,000+ IPs Premium IPs
  •  62 Countries
    On a budget and need to do some simple scraping tasks? Our datacenter proxies are the perfect fit! Get started with as little as $2

See our Datacenter Proxies

♾️ Unlimited Residential Proxies
  • 1M+ Daily Residential IPs
  • 85+ Countries
    Our unlimited residential proxies bill by connection speed, not gigabytes: 100 to 1000 Mbit with unlimited bandwidth, on daily, weekly or monthly plans. Ask us for a 1-hour trial at 50 Mbit before you pick a plan.

See our Unlimited Residential Proxies

proxy locations

30M+ rotating IPs

99.9% uptime - high speed

99.9% uptime.

dedicated support team

24/7 Dedicated Support.

fair price

Fair Pricing.

🏠 Residential Proxies Rotating / Static / Unlimited
📱 Mobile Proxies Rotating and Dedicated
🖥️ Datacenter Proxies Rotating
🌍 IP Pool 30M+ residential + 4M+ mobile IPs
📶 Uptime 99.9% · Live status
💳 Payment Card · PayPal · Crypto · Bank transfer
💬 Support 24/7 live chat · [email protected]