Mobile Proxy Setup in Playwright (Python and Node)
October 2026·7 min read·Playwright, Python, Node.js
Playwright has first-class proxy support, so a dedicated 4G/5G mobile proxy is a one-object change. The details that trip people up are which port to use, how authentication works, and how to tell that a page really loaded through the proxy. This guide covers all three, in Python and Node.
In the RelayKit dashboard, open a proxy card under My Proxies and click 🤖 Use with AI tools → Playwright. The snippets below appear with your host, port, username and password filled in, in both Python and Node, with a copy button. Here they're shown with placeholders:HOST, HTTP port 8000, SOCKS5 port 9000, USER, PASS.
2. Proxy for the whole browser
Pass proxy at launch and every page in that browser uses it.
Python
from playwright.sync_api import sync_playwright
# pip install playwright && playwright install chromium
with sync_playwright() as p:
browser = p.chromium.launch(
proxy={"server": "http://HOST:8000", "username": "USER", "password": "PASS"}
)
page = browser.new_page()
page.goto("https://api.ipify.org?format=json", timeout=45_000)
print(page.inner_text("body")) # must show the proxy's IP
browser.close()
If you run several proxies in one script (say, one per city you bought a proxy in), launch once and set the proxy on each BrowserContext. Chromium needs a launch-level proxy for per-context proxies to work; a placeholder is fine.
Python — one context per proxy
PROXIES = [
{"server": "http://HOST_A:8000", "username": "USER_A", "password": "PASS_A"},
{"server": "http://HOST_B:8000", "username": "USER_B", "password": "PASS_B"},
]
with sync_playwright() as p:
browser = p.chromium.launch(proxy={"server": "http://per-context"}) # placeholder, required by Chromium
for proxy in PROXIES:
ctx = browser.new_context(proxy=proxy)
page = ctx.new_page()
page.goto("https://api.ipify.org?format=json")
print(proxy["server"], "->", page.inner_text("body"))
ctx.close()
browser.close()
Multi Location note: with a RelayKit Multi Location proxy you usually don't need several proxies to cover several cities. One proxy moves between cities from the dashboard. Run your script, switch the city, run it again. See the multi-city research agent guide.
4. HTTP vs SOCKS5 in Chromium
RelayKit proxies answer on both an HTTP port (8000) and a SOCKS5 port (9000). Chromium cannot send a username and password to a SOCKS5 proxy, so in Playwright:
With a username and password: use http://HOST:8000. This is the normal setup.
With IP Whitelisting turned on for the proxy (on the card in the dashboard), there's no password, and socks5://HOST:9000 works too: proxy={"server": "socks5://HOST:9000"}.
The dashboard's snippet panel shows the SOCKS5 Playwright variant only when whitelisting is on, for this reason.
5. Verify every run
Make the IP check a function and call it before the real work. If the IP doesn't match the proxy card, stop.
Python
def assert_on_proxy(page, expected_ip: str):
page.goto("https://api.ipify.org?format=json", timeout=45_000)
seen = page.evaluate("() => JSON.parse(document.body.innerText).ip")
if seen != expected_ip:
raise RuntimeError(f"Not on the proxy: saw {seen}, expected {expected_ip}")
The expected IP is on the proxy card. If you use Reset IP or a rotation timer the IP changes, so for rotating setups compare the city instead, using a geolocation lookup such as https://ipapi.co/json/.
6. Timeouts and retries for a mobile link
Set navigation timeouts to 45–60 seconds. A real carrier connection has more latency than a datacenter link, and some pages are heavy.
Use wait_until="domcontentloaded" for pages with endless trackers, then wait for the one element you need.
Retry once on a timeout before failing a run. Mobile networks have occasional slow seconds.
Block images and fonts if you only need text; it makes a visible difference on a mobile link.
Python — block heavy assets
ctx = browser.new_context(proxy=proxy)
ctx.route("**/*", lambda route: route.abort()
if route.request.resource_type in {"image", "font", "media"} else route.continue_())
7. Example: regional price check
A common research task: record the prices a site shows to visitors from a given city. Run this, then switch the Multi Location proxy to another city in the dashboard and run it again.
price_check.py
import json, time
from playwright.sync_api import sync_playwright
PROXY = {"server": "http://HOST:8000", "username": "USER", "password": "PASS"}
TARGET = "https://example.com/pricing" # the page you're researching
PRICE_SELECTOR = ".price" # adjust to the site
with sync_playwright() as p:
browser = p.chromium.launch(proxy=PROXY)
page = browser.new_page()
page.goto("https://ipapi.co/json/", timeout=45_000)
where = json.loads(page.inner_text("body"))
page.goto(TARGET, timeout=60_000, wait_until="domcontentloaded")
page.wait_for_selector(PRICE_SELECTOR, timeout=30_000)
prices = [el.inner_text() for el in page.query_selector_all(PRICE_SELECTOR)]
print(json.dumps({"city": where.get("city"), "region": where.get("region"),
"ip": where.get("ip"), "prices": prices, "at": time.time()}))
browser.close()
Playwright on a dedicated US mobile IP
Real 4G/5G carrier IPs, unlimited data, HTTP and SOCKS5, and a Multi Location plan that switches cities from the dashboard. Pay with crypto; sign up with an email.