Selenium Proxy Setup: Auth, Rotation, Verification

How to route Selenium through a proxy in Chrome and Firefox, handle username auth, avoid DNS leaks, and verify the exit IP before you run volume.

VoidMob Team
7 min read

You point Selenium at a proxy through browser options, not through WebDriver itself: a Chrome argument (--proxy-server), a Firefox profile preference, or Selenium's Proxy capability object. The hard part is not the proxy line, it is authentication (Chrome ignores user:pass@host in --proxy-server) and rotation (per-request rotation breaks a browser session mid page load). Below is the setup that works, plus the two failure modes that produce most "the proxy is set but the site still sees my real IP" reports.

Chrome: the proxy argument

from selenium import webdriver

opts = webdriver.ChromeOptions()
opts.add_argument("--proxy-server=http://proxy.voidmob.com:10092")
opts.add_argument("--proxy-bypass-list=<-loopback>")  # only if you must proxy localhost
driver = webdriver.Chrome(options=opts)
driver.get("https://example.com")

Notes that matter in practice:

  • The scheme is part of the value: http://, https:// or socks5://. A bare host:port defaults to HTTP and silently misbehaves with SOCKS endpoints.
  • Chrome applies one proxy per browser process. You cannot give two tabs two different exit IPs. One browser process equals one identity.
  • Credentials in the argument are ignored. Chrome will show the native auth dialog, which WebDriver cannot type into.

Firefox: profile preferences

Firefox reads proxy settings from preferences, so set them on the options object:

from selenium import webdriver

opts = webdriver.FirefoxOptions()
opts.set_preference("network.proxy.type", 1)
opts.set_preference("network.proxy.http", "proxy.voidmob.com")
opts.set_preference("network.proxy.http_port", 10092)
opts.set_preference("network.proxy.ssl", "proxy.voidmob.com")
opts.set_preference("network.proxy.ssl_port", 10092)
opts.set_preference("network.proxy.socks_remote_dns", True)
driver = webdriver.Firefox(options=opts)

Forgetting network.proxy.ssl is a classic half-configured setup: plain HTTP goes through the proxy, HTTPS goes direct, and every real target you care about sees your server IP.

Authentication: pick one of three methods

MethodHow it worksTrade-off
IP whitelistingAuthorize your server's IP with the provider, then use host:port with no credentialsCleanest with Selenium; needs a stable outbound IP and does not work from rotating CI runners
Chrome extensionPack a tiny extension that answers chrome.webRequest.onAuthRequired with your credentials, load it via add_extensionWorks headless in modern Chrome, but you build and ship an extension per credential set
Local forwarderRun an upstream-authenticating proxy on localhost and point Chrome at 127.0.0.1One extra process to supervise; easiest way to swap credentials per worker without touching browser flags

The local forwarder is the most maintainable option when you run many workers, because the credential (including any session parameters) lives in the forwarder config, not in the browser command line. It also gives you one place to log which exit IP served which run.

Rotation: sticky, not per-request

This is the failure mode that costs the most debugging time. A single page load fires dozens of requests. On a per-request rotating gateway each of those requests can leave from a different device, so the HTML, the XHR calls and the login POST arrive from different IPs. Sites treat that as session hijacking, and you get logouts, captchas or empty responses that look like blocking but are self-inflicted.

Rule: any Selenium session that logs in, adds to a cart, or walks a multi-step flow needs a sticky exit for the life of the browser process. Per-request rotation belongs to plain HTTP clients, not browsers.

On VoidMob's shared pool you request stickiness in the proxy username by chaining underscore parameters, for example <username>_c_US_s_run1_ttl_30m: country US, session ID run1, held for 30 minutes. Reuse the same session ID for the same browser process, generate a new one when you launch a new profile, and drop the _s_ parameter only for non-browser fetching. If you prefer configuration over per-request strings, a named proxy list can be set to sticky once and every credential in it behaves that way. Dedicated devices are sticky by definition: rotation happens when you call for it. The sticky session explainer covers how long to hold a window per workload.

For geo control beyond the country level, and for the question of whether carrier or ASN targeting actually changes what a target returns, see ASN vs geo targeting.

DNS: the leak Selenium users miss

With an HTTP proxy, Chrome sends the hostname to the proxy and the proxy resolves it. With SOCKS5, Chrome resolves locally by default, so your server's resolver sees every hostname you visit. Chromium's own guidance is to force remote resolution when using a SOCKS proxy, via --host-resolver-rules:

--proxy-server="socks5://proxy.voidmob.com:<your-socks5-port>"
--host-resolver-rules="MAP * ~NOTFOUND , EXCLUDE proxy.voidmob.com"

In Firefox the equivalent is network.proxy.socks_remote_dns = true. A resolver mismatch will not always block you, but it does put your datacenter's DNS geography next to a mobile exit IP, which is exactly the kind of inconsistency detection systems score.

Verify before you run volume

Never trust the flag. Load an IP endpoint as the first action of every worker, log the address, and assert it is not your server:

driver.get("https://api.ipify.org?format=json")
print(driver.find_element("tag name", "pre").text)

Then check the same address mid-run. If it changed, your sticky pin dropped and the gateway re-assigned you.

Check what your exit IP looks like right now

For a credential you have not used yet, test it outside the browser first with the proxy validator, and screen the exit for reputation with the IP blacklist checker before you build a session on it.

Headless changes your fingerprint, not your IP

A correctly routed proxy plus a headless browser still leaves headless signals in the navigator object, WebGL strings and font list. If a target blocks you with the proxy working and the IP verified, the next thing to check is the browser fingerprint, not the network.

When Selenium is the wrong tool

Selenium drives browsers through the WebDriver protocol, which gives you no request interception without extra layers. If your job needs per-request headers, response mocking, or credential injection at the network layer, Chrome DevTools Protocol clients handle it natively: see Playwright proxy setup or Puppeteer proxy setup for the same tasks with built-in proxy options and auth fields. Keep Selenium when you need cross-browser coverage (Firefox and Safari in the same suite) or when an existing test suite already lives there.

1Why does my proxy work in curl but not in Selenium?

Two usual causes. Chrome ignores credentials embedded in --proxy-server, so an authenticated proxy that works in curl fails silently in the browser. Or you set only the HTTP proxy in Firefox and left network.proxy.ssl unset, so HTTPS bypasses the proxy entirely.

2Can I use a different proxy per tab in Selenium?

No. The proxy is set per browser process. Run one driver instance per identity, each with its own user data directory and its own sticky session ID, and never share a session ID between two logins.

3Does Selenium's Proxy capability object still work?

Yes for Firefox and for the SOCKS and PAC cases; it maps to the same underlying settings. It has no field for proxy credentials, so authentication still needs whitelisting, an extension, or a local forwarder.

4How do I rotate IPs between Selenium runs?

Close the driver, change the session ID in the proxy username (or trigger a rotation on a dedicated device), then launch a fresh driver with a fresh profile. Rotating the IP while a browser session is open is what triggers re-verification prompts.

5Do I need mobile IPs for Selenium, or will datacenter proxies do?

Datacenter IPs are fine for public pages with no bot defense. Anything that scores IP reputation, or that you log into, behaves better on carrier-NAT mobile IPs because thousands of real subscribers share the same address and a block is expensive for the platform.

Running Selenium inside an AI agent rather than a fixed script? The same pools are exposed through VoidMob's MCP server, so an agent can request an exit or rotate between tasks as a tool call instead of a hardcoded proxy string.

Run Selenium on real 4G/5G exits

Pay-per-GB shared pools with sticky session parameters, or dedicated devices you rotate on demand.