Free proxies

Free Proxies for Selenium: What Actually Works

Free proxies for Selenium work for a throwaway session, not an unattended run. How to set the Chrome proxy arg and Selenium Wire, and why free exits hang.

HProxy Team··7 min read
HProxy.Free proxies

Skip the dead lists.

Our free proxy list re-checks every exit every few minutes across 100+ countries, with a live last-checked time, so you copy IPs that worked moments ago, not a stale text dump.

Open the free proxy list

Free proxies for Selenium work for a throwaway, attended session and fail an unattended run. A fresh free proxy is fine when you want to check how a page renders from another country or confirm your automation routes traffic at all, because if the exit dies you just rerun it. It falls apart the moment the job has to run on its own, because Selenium has no built-in per-request rotation the way a crawler does: a dead free exit hangs the page load until it times out, and swapping to a new IP means quitting the driver and launching a whole new browser. Free is fine for a look, not for a loop.

We run a proxy network and a live proxy checker, so we see the same Selenium pattern constantly: a script that works in a demo against one hand-picked proxy, then stalls overnight because the free pool underneath it churned. This covers how to set a proxy in Selenium the right way, why authenticated proxies need more than the command-line flag, why a free pool is brutal specifically for a browser, and how to verify the exit. For the paid-tier choices per target, see proxies for Selenium.

Setting a proxy with the Chrome flag

The simplest way to point Selenium's Chrome at a proxy is a launch argument. This is all you need for an open proxy, which nearly every free entry is:

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

options = Options()
options.add_argument("--proxy-server=http://45.61.10.20:8080")

driver = webdriver.Chrome(options=options)
driver.get("https://httpbin.org/ip")
print(driver.page_source)   # should show the proxy's IP, not yours
driver.quit()

One limit trips everyone. The --proxy-server flag takes host and port only. Embed user:pass@ in it and Chrome discards the credentials and throws up a proxy authentication dialog that a headless script cannot click, so the request hangs. Free list entries are usually open, so the flag is enough for them, but a paid gateway with a username and password needs a different tool.

Authenticated proxies need Selenium Wire

For any proxy that requires a login, the common answer is Selenium Wire, a drop-in extension of Selenium that also lets you set the proxy (with credentials) through a config dict and inspect requests:

from seleniumwire import webdriver   # pip install selenium-wire

seleniumwire_options = {
    "proxy": {
        "http": "http://user:pass@gateway.hproxy.com:PORT",
        "https": "http://user:pass@gateway.hproxy.com:PORT",
        "no_proxy": "localhost,127.0.0.1",
    }
}
driver = webdriver.Chrome(seleniumwire_options=seleniumwire_options)
driver.get("https://httpbin.org/ip")

Selenium Wire handles the Proxy-Authorization the flag cannot, which is why it, or a small credentials extension you load into Chrome, is the standard route for a paid gateway. For a free open proxy you do not need it, and the guide how to use proxies in Selenium walks through both paths in more depth.

Firefox instead of Chrome

The same job in Firefox uses proxy preferences rather than a launch flag, which keeps the proxy inside the profile:

from selenium import webdriver
from selenium.webdriver.firefox.options import Options as FirefoxOptions

options = FirefoxOptions()
options.set_preference("network.proxy.type", 1)          # 1 = manual config
options.set_preference("network.proxy.http", "45.61.10.20")
options.set_preference("network.proxy.http_port", 8080)
options.set_preference("network.proxy.ssl", "45.61.10.20")
options.set_preference("network.proxy.ssl_port", 8080)

driver = webdriver.Firefox(options=options)
driver.get("https://httpbin.org/ip")

Firefox has the same authentication gap as Chrome's flag: these preferences take a host and port and no credentials, so an authenticated proxy still needs Selenium Wire. Note also that the old Proxy capability class is deprecated in Selenium 4, so set the proxy through browser options on either engine rather than the desired-capabilities pattern you will still find in older answers online.

Why a free pool is brutal for Selenium specifically

A crawler like Scrapy swaps meta["proxy"] per request for free, so rotating through a dead pool costs almost nothing. Selenium does not work that way. The proxy is bound when the browser launches, so changing the exit means tearing the browser down and building a new one.

Rotating a proxy in Selenium rebuilds the whole browser
  1. Free exit dies

    it expired minutes ago

  2. Page load times out

    no per-request rotation to fall back on

  3. Quit the driver

    the proxy was fixed at launch

  4. Launch a new browser

    slow and memory-heavy, per IP

Source: Why a churny free pool wrecks an unattended Selenium run

That is the whole problem in one picture. With a pool where only a few thousand of the hundreds of thousands we track are alive at any instant, a Selenium loop spends its time relaunching Chrome, and each relaunch is seconds and hundreds of megabytes of RAM. The mitigation is to fail fast and rebuild deliberately: set a page load timeout so a dead exit does not hang, and recreate the driver on the next entry.

from selenium.common.exceptions import TimeoutException, WebDriverException

def make_driver(proxy):
    options = Options()
    options.add_argument(f"--proxy-server=http://{proxy}")
    driver = webdriver.Chrome(options=options)
    driver.set_page_load_timeout(20)   # a dead proxy must not hang the run
    return driver

