# Selenium with an authenticated proxy: a local forwarder that works

> Authenticated proxies in Selenium: why Chrome ignores proxy credentials, and a 40-line Python forwarder that adds them. Residential, no KYC.

- URL: https://crawlrelay.com/docs/selenium/
- Last updated: 2026-10-13
- Publisher: CrawlRelay (https://crawlrelay.com)

Chrome's proxy flag has no place for a password. A tiny local forwarder on 127.0.0.1 adds the credentials, so Selenium only ever sees an open local proxy.

**Quick answer — How do I use a proxy with a username and password in Selenium?**

Run a small local forwarder that adds the `Proxy-Authorization` header, and point Chrome at it with `--proxy-server=http://127.0.0.1:8899`. Chrome ignores credentials in that flag, and Selenium has no portable option for proxy passwords. **CrawlRelay** residential proxies work this way on `gw.crawlrelay.com:7777`, from $0.50/GB. Paid in crypto, with no KYC.

## Selenium setup at a glance

| Attribute | Value |
| --- | --- |
| Why a forwarder | Chrome's `--proxy-server` flag accepts no username or password |
| Forwarder | Listens on `127.0.0.1:8899`, adds `Proxy-Authorization`, relays to `gw.crawlrelay.com:7777` |
| Chrome option | `--proxy-server=http://127.0.0.1:8899` |
| Rotation | Each new CONNECT tunnel is a new connection, so usually a new exit; add a session ID for one IP |
| Simpler alternative | [Playwright](https://crawlrelay.com/docs/playwright/) takes the username and password directly |

## How does the local forwarder work?

It accepts the browser's proxy request, inserts one header with your credentials, and then copies bytes in both directions. For an HTTPS site the browser sends `CONNECT host:443`, the gateway answers `200 Connection established`, and TLS then runs end to end between Chrome and the website. The forwarder never sees page content in clear text.

This minimal version handles HTTPS sites, where each connection carries one CONNECT tunnel. That covers almost every website today. Keep it bound to `127.0.0.1` so no other machine can use your credentials.

*forwarder.py (Python 3.8+, standard library only)*

```python
import asyncio
import base64
import os

UPSTREAM = ("gw.crawlrelay.com", 7777)
USER = os.environ.get("CRAWLRELAY_USER", "USERNAME-country-us")
PASSWORD = os.environ.get("CRAWLRELAY_PASSWORD", "PASSWORD")
AUTH = b"Proxy-Authorization: Basic " + base64.b64encode(("%s:%s" % (USER, PASSWORD)).encode())


async def pipe(reader, writer):
    try:
        while True:
            data = await reader.read(65536)
            if not data:
                break
            writer.write(data)
            await writer.drain()
    except ConnectionError:
        pass
    finally:
        writer.close()


async def handle(client_reader, client_writer):
    try:
        head = await client_reader.readuntil(b"\r\n\r\n")  # request line and headers from the browser
    except asyncio.IncompleteReadError:
        client_writer.close()
        return
    lines = head.split(b"\r\n")
    lines.insert(1, AUTH)  # add the credentials right after the request line
    up_reader, up_writer = await asyncio.open_connection(*UPSTREAM)
    up_writer.write(b"\r\n".join(lines))
    await up_writer.drain()
    await asyncio.gather(pipe(client_reader, up_writer), pipe(up_reader, client_writer))


async def main():
    server = await asyncio.start_server(handle, "127.0.0.1", 8899)
    async with server:
        await server.serve_forever()


if __name__ == "__main__":
    asyncio.run(main())
```

## How do I point Selenium at the forwarder?

Start `forwarder.py` in one terminal, then run your Selenium script with the local proxy address. Selenium Manager, built into Selenium 4.6 and later, downloads a matching ChromeDriver, so there is nothing else to install.

*selenium_example.py*

```python
from selenium import webdriver
from selenium.webdriver.common.by import By

options = webdriver.ChromeOptions()
options.add_argument("--proxy-server=http://127.0.0.1:8899")  # the local forwarder
options.add_argument("--headless=new")

driver = webdriver.Chrome(options=options)
try:
    driver.set_page_load_timeout(60)
    driver.get("https://api.ipify.org")
    print("exit IP:", driver.find_element(By.TAG_NAME, "body").text)
finally:
    driver.quit()
```

## How do I get one IP per Selenium session, or a new IP per page?

The forwarder sends whatever username you give it, so the session behaviour comes from that username:

- **Rotating per connection:** leave out the session part (`USERNAME-country-us`). Chrome opens several connections per page, so a single page can load through several exits.
- **One IP per Selenium session:** set `CRAWLRELAY_USER` to `USERNAME-country-us-session-run42-ttl-30` before you start the forwarder. Every connection then leaves through the same IP for up to 30 minutes; the IP can change earlier.
- **Several sessions in parallel:** run one forwarder per session on different local ports, such as 8899 and 8900, and give each WebDriver its own port.

## What about selenium-wire or browser extensions?

selenium-wire, a popular package that added proxy authentication by intercepting traffic, was archived by its author in January 2024 and receives no updates. A browser extension that answers the proxy's authentication request also works, but it must be packaged and loaded into each profile. The forwarder above has no dependencies and works with any browser that Selenium drives. For new projects, [Playwright](https://crawlrelay.com/docs/playwright/) is simpler still: it takes the proxy username and password directly.

## Selenium and proxies: questions

### Why does Chrome show a login pop-up with my proxy in Selenium?

Because the proxy asked for credentials and Chrome had none: its `--proxy-server` flag takes only a host and port. In headless mode the same problem appears as `ERR_TUNNEL_CONNECTION_FAILED`. Use a local forwarder that adds the credentials, or switch to Playwright, which accepts a username and password.

### Does the forwarder slow down my scraping?

Hardly. It copies bytes between two local sockets and one remote one, without decrypting anything. The time a page takes depends on the residential exit and on the target site, not on a forwarder running on the same machine.

### Can I use Firefox instead of Chrome with Selenium?

Yes. Set Firefox's proxy preferences through `FirefoxOptions`: `network.proxy.type` to 1, and `network.proxy.http` and `network.proxy.ssl` to `127.0.0.1` with port 8899. Keep the forwarder in front: Firefox asks for proxy credentials in a dialog that Selenium cannot fill reliably either.

### Is my password safe in the forwarder?

It stays on your machine as long as the forwarder listens on `127.0.0.1`, as in the example. Read it from environment variables, never commit it, and use a dedicated sub-user with a traffic cap for each scraper so a leaked password cannot drain your whole plan.

**Give Selenium a residential exit** $1.50 for 1 GB to test, $0.50/GB from 50 GB. [See pricing](https://crawlrelay.com/pricing/) · [Playwright guide](https://crawlrelay.com/docs/playwright/)

---

CrawlRelay: CrawlRelay is a developer-first rotating residential and 4G/5G mobile proxy service for scrapers and AI data pipelines: non-expiring pay-as-you-go traffic from $0.50/GB, paid in crypto, with no ID upload. No KYC — no ID, no selfie, no documents. Pay in crypto.
