# How to route Selenium browser traffic through a proxy

[All guides](https://proxylane.dev/blog) 

DEVELOPER GUIDES · 8 MIN READ

Set an HTTP proxy on Chrome with Selenium, verify egress and target content, and separate browser traffic from driver downloads.

[**Victor Paulius** Tech Writer at ProxyLane](https://proxylane.dev/about/victor)   UpdatedSep 29, 2026

On this page [Prerequisites](https://proxylane.dev/blog/selenium-proxy#prerequisites)  [Configure Chrome’s proxy](https://proxylane.dev/blog/selenium-proxy#configure-chromes-proxy)  [Separate browser requests from driver downloads](https://proxylane.dev/blog/selenium-proxy#separate-browser-requests-from-driver-downloads)  [Diagnose the connection](https://proxylane.dev/blog/selenium-proxy#diagnose-the-connection)

About ProxyLane  

- **Ethically sourced**Real residential devices, not datacenter ranges
 
- **Low fraud scores**98.7% low-risk IPs on Scamalytics
 
- **28M+ IPs in 195 countries**Country, city and ISP targeting

  [How we source and check IPs](https://proxylane.dev/about#trust-center)

 

Set Chrome’s proxy when creating the Selenium WebDriver, then verify the egress response and the target’s final origin, HTTP status, and required page marker in that browser. Selenium Manager’s own download proxy is a separate setting and does not route page requests.

 

## Prerequisites

 

- [Python](https://www.python.org/downloads/)  3.14.6.
 
- Selenium 4.49.0, installed with `python -m pip install selenium==4.49.0`.
 
- Google Chrome 154.0.8037.58, installed from the  [official Chrome download page](https://www.google.com/chrome/) .
 
- An unauthenticated HTTP proxy endpoint and permission to make bounded read-only requests to the configured egress and target URLs.
 
- An egress endpoint that returns JSON with an `ip` field, plus a permitted target page with a stable text marker.

 

**Warning:** Browser requests can load target subresources, and a target’s `GET` route can still change state. Keep production disabled; start with staging or a sandbox and set a request or spend cap. This probe makes no application writes by design. Stop on an unexpected redirect or response, then close the WebDriver session.

 

## Configure Chrome’s proxy

 

Save the complete example as `probe.py`. Bind `PROXY_HOSTPORT` without a scheme or credentials. Bind `EGRESS_URL` and `TARGET_URL` to approved HTTP or HTTPS endpoints, `EXPECTED_EXIT` to the expected exact IP address, and `EXPECTED_MARKER` to text in the permitted target page. Keep credentials out of both URLs.

 

```python
import ipaddress
import json
import os
import time
from urllib.parse import urlsplit

from selenium import webdriver
from selenium.webdriver.chrome.options import Options


PROXY_HOSTPORT = os.environ.get("PROXY_HOSTPORT", "")
EGRESS_URL = os.environ.get("EGRESS_URL", "")
EXPECTED_EXIT = os.environ.get("EXPECTED_EXIT", "")
TARGET_URL = os.environ.get("TARGET_URL", "")
EXPECTED_MARKER = os.environ.get("EXPECTED_MARKER", "")

if not all((PROXY_HOSTPORT, EGRESS_URL, EXPECTED_EXIT, TARGET_URL, EXPECTED_MARKER)):
    raise SystemExit("Set PROXY_HOSTPORT, EGRESS_URL, EXPECTED_EXIT, TARGET_URL, and EXPECTED_MARKER")
parsed_proxy = urlsplit("http://" + PROXY_HOSTPORT)
if (
    not parsed_proxy.hostname
    or parsed_proxy.username
    or parsed_proxy.password
    or parsed_proxy.path
    or parsed_proxy.query
    or parsed_proxy.fragment
    or not parsed_proxy.port
    or not 1 <= parsed_proxy.port <= 65535
):
    raise SystemExit("PROXY_HOSTPORT must be host:port without a scheme or credentials")
try:
    for name, value in (("EGRESS_URL", EGRESS_URL), ("TARGET_URL", TARGET_URL)):
        parsed = urlsplit(value)
        if parsed.scheme not in {"http", "https"} or not parsed.hostname or parsed.username or parsed.password:
            raise SystemExit(f"{name} must be an HTTP(S) URL without credentials")
        parsed.port
    ipaddress.ip_address(EXPECTED_EXIT)
except ValueError:
    raise SystemExit("Use valid HTTP(S) URLs and a valid EXPECTED_EXIT IP address") from None


def current_document_status(driver):
    frame = driver.execute_cdp_cmd("Page.getFrameTree", {})["frameTree"]["frame"]
    deadline = time.monotonic() + 5
    while time.monotonic() < deadline:
        for entry in driver.get_log("performance"):
            event = json.loads(entry["message"])["message"]
            params = event.get("params", {})
            if (
                event.get("method") == "Network.responseReceived"
                and params.get("type") == "Document"
                and params.get("frameId") == frame["id"]
                and params.get("loaderId") == frame.get("loaderId")
            ):
                return int(params["response"]["status"])
        time.sleep(0.05)
    return None


options = Options()
options.add_argument("--headless=new")
options.add_argument(f"--proxy-server=http://{PROXY_HOSTPORT}")
options.set_capability("goog:loggingPrefs", {"performance": "ALL"})
driver = None
try:
    driver = webdriver.Chrome(options=options)
    driver.set_page_load_timeout(15)
    driver.execute_cdp_cmd("Network.enable", {})
    driver.get(EGRESS_URL)
    egress_status = current_document_status(driver)
    try:
        observed_exit = json.loads(driver.find_element("tag name", "body").text)["ip"]
    except (KeyError, json.JSONDecodeError):
        raise RuntimeError("Egress endpoint did not return JSON with an ip field") from None
    if egress_status != 200 or observed_exit != EXPECTED_EXIT:
        raise RuntimeError("Proxy egress check did not match the expected value")

    driver.get(TARGET_URL)
    target_status = current_document_status(driver)
    target_body = driver.find_element("tag name", "body").text
    target_origin = urlsplit(TARGET_URL)
    final_origin = urlsplit(driver.current_url)
    if (final_origin.scheme, final_origin.netloc) != (target_origin.scheme, target_origin.netloc):
        raise RuntimeError("Target navigation left the configured origin")
    if target_status != 200 or EXPECTED_MARKER not in target_body:
        raise RuntimeError("Target status or required page marker did not match")
    print({"egress_match": True, "target_status": target_status, "marker_match": True})
except Exception as error:
    raise SystemExit(f"Probe failed ({type(error).__name__}); check settings and local logs") from None
finally:
    if driver is not None:
        driver.quit()
```

 

Run `python probe.py`. Selenium 4.49.0 uses Selenium Manager to locate a compatible driver for the installed browser. `goog:loggingPrefs` enables Chrome performance events; the status helper selects the final top-level document by its frame and loader identifiers. Raw events can include sensitive request details, so keep them private and do not print or attach them to a public log.

 

A successful fixture run prints:

 

```text
{'egress_match': True, 'target_status': 200, 'marker_match': True}
```

 

`egress_match` means the egress JSON IP exactly matched `EXPECTED_EXIT`; `target_status` is the top-level target response status; and `marker_match` means the body contained `EXPECTED_MARKER`. The fixture returned a reserved documentation IP, not a real proxy exit.

 

The  [Selenium options guide](https://www.selenium.dev/documentation/webdriver/drivers/options/)  shows browser options and the  [Python Proxy API](https://www.selenium.dev/selenium/docs/api/py/selenium_webdriver_common/selenium.webdriver.common.proxy.html)  defines proxy capability fields. This narrow example sets Chrome’s HTTP proxy with a launch argument and supports an unauthenticated endpoint. It checks an exact JSON `ip` value, a final target origin, HTTP 200, and required body text before it reports success.

 

## Separate browser requests from driver downloads

 

The browser uses `--proxy-server` for page traffic. Selenium Manager uses its own network connection to find or download browsers and drivers. Its `SE_PROXY` setting configures that separate management request; it does not replace the Chrome option above. The  [Selenium Manager guide](https://www.selenium.dev/documentation/selenium_manager/)  documents both paths.

 

Chrome does not use credentials embedded in manual proxy settings, according to the  [Chrome proxy guide](https://chromium.googlesource.com/chromium/src/+/HEAD/net/docs/proxy.md) . Do not place `user:password@host:port` in `--proxy-server`, command arguments, or source. For authenticated routes, select an extension, enterprise policy, or provider integration that documents browser support and secret handling. Do not copy proxy credentials into the target’s `Authorization` header. Chrome’s SOCKS5 support also does not provide proxy authentication.

 

An HTTP proxy connection is not encrypted between Chrome and the proxy. HTTPS target traffic uses a `CONNECT` tunnel and keeps TLS between Chrome and the target, but the proxy sees the target hostname. An HTTPS proxy encrypts the browser-to-proxy hop. Confirm the endpoint scheme and provider auth method before sending secrets.

 

## Diagnose the connection

 

| Evidence | Likely layer | Next check |
| --- | --- | --- |
| Chrome or driver fails before navigation | Browser setup | Check Chrome, Selenium, Selenium Manager, and driver startup output |
| Navigation fails before response headers | Browser-to-proxy route | Check protocol, host, port, firewall, and runner reachability |
| Egress JSON or IP differs | Proxy route or egress endpoint | Check the expected exit and exact JSON `ip` field |
| Target returns a non-200 status | Target response | Inspect the authorized staging response and redirect behavior |
| Target returns 200 without the marker | Page content | Check the required text, access policy, and selector or render timing |
| Browser does not use the expected proxy | Proxy configuration | Inspect the browser capability and any bypass rules |

 

The page-load timeout bounds a navigation wait; it does not bound the entire job or all network activity. This example uses 2 navigations and no application write, but Chrome can request page resources as well. Set explicit request or spend limits in the runner. For a command-line proxy check, continue with the  [curl proxy guide](https://proxylane.dev/blog/curl-proxy/) .

 

The local proof used Selenium 4.49.0, Python 3.14.6, Chrome 154.0.8037.58, and an unauthenticated loopback-only forwarding fixture. The fixture returned the reserved test IP `198.51.100.7`; it was not a public exit measurement. The run confirms browser routing and response checks against that fixture, not provider egress or target access in production.

 

## Sources and further reading

- [Selenium browser options](https://www.selenium.dev/documentation/webdriver/drivers/options/)

- [Selenium Python Proxy API](https://www.selenium.dev/selenium/docs/api/py/selenium_webdriver_common/selenium.webdriver.common.proxy.html)

- [Selenium Manager](https://www.selenium.dev/documentation/selenium_manager/)

- [Chrome-specific Selenium functionality](https://www.selenium.dev/documentation/webdriver/browsers/chrome/)

- [Chrome proxy support](https://chromium.googlesource.com/chromium/src/+/HEAD/net/docs/proxy.md)

ProxyLane  Traffic never expires

 

## [Premium residential proxies](https://proxylane.dev/residential-proxies) From $2/GB

 

Scale your workflows with the tools you already use. Rotating or sticky sessions up to 72 hours.

 

[Try 350 MB for $1.95](https://proxylane.dev/register?interest=proxies&plan=trial)   [View plans](https://proxylane.dev/pricing)

## Keep reading

[Use cases · 4 min read

### Amazon Scraper API vs Proxy: Choose a Product Data Source

Compare seller APIs, licensed Amazon product data and proxy page checks by record, access scope and reuse rights.

 Read guide](https://proxylane.dev/blog/amazon-scraper-api-vs-proxy)   [Integration guides · 5 min read

### Antidetect browser proxy setup: choose a profile guide

Choose the right anti-detect browser proxy guide, map the shared verification steps, and keep account access separate from the network route.

 Read guide](https://proxylane.dev/blog/antidetect-browser-proxy-setup)   [Comparisons · 11 min read

### Best Proxies for Market Research: Choose by Sample and Cost

Our picks for market research: ProxyLane for small, intermittent projects, plus options for regional tracking, monthly collection and managed extraction.

 Read guide](https://proxylane.dev/blog/best-proxies-for-market-research)

Canonical source: https://proxylane.dev/blog/selenium-proxy

Documentation index: https://proxylane.dev/llms.txt
