Integration

Use Shifter with Selenium

Wire Shifter's residential and ISP proxies into Selenium WebDriver across Python, Java, JavaScript, C#, and Ruby. Works with Chrome, Firefox, and Edge — pair with selenium-wire for full username-password auth in headless mode.

Quick Start

Install

pip install selenium selenium-wire

Basic Usage

# selenium-wire is a drop-in replacement for selenium that adds first-class
# support for authenticated proxies in headless mode.
from seleniumwire import webdriver
from selenium.webdriver.chrome.options import Options

options = Options()
options.add_argument("--headless=new")

seleniumwire_options = {
    "proxy": {
        "http":  "customer-USERNAME-country-us-sid-123ABC:PASSWORD@p.shifter.io:443",
        "https": "customer-USERNAME-country-us-sid-123ABC:PASSWORD@p.shifter.io:443",
        "no_proxy": "localhost,127.0.0.1",
    }
}

driver = webdriver.Chrome(
    options=options,
    seleniumwire_options=seleniumwire_options,
)

driver.get("https://ipinfo.io/json")
print(driver.find_element("tag name", "body").text)
# {"ip": "154.16.xxx.xxx", "city": "New York", "country": "US", ...}

driver.quit()

Features

Drop-in support across Selenium clients in Python, Java, JavaScript, C#, and Ruby
Authenticated proxies in headless mode via selenium-wire (Python) or BrowserMob (Java)
Standard --proxy-server flag works with Chrome, Edge, and Firefox when paired with IP-whitelist auth
Geo-targeting in 195+ countries via username parameters — country, region, city, ASN
Per-request rotation by default, with `sid` for sticky sessions and `ttl-N` for timed pins of N seconds
Compatible with Selenium Grid, GitHub Actions runners, and any container-based scraping pipeline

Examples

Python + selenium-wire (Sticky Session)

selenium-wire forwards traffic through an in-process MITM, which means username-password proxies just work in headless Chrome. Add a `sid` for a sticky residential IP across the whole session.

from seleniumwire import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import secrets

sid = secrets.token_hex(4)

options = Options()
options.add_argument("--headless=new")
options.add_argument(
    "--user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
)

proxy_url = (
    f"customer-USERNAME-country-uk-city-london-sid-{sid}-ttl-300:"
    f"PASSWORD@p.shifter.io:443"
)

driver = webdriver.Chrome(
    options=options,
    seleniumwire_options={"proxy": {"http": proxy_url, "https": proxy_url}},
)

# Multi-step flow — same residential IP across every navigation.
driver.get("https://example.co.uk/login")
driver.find_element(By.ID, "email").send_keys("user@example.com")
driver.find_element(By.ID, "password").send_keys("secret")
driver.find_element(By.CSS_SELECTOR, "button[type=submit]").click()

WebDriverWait(driver, 10).until(EC.url_contains("/dashboard"))

rows = driver.find_elements(By.CSS_SELECTOR, ".order-row")
print(f"Found {len(rows)} orders on dashboard")

driver.quit()

Vanilla Selenium (no extras) — IP Whitelist

If you don't want selenium-wire as a dependency, use Shifter's IP whitelist authentication and configure the proxy via standard ChromeOptions. Cleaner deps but you must whitelist your scrape host.

from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.by import By

options = Options()
options.add_argument("--headless=new")
options.add_argument("--proxy-server=http://p.shifter.io:443")
options.add_argument(
    "--user-agent=Mozilla/5.0 (Macintosh) AppleWebKit/537.36"
)

# When using IP-whitelist auth, your scrape host's outbound IP is
# pre-authorized — no username/password needed in the URL.
driver = webdriver.Chrome(options=options)

driver.get("https://example.com")
print(driver.title)

products = driver.find_elements(By.CSS_SELECTOR, ".product")
for p in products[:5]:
    title = p.find_element(By.CSS_SELECTOR, "h2").text
    price = p.find_element(By.CSS_SELECTOR, ".price").text
    print(title, price)

driver.quit()

Java with selenium-wire-equivalent (BrowserMob)

Java doesn't have selenium-wire, but BrowserMob Proxy fills the same role — start a local proxy that adds Basic auth headers, then point Selenium at it.

import net.lightbody.bmp.BrowserMobProxy;
import net.lightbody.bmp.BrowserMobProxyServer;
import net.lightbody.bmp.client.ClientUtil;
import org.openqa.selenium.Proxy;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import java.net.InetSocketAddress;

public class SeleniumShifter {
  public static void main(String[] args) {
    BrowserMobProxy proxy = new BrowserMobProxyServer();
    proxy.setChainedProxy(new InetSocketAddress("p.shifter.io", 443));
    proxy.chainedProxyAuthorization(
        "customer-USERNAME-country-de-sid-456DEF", "PASSWORD",
        net.lightbody.bmp.proxy.auth.AuthType.BASIC);
    proxy.start(0);

    Proxy seleniumProxy = ClientUtil.createSeleniumProxy(proxy);
    ChromeOptions options = new ChromeOptions();
    options.setProxy(seleniumProxy);
    options.addArguments("--headless=new");

    WebDriver driver = new ChromeDriver(options);
    try {
      driver.get("https://example.de");
      System.out.println(driver.getTitle());
    } finally {
      driver.quit();
      proxy.stop();
    }
  }
}

Selenium Grid (parallel browsers)

When you scale to a Grid hub with multiple nodes, configure Shifter once at the Capabilities level — every node will route through Shifter without per-node config.

from selenium import webdriver
from selenium.webdriver.common.proxy import Proxy, ProxyType
from selenium.webdriver.chrome.options import Options

# Use selenium-wire-equivalent or Shifter IP whitelist for auth.
proxy_str = "p.shifter.io:443"

shared_proxy = Proxy()
shared_proxy.proxy_type = ProxyType.MANUAL
shared_proxy.http_proxy = proxy_str
shared_proxy.ssl_proxy  = proxy_str

options = Options()
options.proxy = shared_proxy
options.add_argument("--headless=new")

# Grid hub
HUB_URL = "http://selenium-hub.internal:4444/wd/hub"

driver = webdriver.Remote(command_executor=HUB_URL, options=options)

try:
    driver.get("https://example.com")
    print(driver.title, len(driver.page_source), "bytes")
finally:
    driver.quit()
FAQ

Frequently asked FAQ questions

Common questions about using Shifter with Selenium.

Use selenium-wire (Python) or BrowserMob Proxy (Java). Both run a local MITM proxy that injects Basic auth headers — Chrome and Firefox accept the inner proxy without prompting for credentials, even in headless mode. Alternatively, use Shifter's IP-whitelist auth and skip credentials entirely.

Get started

Start Using Shifter with Selenium

Drive Selenium WebDriver through Shifter's 205M+ residential and ISP proxies in Python, Java, and beyond. Native --proxy-server flag, selenium-wire for headless auth, and full Selenium Grid support.

Try Shifter for FreeSet up in minutes. Cancel anytime.