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.

Jun 16, 2026 - 12:16
Jun 2, 2026 - 12:40
 4
How to Integrate Proxies with Selenium
How to Integrate Proxies with Selenium
  • 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-server flag. Passing --proxy-server=user:pass@host:port does 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, the Proxy capability 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-server argument. 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-list argument accepts a comma-separated list of hostnames and IP ranges to bypass. Use to 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-server flag accepts http://, https://, and socks5:// 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 Proxy class 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 ProxyType enum 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:config proxy 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 Proxy capability 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-server flag.

    ```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")

      ```

      IP whitelisting for proxies

    • 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.onAuthRequired event. 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.

    proxy rotation strategies

    • 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.proxy property:

      ```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.proxy assignment 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 ChromeOptions before 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_httpbin and exit_ip_https should 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:port ignored | 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-server argument was added before webdriver.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-server or use http:// |

    | 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 both network.proxy.ssl and network.proxy.ssl_port prefs |

    | SessionNotCreatedException: Chrome not reachable | Extension ZIP malformed or manifest error | Validate manifest.json has "manifest_version": 2 and background.scripts field |

    | 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