nodriver Proxy Setup: Residential & Authenticated Proxies (2026)

Published July 2, 2026 · 9 min read

nodriver is the successor to undetected-chromedriver, written by the same author. It drops Selenium and the chromedriver binary entirely, talks to Chrome directly over the DevTools Protocol, and is async by default. The result is faster startup and a much smaller detection surface than the old Selenium + chromedriver stack. What it does not do is change where your traffic comes from. This guide covers wiring residential proxies into nodriver — including authenticated proxies, which its command-line flag can't handle on its own — plus rotation, sticky sessions, and the fingerprint/IP consistency that decides whether you actually get through.

Why people moved from undetected-chromedriver to nodriver

That makes nodriver a real upgrade on the headless and CDP detection front. If you prefer the Playwright API over raw CDP, Patchright is the sibling approach. But detection is layered — the browser is only one layer.

The part nodriver doesn't solve: your IP

A clean browser fingerprint still exits from whatever network you run it on. If that's an AWS, GCP or Hetzner range, anti-bot systems score you on ASN reputation before your perfect fingerprint is ever evaluated. This is the single most common reason a nodriver script works on a laptop and dies the moment it's deployed to a cloud VM — the code didn't change, the ASN did. Residential or mobile exits are what carry real-user trust; nodriver handles the browser layer, proxies handle the network layer, and you need both.

Basic proxy setup

An unauthenticated proxy goes straight into the browser launch flags:

import nodriver as uc

async def main():
    browser = await uc.start(
        browser_args=["--proxy-server=socks5://us.jibaoproxy.com:913"]
    )
    page = await browser.get("https://www.jibaoproxy.com/tools/fingerprint.html")
    print(await page.get_content())

uc.loop().run_until_complete(main())

That's enough when the proxy authenticates by IP allowlist. Most residential gateways authenticate by username/password instead — and Chrome's --proxy-server flag has no place to put credentials. That's the part that trips people up.

Authenticated proxies (the flag can't do this alone)

You can't put user:pass@host in --proxy-server — Chrome ignores it and pops a login dialog. The clean fix is to answer the proxy's auth challenge over CDP with the Fetch domain, the same technique selenium-wire and puppeteer-extra use under the hood:

import nodriver as uc

HOST, PORT = "us.jibaoproxy.com", 913
USER, PASS = "USERNAME", "PASSWORD"

async def main():
    browser = await uc.start(
        browser_args=[f"--proxy-server=http://{HOST}:{PORT}"]
    )
    tab = browser.main_tab

    # Enable request interception and auto-answer the proxy auth challenge
    await tab.send(uc.cdp.fetch.enable(handle_auth_requests=True))

    async def auth(event):
        await tab.send(uc.cdp.fetch.continue_with_auth(
            request_id=event.request_id,
            auth_challenge_response=uc.cdp.fetch.AuthChallengeResponse(
                response="ProvideCredentials", username=USER, password=PASS,
            ),
        ))

    async def cont(event):
        await tab.send(uc.cdp.fetch.continue_request(request_id=event.request_id))

    tab.add_handler(uc.cdp.fetch.AuthRequired, auth)
    tab.add_handler(uc.cdp.fetch.RequestPaused, cont)

    page = await browser.get("https://www.jibaoproxy.com/tools/fingerprint.html")
    print(await page.get_content())

uc.loop().run_until_complete(main())

Now the credentials are handled programmatically, no dialog, and the browser exits through your authenticated residential IP.

Rotating exits: one proxy per browser

For rotation, the cleanest model with nodriver is one exit per browser instance rather than swapping proxies mid-session (Chrome can't change --proxy-server after launch). Cycle a pool and spin a fresh browser per task:

import itertools, asyncio
import nodriver as uc

POOL = itertools.cycle([
    "http://us.jibaoproxy.com:913",
    "http://eu.jibaoproxy.com:913",
])

async def scrape(url):
    proxy = next(POOL)
    browser = await uc.start(browser_args=[f"--proxy-server={proxy}"])
    try:
        page = await browser.get(url)
        await page.sleep(2)
        return await page.get_content()
    finally:
        browser.stop()

async def main():
    tasks = [scrape(u) for u in urls]
    return await asyncio.gather(*tasks)

Keep concurrency bounded with a semaphore — launching dozens of real Chrome instances at once will exhaust memory long before your proxy pool complains.

Sticky sessions for logins and carts

Per-task rotation is right for stateless scraping, but anything stateful — a login, a cart, a multi-step flow — breaks if your IP changes mid-session. Keep one browser (and therefore one sticky exit) for the entire authenticated flow, and only rotate at the account or task boundary. Rotation gets you in the door; a sticky session is what keeps you logged in once you're through.

Fingerprint and IP have to agree

The failure mode that survives even a good proxy is a mismatch: a US residential IP paired with a timezone, locale, or TLS/JA3 fingerprint that says something else. nodriver gives you a believable browser; make sure the exit's geography lines up with the browser's locale and timezone, and don't run an obviously datacenter ASN behind a residential-looking browser. For AI agents and automation that run unattended, this consistency is what separates a session that lasts hours from one that's challenged on the first request.

Verify before you scale

Before pointing a nodriver fleet at a target, confirm what your exit actually looks like from the outside. Load www.jibaoproxy.com/tools/fingerprint.html through the browser to read back the JA3 fingerprint and exit IP, and check that the ASN reads as residential/mobile — not the cloud provider you deployed on. If the fingerprint and IP both look like a real user, you've closed the two layers nodriver can't close by itself.

Summary

JIBAO residential proxies ship with clean ASNs and browser-matched exits, which is exactly what nodriver needs on the network side. Every new account gets 500MB of free traffic to test a real exit against your own target.

Universal for All IP Products · Massive Nodes Always Available

Join now & enjoy up to 100% deposit bonus.

New users get 500MB free traffic instantly, plus an extra first-deposit reward — limited-time offer.