for proxy in pool:
    driver = make_driver(proxy)
    try:
        driver.get("https://example.com")
        break                          # this exit worked, carry on
    except (TimeoutException, WebDriverException):
        driver.quit()                  # tear it down and try the next IP
        continue

This survives a free pool for a test. It does not make one fast, because the cost is the browser rebuild, not the code.

There is a deeper reason this stings more in a browser than in a script. A headless Chrome is a full rendering engine, so every relaunch pays for a fresh process, a new profile directory, and the memory that comes with them. Doing that once per dead exit turns a churny free pool into a machine that spends more time starting browsers than loading pages. A crawler pays a few cents of overhead for the same churn, because it swaps a string and moves on. A browser pays seconds and hundreds of megabytes each time, which is why the free-pool tax that is merely annoying in Scrapy is close to disqualifying in Selenium.

Verify the exit, and check WebRTC

Never trust a session because the browser opened. The first thing to confirm is that the target sees the proxy and not you:

driver.get("https://httpbin.org/ip")
print(driver.page_source)   # the proxy's address, or the run is leaking

Do the same check outside the browser with our free proxy checker, which reports the real exit IP, country, latency, and anonymity grade so you can drop anything transparent, and how to check if a proxy is working covers the full method. One trap is specific to browsers: a proxy set on Chrome routes HTTP traffic, but plain Selenium does not mask WebRTC, so a page's JavaScript can read your real IP over a STUN request even with the proxy active. Selenium has no clean built-in fix for that, which is one of the reasons multi-account work moves to an antidetect browser (the free-versus-paid version of that story is in free proxies for Multilogin).

Never put a login behind a free proxy

The reachability check is the safe use of a free proxy. A login is not. When Selenium drives an authenticated flow, it sends cookies and often credentials, and a free proxy is run by a stranger sitting in the middle of that connection. Traffic to an HTTPS site stays encrypted across the hop, but plenty of free proxies are transparent, misconfigured, or hostile, and some tamper with anything that is not. Keep free proxies to logged-out page pulls and geo checks, and read are free proxies safe for the full trust picture before you automate anything that signs in. The moment a script has to log in and stay logged in, you have left the territory a free proxy belongs in.

When to switch to a gateway

Free proxies end where the unattended run begins. The fix for the browser-rebuild problem is a rotating residential gateway: one endpoint, with credentials handled by Selenium Wire, that rotates the exit server-side, so you launch the browser once and never tear it down to change IP. That removes the single most expensive part of running Selenium behind a pool.

Our residential proxies start at $0.44 per GB, pay as you go, with no KYC and a balance that does not expire, so a script you run in bursts never pays for idle IPs. If your target is better suited to a headless crawler than a full browser, the same free-versus-paid split is in free proxies for Scrapy.

Prove your automation against our free proxy list until the session visibly egresses from another IP, pull a test pool from the free proxy API, and vet any entry in the proxy checker first. When the run has to stand on its own, move it to residential at $0.44/GB behind a gateway, set your timeouts, and let one steady endpoint do the rotation the browser cannot.

Frequently asked questions

Do free proxies work with Selenium?
For a quick, attended session, yes. For an unattended run, no. Most free proxies are datacenter IPs that die within minutes and only a small fraction of any list works at once, and Selenium has no built-in per-request rotation, so a dead exit hangs the page load and rotating means tearing down and relaunching the whole browser. Use a free proxy to prove your automation routes traffic, then move to a paid gateway for the real job.
How do I set a proxy in Selenium with Chrome?
Add the proxy as a command-line argument on ChromeOptions: options.add_argument('--proxy-server=http://IP:PORT'), then create the driver with those options. This works for open proxies, which most free entries are. The important limit is that --proxy-server does not accept a username and password, so an authenticated proxy needs Selenium Wire or a credentials extension instead.
Why does --proxy-server ignore my proxy username and password?
Because Chrome's --proxy-server flag takes only host and port. If you embed user:pass@ in it, Chrome drops the credentials and pops up a proxy authentication dialog that a headless script cannot answer, so the request stalls. Free list entries are usually open, so the flag is fine for them. For a paid gateway that needs auth, use Selenium Wire's proxy dict, which handles the credentials for you.
How do I rotate proxies in Selenium?
There is no per-request rotation like a crawler has. Because --proxy-server is fixed when the browser launches, changing the exit means quitting the driver and starting a new browser with the next proxy. Wrap driver.get in a try/except on TimeoutException, set a page load timeout so a dead exit fails fast, and rebuild the driver on failure. A rotating gateway avoids the rebuilds by giving you one endpoint that rotates server-side.
Does Selenium leak my real IP through WebRTC?
It can. A proxy set on Chrome routes HTTP traffic, but plain Selenium does not mask WebRTC, so a page's JavaScript can read your real IP over a STUN request even while the proxy is active. Selenium has no clean built-in fix, which is one reason multi-account operators use an antidetect browser instead. Always verify the exit IP, and test WebRTC, before trusting a session.

Get proxies that are alive right now

Our free list re-checks every exit every few minutes and shows a last-checked time, so you copy IPs that worked moments ago, not a stale text dump. When the location has to survive a real check, the paid network holds up.

129M+ proxy checks run · 100+ countries · HTTP / HTTPS / SOCKS · re-checked every few minutes · no signup