Integration · Playwright
Use RoProxy with Playwright
Playwright takes a proxy server, username and password at launch or per browser context, which maps neatly onto RoProxy sessions: every session has its own credentials. This guide covers both setups in Node.js and Python, explains why the HTTP port is the one to use with Chromium, runs several IPs in parallel with one session per context, and picks the session type that keeps a page load consistent.
Use the HTTP port
Chromium does not send a username and password to SOCKS5 proxies: it drops the credentials, the proxy refuses the connection, and the page fails or leaves without the proxy. RoProxy sessions always authenticate, so point Chromium at the session's HTTP port.
HTTPS sites work through that port: the browser opens a CONNECT tunnel and TLS stays between the browser and the site.
One proxy for the whole browser
import { chromium } from "playwright"
const browser = await chromium.launch({
proxy: {
server: "http://GATEWAY_HOST:HTTP_PORT",
username: "USERNAME",
password: "PASSWORD",
},
})
const page = await browser.newPage()
await page.goto("https://api.ipify.org?format=json")
console.log(await page.textContent("body"))
await browser.close()One session per context for parallel IPs
A browser context is an isolated profile with its own cookies. Give each context its own session and one browser runs several IPs side by side.
import { chromium } from "playwright"
// Each entry is one RoProxy session, copied from the dashboard.
const sessions = [
{ server: "http://GATEWAY_HOST:HTTP_PORT", username: "USERNAME_1", password: "PASSWORD_1" },
{ server: "http://GATEWAY_HOST:HTTP_PORT", username: "USERNAME_2", password: "PASSWORD_2" },
]
const browser = await chromium.launch()
await Promise.all(sessions.map(async (proxy) => {
const context = await browser.newContext({ proxy })
const page = await context.newPage()
await page.goto("https://api.ipify.org?format=json")
console.log(await page.textContent("body"))
await context.close()
}))
await browser.close()Choosing the session type for a browser
Sticky (bind)
The default choice for browsers: logins, carts and multi-step flows keep one IP and one cookie jar.
Timed rotation
Good for crawling many pages in a row, as long as no login spans the moment the IP changes.
Per request (Business)
A page loads dozens of resources and each could leave from a different IP, which some sites flag. Better for API-style fetches than for full page loads.
Common errors
net::ERR_TUNNEL_CONNECTION_FAILED
The gateway host or port is wrong, or the session has expired. Check the connection string in the dashboard.
407 or a proxy login prompt
The username or password is missing or wrong. Pass both in the proxy option, not in the server URL.
Slow page loads
Every resource goes through the proxy. Block images, fonts and media with page.route when you only need the HTML.
Frequently asked questions
Why does the SOCKS5 port not work in Chromium?
Chromium does not send a username and password to SOCKS5 proxies. Use the session's HTTP port; HTTPS sites still work through it.
Can each browser context use a different IP?
Yes. Pass each context its own session's credentials in newContext({ proxy }); every session has its own IP.
Should I use per-request rotation with a browser?
Usually not. A page load pulls many resources, and each could leave from a different IP. Sticky or timed sessions keep a page load consistent.
Can I change the IP without restarting the browser?
Yes. Call the rotate endpoint of the RoProxy API for that session; new connections then leave from the new IP, so open a fresh context to drop old ones.
Related pages
Node.js
Route fetch, axios and SOCKS5 traffic through a session and rotate the IP from code.
Selenium
Chrome takes no proxy password: run a local forwarder that adds the session's credentials and point Selenium at it.
Python
Connect requests and httpx over HTTP or SOCKS5 and rotate the IP from your script.