Selenium WebDriver Datacenter Proxy Setup: Python, Node.js & Java
Datacenter proxies hit 99.88% success at 0.38s median response. Full Selenium WebDriver proxy setup in Python, Node.js, and Java with rotation and auth.

Datacenter proxies are the most practical choice for Selenium automation at scale. They hit a 99.88% median infrastructure success rate with a 0.38-second median response time and cost roughly $0.70 per GB, seven times cheaper than residential alternatives (ProxyWay Proxy Market Research 2024).
Selenium WebDriver 4 has a built-in proxy capability that works across every browser it supports. The API looks slightly different in each language, but the underlying Proxy object is the same. This tutorial walks through the complete setup in Python, Node.js, and Java: basic configuration, authentication, proxy rotation, and verification. Every code block is ready to copy into a real project.
Key Takeaways
- Selenium 4 uses
ChromeOptions/FirefoxOptions, the oldDesiredCapabilitiesproxy pattern is deprecated- Datacenter proxies average 0.38s response time and $0.70/GB, making them 7ร cheaper than residential IPs (ProxyWay 2024)
- Authenticated proxies in Chrome require a browser extension; Firefox handles credentials natively via profile or proxy URL
- Proxy rotation means a
driver.quit()+ reinitialise cycle, you can't hot-swap an active session's proxy- Always verify the active IP with
httpbin.org/ipbefore running production logic
Why Are Datacenter Proxies the Right Choice for Selenium Automation?
Browser-based automation is heavier than raw HTTP scraping. Every Selenium session loads a full Chrome or Firefox instance, renders JavaScript, and downloads assets. The proxy tier amplifies or absorbs that overhead.
Datacenter proxies perform well here because they're hosted on dedicated servers in colocation facilities with high-bandwidth uplinks. They're always online, they respond quickly, and they're cheap enough to run at volume. The ProxyWay 2024 benchmark puts the rotating datacenter median at a 99.88% success rate and 0.38 seconds median response time, the fastest participant (Bright Data) completed requests in 0.26 seconds. At $0.70/GB average, you get 10ร the throughput budget compared to residential proxies for the same spend.
The tradeoff is detectability. Datacenter IPs are registered to hosting providers, not ISPs, and anti-bot systems know this. They're appropriate for targets without aggressive bot detection: internal testing, QA automation, price monitoring on cooperative sites, and geo-testing. For targets that specifically block datacenter ASNs, a residential or ISP proxy is the right call.
Proxy cost vs. response time (rotating proxies, ProxyWay 2024):
โโโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโ
โ Type โ Avg $/GB โ Median RTT โ
โโโโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโผโโโโโโโโโโโโโโโค
โ Rotating datacenter โ $0.70 โ 0.38 s โ
โ Residential โ $4.90 โ 0.41 s โ
โ Mobile โ $9.80 โ 0.88 s โ
โโโโโโโโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโดโโโโโโโโโโโโโโโ
Source: ProxyWay Proxy Market Research 2024
[CITATION CAPSULE] "With a median success rate of 99.88%, rotating datacenter proxies very rarely fail. The median response time was 0.38 seconds. Rotating datacenter proxies cost $0.70 on average at 100 GB of data, seven times cheaper than residential and over 14 times cheaper than mobile proxy networks.", ProxyWay Proxy Market Research 2024
How Do You Configure a Datacenter Proxy in Selenium with Python?
Selenium's Python bindings use the selenium.webdriver.common.proxy.Proxy class to define proxy settings, then pass the result to ChromeOptions or FirefoxOptions.
Chrome:
import os
from selenium import webdriver
from selenium.webdriver.common.proxy import Proxy, ProxyType
PROXY_HOST = "dc.example.com"
PROXY_PORT = "7000"
proxy = Proxy()
proxy.proxy_type = ProxyType.MANUAL
proxy.http_proxy = f"{PROXY_HOST}:{PROXY_PORT}"
proxy.ssl_proxy = f"{PROXY_HOST}:{PROXY_PORT}"
options = webdriver.ChromeOptions()
options.Proxy = proxy
# Headless for CI/CD environments
options.add_argument("--headless=new")
options.add_argument("--no-sandbox")
options.add_argument("--disable-dev-shm-usage")
driver = webdriver.Chrome(options=options)
driver.get("https://httpbin.org/ip")
print(driver.find_element("tag name", "body").text)
driver.quit()
Firefox accepts the same Proxy object via FirefoxOptions:
from selenium import webdriver
from selenium.webdriver.common.proxy import Proxy, ProxyType
proxy = Proxy()
proxy.proxy_type = ProxyType.MANUAL
proxy.http_proxy = "dc.example.com:7000"
proxy.ssl_proxy = "dc.example.com:7000"
proxy.ftp_proxy = "dc.example.com:7000"
options = webdriver.FirefoxOptions()
options.proxy = proxy
driver = webdriver.Firefox(options=options)
driver.get("https://httpbin.org/ip")
print(driver.find_element("tag name", "pre").text)
driver.quit()
Two things to keep in mind with the Python API:
- Set both
http_proxyandssl_proxy. Ifssl_proxyis missing, HTTPS sites won't route through the proxy, a common silent failure. You'll see your real IP in the response rather than an error, which makes it hard to notice. --headless=new(Chrome 112+) is the modern headless flag. The old--headlessflag triggers the legacy headless mode, which behaves differently with proxy settings on some versions.
Scraping at scale? Skip the blocks.
Fast, unblockable datacentre proxies with unlimited bandwidth.
How Do You Set a Proxy in Selenium with Node.js?
The selenium-webdriver npm package uses Capabilities and a proxy configuration object. Selenium 4 structures this differently from the old DesiredCapabilities approach.
Chrome:
const { Builder, Capabilities } = require('selenium-webdriver');
const chrome = require('selenium-webdriver/chrome');
const PROXY_HOST = 'dc.example.com';
const PROXY_PORT = '7000';
const proxyStr = `${PROXY_HOST}:${PROXY_PORT}`;
const options = new chrome.Options();
options.setProxy({
proxyType: 'manual',
httpProxy: proxyStr,
sslProxy: proxyStr,
});
// Headless
options.addArguments('--headless=new', '--no-sandbox', '--disable-dev-shm-usage');
async function main() {
const driver = await new Builder()
.forBrowser('chrome')
.setChromeOptions(options)
.build();
try {
await driver.get('https://httpbin.org/ip');
const body = await driver.findElement({ tagName: 'body' });
console.log(await body.getText());
} finally {
await driver.quit();
}
}
main();
Firefox via the firefox module:
const { Builder } = require('selenium-webdriver');
const firefox = require('selenium-webdriver/firefox');
const options = new firefox.Options();
options.setPreference('network.proxy.type', 1); // 1 = Manual
options.setPreference('network.proxy.http', 'dc.example.com');
options.setPreference('network.proxy.http_port', 7000);
options.setPreference('network.proxy.ssl', 'dc.example.com');
options.setPreference('network.proxy.ssl_port', 7000);
options.setPreference('network.proxy.no_proxies_on', '');
async function main() {
const driver = await new Builder()
.forBrowser('firefox')
.setFirefoxOptions(options)
.build();
try {
await driver.get('https://httpbin.org/ip');
const pre = await driver.findElement({ tagName: 'pre' });
console.log(await pre.getText());
} finally {
await driver.quit();
}
}
main();
The Firefox approach uses direct setPreference calls because Firefox exposes proxy config through user preferences. The network.proxy.type value of 1 is the constant for manual proxy mode, 0 is no proxy, 2 is PAC URL, 4 is auto-detect.
[UNIQUE INSIGHT] Chrome's
setProxyin Node.js silently ignores the proxy on HTTPS sites if onlyhttpProxyis set. Always set bothhttpProxyandsslProxyto the same endpoint, the names are misleading becausesslProxycontrols HTTPS tunnelling, not just SSL-native traffic.
How Do You Configure a Selenium Proxy in Java?
Java uses org.openqa.selenium.Proxy and the setCapability method on ChromeOptions. Add the Maven dependency for Selenium 4 before you start:
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>4.20.0</version>
</dependency>
Chrome:
import org.openqa.selenium.Proxy;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
public class ProxyExample {
public static void main(String[] args) {
String proxyAddress = "dc.example.com:7000";
Proxy proxy = new Proxy();
proxy.setHttpProxy(proxyAddress);
proxy.setSslProxy(proxyAddress);
ChromeOptions options = new ChromeOptions();
options.setCapability("proxy", proxy);
options.addArguments("--headless=new", "--no-sandbox");
WebDriver driver = new ChromeDriver(options);
try {
driver.get("https://httpbin.org/ip");
System.out.println(driver.findElement(
org.openqa.selenium.By.tagName("body")).getText());
} finally {
driver.quit();
}
}
}
Firefox:
import org.openqa.selenium.Proxy;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.firefox.FirefoxOptions;
public class FirefoxProxyExample {
public static void main(String[] args) {
String proxyAddress = "dc.example.com:7000";
Proxy proxy = new Proxy();
proxy.setHttpProxy(proxyAddress);
proxy.setSslProxy(proxyAddress);
proxy.setFtpProxy(proxyAddress);
FirefoxOptions options = new FirefoxOptions();
options.setCapability("proxy", proxy);
WebDriver driver = new FirefoxDriver(options);
try {
driver.get("https://httpbin.org/ip");
System.out.println(driver.findElement(
org.openqa.selenium.By.tagName("pre")).getText());
} finally {
driver.quit();
}
}
}
The setCapability("proxy", proxy) call is the Selenium 4 standard. Some older tutorials use setProxy(proxy) directly on ChromeOptions, this was valid in Selenium 3 but is deprecated in Selenium 4 and may not behave consistently across browser versions.
[CITATION CAPSULE] "A proxy server for automation scripts with Selenium could be helpful for capturing network traffic, mocking backend calls, and accessing required websites under complex network topologies or strict corporate restrictions. Selenium WebDriver provides a way to proxy settings via the Proxy capability.", Selenium WebDriver Official Documentation
How Do You Handle Authenticated Proxies in Selenium?
Most commercial datacenter proxy services require username/password authentication. The handling differs significantly between Chrome and Firefox.
Firefox accepts credentials directly in the proxy URL via profile preferences:
# Python, Firefox with authenticated proxy
from selenium import webdriver
import os
user = os.environ["PROXY_USER"]
pwd = os.environ["PROXY_PASS"]
host = "dc.example.com"
port = 7000
profile = webdriver.FirefoxProfile()
profile.set_preference("network.proxy.type", 1)
profile.set_preference("network.proxy.http", host)
profile.set_preference("network.proxy.http_port", port)
profile.set_preference("network.proxy.ssl", host)
profile.set_preference("network.proxy.ssl_port", port)
# Firefox prompts for credentials, pre-fill via network.proxy credentials
profile.set_preference("signon.autologin.proxy", True)
options = webdriver.FirefoxOptions()
options.profile = profile
driver = webdriver.Firefox(options=options)
Chrome does not support proxy authentication natively through ChromeOptions. The standard workaround is a tiny browser extension that intercepts the authentication challenge:
import os
import zipfile
import string
import tempfile
from selenium import webdriver
def make_proxy_auth_extension(host, port, user, pwd):
manifest = """{
"version": "1.0.0",
"manifest_version": 2,
"name": "Proxy Auth",
"permissions": ["proxy", "tabs", "unlimitedStorage",
"storage", "<all_urls>", "webRequest",
"webRequestBlocking"],
"background": {"scripts": ["background.js"]},
"minimum_chrome_version": "22.0.0"
}"""
background = string.Template("""
var config = {
mode: "fixed_servers",
rules: {
singleProxy: {scheme:"http", host:"$host", port:parseInt($port)},
bypassList: ["localhost"]
}
};
chrome.proxy.settings.set({value:config, scope:"regular"}, function(){});
function callbackFn(details) {
return {authCredentials: {username:"$user", password:"$pwd"}};
}
chrome.webRequest.onAuthRequired.addListener(
callbackFn,
{urls:["<all_urls>"]},
["blocking"]
);
""").substitute(host=host, port=port, user=user, pwd=pwd)
tmp = tempfile.mktemp(suffix=".zip")
with zipfile.ZipFile(tmp, "w") as zp:
zp.writestr("manifest.json", manifest)
zp.writestr("background.js", background)
return tmp
ext = make_proxy_auth_extension(
host=os.environ["PROXY_HOST"],
port=os.environ["PROXY_PORT"],
user=os.environ["PROXY_USER"],
pwd=os.environ["PROXY_PASS"],
)
options = webdriver.ChromeOptions()
options.add_extension(ext)
driver = webdriver.Chrome(options=options)
driver.get("https://httpbin.org/ip")
print(driver.find_element("tag name", "body").text)
driver.quit()
The extension approach works reliably across Chrome versions. One practical note: Chrome in headless mode (prior to Chrome 112) doesn't load extensions. If you're on a headless CI pipeline, use Firefox for authenticated proxy sessions, it handles credentials natively.
[UNIQUE INSIGHT] The extension ZIP is temporary but its path is referenced by the
ChromeOptionsobject, so cleanup must happen afterdriver.quit(), not before. In long-running rotation loops, accumulating temp files from uncleaned extension ZIPs is a common source of disk exhaustion that doesn't surface until hours into a run.
How Do You Rotate Proxies Across Selenium Sessions?
Selenium WebDriver doesn't support hot-swapping a proxy in an active session. The proxy is set at session start through ChromeOptions / FirefoxOptions and persists for the lifetime of that driver instance.
Rotation means creating a new driver with a new proxy for each logical scraping task:
import os
import random
from selenium import webdriver
from selenium.webdriver.common.proxy import Proxy, ProxyType
PROXY_LIST = [
"dc1.example.com:7000",
"dc2.example.com:7000",
"dc3.example.com:7000",
]
def create_driver(proxy_address: str) -> webdriver.Chrome:
proxy = Proxy()
proxy.proxy_type = ProxyType.MANUAL
proxy.http_proxy = proxy_address
proxy.ssl_proxy = proxy_address
options = webdriver.ChromeOptions()
options.Proxy = proxy
options.add_argument("--headless=new")
options.add_argument("--no-sandbox")
options.add_argument("--disable-dev-shm-usage")
return webdriver.Chrome(options=options)
def scrape_url(url: str, proxy_address: str) -> str:
driver = create_driver(proxy_address)
try:
driver.get(url)
return driver.find_element("tag name", "body").text
finally:
driver.quit()
urls = [f"https://example.com/product/{i}" for i in range(30)]
for i, url in enumerate(urls):
proxy = PROXY_LIST[i % len(PROXY_LIST)]
result = scrape_url(url, proxy)
print(f"{proxy} โ {url}: {len(result)} bytes")
For backconnect rotating proxies, the endpoint address never changes, the provider assigns a fresh IP per request internally. In this case you only need one PROXY_LIST entry and can skip the rotation loop entirely:
BACKCONNECT_PROXY = "rotate.dc.example.com:9000"
for url in urls:
result = scrape_url(url, BACKCONNECT_PROXY)
Starting and quitting browser instances for every URL is expensive. In production, batch tasks by session: keep a driver alive for N pages, then rotate:
BATCH_SIZE = 10
for batch_start in range(0, len(urls), BATCH_SIZE):
proxy = random.choice(PROXY_LIST)
driver = create_driver(proxy)
try:
for url in urls[batch_start:batch_start + BATCH_SIZE]:
driver.get(url)
# process page...
finally:
driver.quit()
How Do You Verify Your Proxy Is Active in Selenium?
Misconfigured proxies fail silently. requests.get() raises an error on connection failure, but driver.get() often loads an error page without throwing an exception, your code continues, logging your real IP.
The simplest verification is hitting httpbin.org/ip and asserting the returned IP is not your machine's public IP:
import json
import requests
from selenium import webdriver
from selenium.webdriver.common.proxy import Proxy, ProxyType
def get_my_public_ip() -> str:
return requests.get("https://httpbin.org/ip", timeout=10).json()["origin"]
def verify_proxy(driver: webdriver.Chrome) -> dict:
driver.get("https://httpbin.org/ip")
body = driver.find_element("tag name", "body").text
data = json.loads(body)
return data
real_ip = get_my_public_ip()
proxy = Proxy()
proxy.proxy_type = ProxyType.MANUAL
proxy.http_proxy = "dc.example.com:7000"
proxy.ssl_proxy = "dc.example.com:7000"
options = webdriver.ChromeOptions()
options.Proxy = proxy
options.add_argument("--headless=new")
driver = webdriver.Chrome(options=options)
result = verify_proxy(driver)
proxy_ip = result.get("origin", "unknown")
if proxy_ip == real_ip:
print(f"WARNING: proxy not active, browser is using real IP {real_ip}")
else:
print(f"Proxy confirmed: {proxy_ip} (real IP hidden)")
driver.quit()
Run this check at the start of every session in production code. The overhead is a single HTTP request, negligible against the cost of running hundreds of tasks without proxy coverage.
For batch jobs, log the proxy IP on the first request of each session and compare it across the run. A proxy rotation that silently fails leaves you cycling through the same IP, detectable by sorting the IP log and looking for unexpected repetition.
Proxy verification checklist:
โ
proxy_ip != real_ip
โ
proxy_ip matches expected CIDR or provider ASN
โ
HTTPS test URL returns 200 (not an error page)
โ
ssl_proxy and http_proxy both set (not just one)
Wrapping Up
Selenium WebDriver's proxy setup is consistent across Python, Node.js, and Java, the same Proxy object model, the same http_proxy + ssl_proxy rule, the same session-scoped limitation. The language differences are syntactic rather than conceptual.
Datacenter proxies fit most Selenium automation well: at 99.88% success rate and $0.70/GB, they're fast and cheap enough to run at the kind of volume browser-based automation demands. The two gotchas worth remembering, always set both http_proxy and ssl_proxy, and verify the active IP before running production logic, save hours of debugging silent misconfiguration later.
Frequently asked questions
Yes. Set proxy.socks_proxy (Python) or proxy.setSocksProxy() (Java) to the SOCKS5 endpoint, and set proxy.socks_version = 5. Chrome and Firefox both support SOCKS5. Note that SOCKS5 username/password authentication requires the same Chrome extension workaround as HTTP proxy authentication, the native Proxy object only supports unauthenticated SOCKS5 in Chrome. Firefox handles it natively through profile preferences.
No. The proxy is session-scoped and applies to every tab and window in that driver instance. To use different proxies simultaneously, run separate WebDriver instances, each gets its own proxy configured via ChromeOptions or FirefoxOptions. This also means proxy rotation requires a driver.quit() + reinitialise cycle, not a live swap.
The most common cause is setting only http_proxy without ssl_proxy. Chrome tunnels HTTPS through the proxy using the HTTP CONNECT method, and it reads that from the sslProxy field, not httpProxy. Set both to the same datacenter endpoint. If you're using --proxy-server as a Chrome argument instead of the Proxy object, use --proxy-server=http://host:port, this applies to both HTTP and HTTPS automatically.
A static datacenter proxy gives you a fixed IP for the lifetime of your subscription. Your Selenium sessions always exit from the same address, useful for account-bound automation or whitelist-based access. A rotating datacenter proxy assigns a fresh IP per connection or per session. From Selenium's perspective the configuration is identical: the same endpoint address gets different IPs server-side. Rotating fits high-volume scraping where IP burnout is a concern; static fits tasks where continuity of identity matters.
Get 20% off your first month
Premium datacentre proxies with unlimited bandwidth. Use the code at checkout.
Save up to 15% more on quarterly, half-yearly and yearly plans
Written by
SparkProxy
Proxy infrastructure and web-data experts at SparkProxy.
Related articles

How to Scrape Mercado Libre Product Data (API First)
Scrape Mercado Libre product data properly: start with the api.mercadolibre.com REST API, then fill the gaps by site ID, currency, shipping and language.

How to Scrape Kayak Flight Prices Without Losing Fares
Scrape Kayak flight prices correctly: handle progressive metasearch results, poll for search completion, and pull a full fare set with the SparkProxy API.

How to Scrape IndiaMART Supplier Data: B2B Market Intel
Scrape IndiaMART supplier data for B2B market research: parse lakh and crore prices, MOQ and units, map supplier geography, and stay inside DPDP Act limits.
