Selenium proxy setup with a login

Chrome's `--proxy-server` flag takes the proxy address but not the login. Selenium can pass the login through a WebDriver BiDi handler or a small extension, without extra packages.

Protocols
HTTP proxy on port 7000 (HTTPS sites through CONNECT). Chrome has no SOCKS5 login
Where the login goes
A WebDriver BiDi auth handler, or a small extension
Rotation
A sticky -sid- login per driver: one IP for up to 60 minutes
Works with
Residential and mobile proxies

Before you start

  • Selenium 4.34 or newer (pip install -U selenium); older releases lack the BiDi calls below. Selenium Manager fetches a matching ChromeDriver.
  • Your proxy login and password from the Residential or Mobile page of the dashboard.
  • Traffic on the product you use: a login without traffic gets 402.
Connection details
Host
gate.aeonproxy.com
Port (HTTP / HTTPS)
7000
Login
your proxy login, with targeting keys if you need them: LOGIN-cc-us-sid-abc123
Password
your proxy password

Copy the login and password from the Residential or Mobile page of the dashboard; the generator there also writes ready lines. Key syntax: targeting and sessions.

Why the flag alone is not enough

--proxy-server=http://gate.aeonproxy.com:7000 only tells Chrome where the proxy is. With a login written into that address pages fail with ERR_NO_SUPPORTED_PROXIES; with no login, ERR_INVALID_AUTH_CREDENTIALS. The login has to come from a handler that answers the proxy's 407.

Option 1: the WebDriver BiDi auth handler

Turn BiDi on and register the login once. Selenium then answers the proxy for every page of that driver.

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

options = webdriver.ChromeOptions()
options.add_argument("--proxy-server=http://gate.aeonproxy.com:7000")
options.enable_bidi = True

driver = webdriver.Chrome(options=options)
driver.network.add_auth_handler("LOGIN-cc-us-sid-ab12cd34-ttl-30", "PASSWORD")

# open the first page over BiDi, not with driver.get() (see the note below)
driver.browsing_context.navigate(context=driver.current_window_handle, url="https://api.ipify.org", wait="complete")
print(driver.find_element(By.TAG_NAME, "body").text)

driver.get("https://example.com")  # from here on driver.get() works as usual
print(driver.title)
driver.quit()

In our test (Selenium 4.51, Chrome 156), a driver.get() as the first page got stuck on the proxy's 407 until the page load timeout, with Timed out waiting for response to BiDi command in the output. browsing_context.navigate worked in every run, and after the first page driver.get() works too: Chrome reuses the login.

add_auth_handler answers every HTTP login prompt, a site's own included. If a site you test uses HTTP authentication, take option 2, which answers only the proxy.

Option 2: a small extension

A Manifest V3 extension with the webRequestAuthProvider permission can answer the proxy's challenge, and only the proxy's (isProxy). Branded Chrome ignores the --load-extension flag since version 137, so let Selenium install the extension:

import json
import pathlib
from selenium import webdriver
from selenium.webdriver.common.by import By

def proxy_login_extension(folder, login, password):
    """Writes a tiny Chrome extension that answers the proxy's login prompt."""
    d = pathlib.Path(folder)
    d.mkdir(exist_ok=True)
    (d / "manifest.json").write_text(json.dumps({
        "manifest_version": 3, "name": "proxy-login", "version": "1.0",
        "permissions": ["webRequest", "webRequestAuthProvider"],
        "host_permissions": ["<all_urls>"],
        "background": {"service_worker": "sw.js"},
    }))
    creds = json.dumps({"username": login, "password": password})
    (d / "sw.js").write_text(
        "chrome.webRequest.onAuthRequired.addListener("
        f"(d, done) => done(d.isProxy ? {{authCredentials: {creds}}} : {{}}),"
        "{urls: ['<all_urls>']}, ['asyncBlocking']);"
    )
    return str(d.resolve())

ext = proxy_login_extension("proxy-login", "LOGIN-cc-us-sid-ab12cd34-ttl-30", "PASSWORD")

options = webdriver.ChromeOptions()
options.add_argument("--proxy-server=http://gate.aeonproxy.com:7000")
options.enable_bidi = True
options.enable_webextensions = True  # lets Selenium install an unpacked extension

driver = webdriver.Chrome(options=options)
driver.webextension.install(path=ext)
driver.get("https://api.ipify.org")
print(driver.find_element(By.TAG_NAME, "body").text)
driver.quit()

enable_webextensions adds Chrome's --enable-unsafe-extension-debugging and --remote-debugging-pipe flags. Selenium warns that the pipe turns off many DevTools (CDP) features, so keep CDP calls out of this setup.

SOCKS5

Chrome supports no login for SOCKS5 proxies, and neither option changes that: with --proxy-server=socks5://gate.aeonproxy.com:7001 pages fail with ERR_SOCKS_CONNECTION_FAILED. Use the HTTP port 7000.

Rotating or sticky

A browser opens many connections for one page, and a rotating login gives each a new IP, so one page can load from several addresses. Use a sticky login per driver, such as LOGIN-cc-us-sid-ab12cd34-ttl-30, and start a new driver with a new key when you need a new IP. To check the exit, open IP checker in the driver: it shows the IP, location and WebRTC leaks.

If it does not work

What you seeWhat to check
Timed out waiting for response to BiDi command, the first page never loadsThe first page was opened with driver.get(). Open it with browsing_context.navigate, as in option 1.
ERR_INVALID_AUTH_CREDENTIALSNo handler answered, or the login, the password or a key in the login is wrong.
ERR_NO_SUPPORTED_PROXIESA login inside --proxy-server. Keep only http://gate.aeonproxy.com:7000 there.
net::ERR_TUNNEL_CONNECTION_FAILEDThe gateway refused the tunnel, and Chrome does not show the code: usually 402 (no traffic left), 403 (a target blocked by default) or 502 (the exit failed, retry). curl with the same login prints it: CONNECT tunnel failed, response 402.
ERR_SOCKS_CONNECTION_FAILEDSOCKS5 with a login, which Chrome cannot do. Use port 7000.
The extension does nothingBranded Chrome 137 or newer ignores --load-extension. Install it with driver.webextension.install() as above.

Questions

Yes. We ran both with --headless=new.

Yes. Each driver has its own login, so LOGIN-cc-de-sid-de01 in one and LOGIN-cc-jp-sid-jp01 in another run side by side. Bought traffic has no thread limit.

Its GitHub repository is archived and its last release is from 2022, so this guide does not use it. Both options above work with Selenium alone.

Proxy questions? Ask support in the live chat.