How to Integrate Proxies with Selenium
Set up a Selenium proxy for Chrome and Firefox. Covers ChromeOptions, Selenium Wire for auth, proxy rotation, and common errors with code examples.
Table of Contents
- Why Use a Proxy with Selenium? {#why-proxy-selenium}
- Selenium Proxy via ChromeOptions (IP Whitelisting) {#chromeoptions-proxy}
- Selenium Proxy via the Proxy Capability Class {#proxy-capability-class}
- Firefox Proxy with FirefoxOptions {#firefox-proxy}
- Proxy Authentication in Chrome: The Core Problem {#chrome-proxy-auth}
- Selenium Wire for Authenticated Proxy (Recommended) {#selenium-wire}
- Proxy Rotation in Selenium {#proxy-rotation}
- Selenium Grid and Remote WebDriver with Proxy {#remote-webdriver}
- Test Your Proxy in Selenium {#test-proxy}
- Common Selenium Proxy Errors and Fixes {#common-errors}
- About the Author
-
Why Use a Proxy with Selenium? {#why-proxy-selenium}
Setting up a Selenium proxy has one critical trap: Chrome silently ignores credentials in the
--proxy-serverflag. Passing--proxy-server=user:pass@host:portdoes nothing. Proxy authentication in Chrome requires either IP whitelisting, Selenium Wire, or a packaged browser extension — and most guides skip that entirely. This article covers every method: ChromeOptions, FirefoxOptions, theProxycapability class, Selenium Wire for authenticated proxies, rotation patterns, and a complete error reference for Selenium datacenter proxy setups.A browser automation proxy routes all browser traffic — including JavaScript-initiated requests, images, fonts, and API calls through a datacenter IP. Unlike HTTP library proxies (requests, httpx), Selenium proxies affect the full browser network stack, making them essential for:
| Use Case | Why Proxy Is Required |
|---|---|
| Web scraping geo-restricted content | Present a specific country's datacenter IP |
| Ad verification | Verify ad rendering from the target geography |
| Price monitoring | Prevent single-IP rate limiting across hundreds of pages |
| Account management | Assign a stable IP per account to avoid association |
| QA on production sites | Test from specific regions without VPN |
When you set a proxy on a Selenium driver, every request the browser makes, page loads, XHR/fetch calls, and resource downloads go through the proxy. This is different from configuring a proxy in Python
requests, which only affects your script's HTTP calls.
-
Selenium Proxy via ChromeOptions (IP Whitelisting) {#chromeoptions-proxy}
The simplest Chrome proxy setup uses the
--proxy-serverargument. This works for datacenter proxies that use IP whitelisting; your machine's IP is authorized in the proxy dashboard, so no username or password is required.```python
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
def create_driver_with_proxy(proxy_host: str, proxy_port: int) -> webdriver.Chrome:
options = Options()
options.add_argument(f"--proxy-server={proxy_host}:{proxy_port}")
options.add_argument(f"--proxy-bypass-list=localhost,127.0.0.1")
options.add_argument("--no-sandbox")
options.add_argument("--disable-dev-shm-usage")
return webdriver.Chrome(options=options)
driver = create_driver_with_proxy("your-proxy.sparkproxy.com", 10000)
driver.get("https://httpbin.org/ip")
print(driver.find_element("tag name", "pre").text)
driver.quit()
```
The
--proxy-bypass-listargument accepts a comma-separated list of hostnames and IP ranges to bypass. Useto skip the proxy for all local addresses:```python
options.add_argument("--proxy-bypass-list=
,*.internal.company.com") ```
-
SOCKS5 proxy with ChromeOptions
```python
options = Options()
options.add_argument("--proxy-server=socks5://your-proxy.sparkproxy.com:1080")
driver = webdriver.Chrome(options=options)
```
Note: Chrome's
--proxy-serverflag acceptshttp://,https://, andsocks5://schemes. For most datacenter proxy setups, omit the scheme entirely, Chrome defaults to HTTP CONNECT tunneling when no scheme is specified.
-
-
Selenium Proxy via the Proxy Capability Class {#proxy-capability-class}
Selenium's official
Proxyclass provides a structured, browser-agnostic way to configure proxies, documented in the Selenium WebDriver Browser Options spec. It supports HTTP, HTTPS, SOCKS, FTP, and auto-configuration proxies.```python
from selenium import webdriver
from selenium.webdriver.common.proxy import Proxy, ProxyType
from selenium.webdriver.chrome.options import Options
Build the proxy capability object
proxy = Proxy()
proxy.proxy_type = ProxyType.MANUAL
proxy.http_proxy = "your-proxy.sparkproxy.com:10000"
proxy.ssl_proxy = "your-proxy.sparkproxy.com:10000" # HTTPS
proxy.no_proxy = "localhost,127.0.0.1"
Attach to ChromeOptions
options = Options()
options.proxy = proxy
driver = webdriver.Chrome(options=options)
driver.get("https://httpbin.org/ip")
driver.quit()
```
The
ProxyTypeenum values relevant for datacenter proxies:| ProxyType | Description |
|---|---|
|
MANUAL| Explicit host:port for each protocol ||
AUTODETECT| WPAD auto-detection ||
PAC| Proxy Auto-Config file URL ||
DIRECT| No proxy (bypass all) ||
SYSTEM| Use OS proxy settings |For PAC file-based proxy configuration:
```python
proxy = Proxy()
proxy.proxy_type = ProxyType.PAC
proxy.proxy_autoconfig_url = "http://proxy.company.com/proxy.pac"
options = Options()
options.proxy = proxy
```
-
Firefox Proxy with FirefoxOptions {#firefox-proxy}
Firefox proxy configuration uses preference keys rather than command-line arguments. These map directly to Firefox's
about:configproxy settings.```python
from selenium import webdriver
from selenium.webdriver.firefox.options import Options as FirefoxOptions
def create_firefox_with_proxy(host: str, port: int) -> webdriver.Firefox:
options = FirefoxOptions()
0 = no proxy, 1 = manual, 2 = PAC, 4 = auto-detect, 5 = system
options.set_preference("network.proxy.type", 1)
HTTP proxy
options.set_preference("network.proxy.http", host)
options.set_preference("network.proxy.http_port", port)
HTTPS proxy (uses same host/port for datacenter proxies)
options.set_preference("network.proxy.ssl", host)
options.set_preference("network.proxy.ssl_port", port)
SOCKS proxy (optional: set if using SOCKS5)
options.set_preference("network.proxy.socks", host)
options.set_preference("network.proxy.socks_port", socks_port)
options.set_preference("network.proxy.socks_version", 5)
Bypass list
options.set_preference(
"network.proxy.no_proxies_on",
"localhost,127.0.0.1"
)
return webdriver.Firefox(options=options)
driver = create_firefox_with_proxy("your-proxy.sparkproxy.com", 10000)
driver.get("https://httpbin.org/ip")
driver.quit()
```
-
Firefox proxy with the Proxy class
You can also use the same
Proxycapability object as Chrome:```python
from selenium.webdriver.common.proxy import Proxy, ProxyType
from selenium.webdriver.firefox.options import Options as FirefoxOptions
proxy = Proxy()
proxy.proxy_type = ProxyType.MANUAL
proxy.http_proxy = "gateway.sparkproxy.io:10000"
proxy.ssl_proxy = "gateway.sparkproxy.io:10000"
options = FirefoxOptions()
options.proxy = proxy
driver = webdriver.Firefox(options=options)
```
-
-
Proxy Authentication in Chrome: The Core Problem {#chrome-proxy-auth}
This is the most misunderstood part of Selenium proxy configuration:
Chrome does not support credentials in the
--proxy-serverflag.```python
THIS DOES NOT WORK — credentials are silently ignored
options.add_argument("--proxy-server=user:[email protected]:10000")
```
Chrome was intentionally designed this way. The browser expects proxy credentials to come through authentication dialogs (which WebDriver can't reliably intercept) or through dedicated credential-storage APIs. There are three practical solutions:
-
Solution 1: IP Whitelisting (Recommended)
Add your machine's public IP address to the proxy whitelist in your SparkProxy dashboard. No credentials needed in the driver configuration at all — the proxy grants access based on IP. This is the cleanest approach for Selenium automation running from a fixed-IP server.
```python
With IP whitelisting, no credentials required
options.add_argument("--proxy-server=your-proxy.sparkproxy.com:10000")
```
-
Solution 2: Selenium Wire (see next section)
Selenium Wire intercepts the browser's proxy authentication challenge at the Python level and handles credential injection transparently. This is the recommended approach for credentials-based auth.
-
Solution 3: Chrome Extension for Proxy Auth
Create a packaged Chrome extension that handles the
chrome.webRequest.onAuthRequiredevent. The extension provides credentials programmatically, bypassing the auth dialog.```python
import zipfile
import os
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
def create_proxy_extension(host, port, username, password):
"""
Creates a Chrome extension ZIP that handles proxy authentication.
Returns the path to the generated .zip file.
"""
manifest = """
{
"version": "1.0.0",
"manifest_version": 2,
"name": "Proxy Auth",
"permissions": ["proxy", "tabs", "unlimitedStorage", "storage",
"
", "webRequest", "webRequestBlocking"], "background": {"scripts": ["background.js"]},
"minimum_chrome_version": "22.0.0"
}
"""
background_js = f"""
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: "{username}",
password: "{password}"
}}
}};
}}
chrome.webRequest.onAuthRequired.addListener(
callbackFn,
{{urls: ["
"]}}, ["blocking"]
);
"""
ext_path = "proxy_auth_extension.zip"
with zipfile.ZipFile(ext_path, "w") as zf:
zf.writestr("manifest.json", manifest)
zf.writestr("background.js", background_js)
return ext_path
Use the extension
ext_path = create_proxy_extension(
host="gateway.sparkproxy.io",
port=10000,
username="YOUR_USER",
password="YOUR_PASS",
)
options = Options()
options.add_extension(ext_path)
driver = webdriver.Chrome(options=options)
driver.get("https://httpbin.org/ip")
driver.quit()
os.remove(ext_path) # Clean up
```
Security note: The extension approach embeds credentials in the ZIP file in plain text. Use IP whitelisting or Selenium Wire in production, both avoid storing credentials in files.
-
-
Selenium Wire for Authenticated Proxy (Recommended) {#selenium-wire}
Selenium Wire extends Selenium's WebDriver with proxy support including authentication, request/response interception, and per-request proxy assignment. It is the cleanest solution for credential-based datacenter proxy authentication in Selenium.
```bash
pip install selenium-wire
```
```python
from seleniumwire import webdriver # Drop-in replacement for selenium.webdriver
Authenticated datacenter proxy
sw_options = {
"proxy": {
"http": "http://user:[email protected]:10000",
"https": "http://user:[email protected]:10000",
"no_proxy": "localhost,127.0.0.1",
}
}
driver = webdriver.Chrome(seleniumwire_options=sw_options)
driver.get("https://httpbin.org/ip")
Bonus: Selenium Wire lets you inspect requests made by the browser
for requests in the driver.requests:
if request.response:
print(f"{request.url} → {request.response.status_code}")
driver.quit()
```
-
Selenium Wire with IP whitelisting (no credentials)
```python
from seleniumwire import webdriver
sw_options = {
"proxy": {
"http": "http://gateway.sparkproxy.io:10000",
"https": "http://gateway.sparkproxy.io:10000",
}
}
driver = webdriver.Chrome(seleniumwire_options=sw_options)
driver.get("https://httpbin.org/ip")
driver.quit()
```
-
Selenium Wire with SOCKS5
```python
from seleniumwire import webdriver
sw_options = {
"proxy": {
"http": "socks5://user:[email protected]:1080",
"https": "socks5://user:[email protected]:1080",
}
}
driver = webdriver.Chrome(seleniumwire_options=sw_options)
```
Selenium Wire supports all major browsers via their respective webdriver classes:
webdriver.Chrome,webdriver.Firefox,webdriver.Edge.
-
-
Proxy Rotation in Selenium {#proxy-rotation}
Each Selenium WebDriver session is bound to one proxy at launch — the proxy cannot be changed mid-session via ChromeOptions. To rotate proxies, create a new driver instance for each proxy or IP.
-
Rotate by creating a new driver per session
```python
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
import random
PROXY_LIST = [
"proxy1.sparkproxy.com:10000",
"proxy2.sparkproxy.com:10001",
"proxy3.sparkproxy.com:10002",
]
def get_driver(proxy: str) -> webdriver.Chrome:
options = Options()
options.add_argument(f"--proxy-server={proxy}")
options.add_argument("--headless=new")
options.add_argument("--no-sandbox")
return webdriver.Chrome(options=options)
urls = [
"https://httpbin.org/ip",
"https://httpbin.org/user-agent",
"https://httpbin.org/headers",
]
for url in urls:
proxy = random.choice(PROXY_LIST)
driver = get_driver(proxy)
try:
driver.get(url)
print(f"[{proxy}] {driver.current_url}: OK")
finally:
driver.quit() # Always quit to free resources
```
-
Rotate with Selenium Wire per request
Selenium Wire allows changing the proxy between requests within the same session using the
driver.proxyproperty:```python
from seleniumwire import webdriver
import random
PROXIES = [
{"http": "http://user:[email protected]:10000",
"https": "http://user:[email protected]:10000"},
{"http": "http://user:[email protected]:10001",
"https": "http://user:[email protected]:10001"},
]
driver = webdriver.Chrome()
for url in ["https://httpbin.org/ip", "https://httpbin.org/ip"]:
driver.proxy = random.choice(PROXIES) # Rotate before each request
driver.get(url)
print(driver.find_element("tag name", "pre").text)
driver.quit()
```
driver.proxyassignment in Selenium Wire takes effect for all subsequent requests in the session — no restart required.
-
-
Selenium Grid and Remote WebDriver with Proxy {#remote-webdriver}
When running Selenium against a remote Grid node, pass the proxy via
ChromeOptionsbefore creating the remote session:```python
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.proxy import Proxy, ProxyType
proxy = Proxy()
proxy.proxy_type = ProxyType.MANUAL
proxy.http_proxy = "your-proxy.sparkproxy.com:10000"
proxy.ssl_proxy = "your-proxy.sparkproxy.com:10000"
options = Options()
options.proxy = proxy
Remote Grid session (Selenium Grid 4 / cloud provider)
driver = webdriver.Remote(
command_executor="http://selenium-hub:4444/wd/hub",
options=options,
)
driver.get("https://httpbin.org/ip")
driver.quit()
```
Grid note: The proxy is configured in the browser running on the Grid node, not the machine running the test. The Grid node's IP must be whitelisted in your proxy dashboard (for IP auth), or credentials must be passed via Selenium Wire or the extension method.
-
Test Your Proxy in Selenium {#test-proxy}
Before running your actual automation, verify the proxy is routing correctly.
```python
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
import json
def verify_proxy(proxy_host: str, proxy_port: int) -> dict:
options = Options()
options.add_argument(f"--proxy-server={proxy_host}:{proxy_port}")
options.add_argument("--headless=new")
options.add_argument("--no-sandbox")
options.add_argument("--disable-dev-shm-usage")
driver = webdriver.Chrome(options=options)
try:
Test 1: Check exit IP
driver.get("https://httpbin.org/ip")
ip_data = json.loads(driver.find_element("tag name", "pre").text)
Test 2: Check that HTTPS also routes through proxy
driver.get("https://ipv4.icanhazip.com")
https_ip = driver.find_element("tag name", "body").text.strip()
return {
"proxy": f"{proxy_host}:{proxy_port}",
"exit_ip_httpbin": ip_data.get("origin"),
"exit_ip_https": https_ip,
"status": "ok",
}
except Exception as e:
return {"proxy": f"{proxy_host}:{proxy_port}", "status": "error", "error": str(e)}
finally:
driver.quit()
result = verify_proxy("your-proxy.sparkproxy.com", 10000)
print(result)
{"proxy": "your-proxy.sparkproxy.com:10000", "exit_ip_httpbin": "1.2.3.4", ...}
```
Both
exit_ip_httpbinandexit_ip_httpsshould match the proxy's datacenter IP. If they are your real IP, the proxy is not being applied.
-
Common Selenium Proxy Errors and Fixes {#common-errors}
| Error / Symptom | Cause | Fix |
|---|---|---|
|
--proxy-server=user:pass@host:portignored | Chrome does not support credentials in this flag | Use IP whitelisting, Selenium Wire, or the extension method ||
ERR_TUNNEL_CONNECTION_FAILED| Proxy host unreachable, port blocked, or proxy down | Test:curl -x proxy-host:port https://httpbin.org/ip; check port is open ||
ERR_PROXY_AUTH_REQUIRED| Credentials required but not provided | Use Selenium Wire or extension for auth; or add machine IP to whitelist || Browser opens, but real IP shown on target site | Proxy set but not routing correctly | Confirm
--proxy-serverargument was added beforewebdriver.Chrome()call; check no typo in host ||
WebDriverException: unknown error: net::ERR_NO_SUPPORTED_PROXIES| Wrong scheme used (e.g.,https://proxy URL for Chrome) | Remove the scheme from--proxy-serveror usehttp://|| Selenium Wire:
OSError: [Errno 48] Address already in use| Port conflict — Selenium Wire uses a local proxy listener | Set a custom port:sw_options = {"port": 9999}|| Firefox:
SSL_ERROR_RX_RECORD_TOO_LONG| Proxy is not configured for HTTPS (only HTTP pref set) | Set bothnetwork.proxy.sslandnetwork.proxy.ssl_portprefs ||
SessionNotCreatedException: Chrome not reachable| Extension ZIP malformed or manifest error | Validatemanifest.jsonhas"manifest_version": 2andbackground.scriptsfield || Proxy works for first request, then 407 errors | IP whitelist entry expired (DHCP IP change) | Use credential auth via Selenium Wire; or assign a static IP |
-
About the Author
SparkProxy Technical Team — The SparkProxy engineering team builds and maintains global datacenter and residential proxy infrastructure. This guide reflects proxy integration patterns tested with Selenium 4.20+, Chrome 124+, Firefox 125+, and Selenium Wire 5.1.
Citations: Browser Options: proxy — Selenium WebDriver Documentation · selenium-wire — GitHub: wkeeling/selenium-wire