Playwright
Use NyxonProxies with Playwright in Python and Node.js: proxy at launch, a proxy per browser context, sticky sessions, bypass lists, saving traffic and errors.
Playwright takes the proxy server, username and password as one option, at launch or per browser context. It handles the gateway's login itself, so no extension or handler is needed.
Install
pip install playwright
playwright install chromiumnpm install playwright
npx playwright install chromiumProxy at launch
from playwright.sync_api import sync_playwright
with sync_playwright() as p:
browser = p.chromium.launch(proxy={
"server": "http://geo.gw.nyxon.sh:8080",
"username": "USERNAME-country-us",
"password": "PASSWORD",
})
page = browser.new_page()
page.goto("https://api.ipify.org?format=json")
print(page.inner_text("body"))
browser.close()import { chromium } from "playwright";
const browser = await chromium.launch({
proxy: {
server: "http://geo.gw.nyxon.sh:8080",
username: "USERNAME-country-us",
password: "PASSWORD",
},
});
const page = await browser.newPage();
await page.goto("https://api.ipify.org?format=json");
console.log(await page.innerText("body"));
await browser.close();Keep the credentials in username and password. Written into the server URL, they are not sent.
One proxy per context
A browser context is an isolated session inside one browser, with its own cookies and storage. Give each context its own username with a session ID and each one keeps its own IP. This checks a page from three countries, with the locale and time zone matched to each exit:
import secrets
from playwright.sync_api import sync_playwright
MARKETS = {
"us": ("en-US", "America/New_York"),
"de": ("de-DE", "Europe/Berlin"),
"gb": ("en-GB", "Europe/London"),
}
with sync_playwright() as p:
browser = p.chromium.launch()
for country, (locale, tz) in MARKETS.items():
sid = secrets.token_hex(4)
context = browser.new_context(
proxy={
"server": "http://geo.gw.nyxon.sh:8080",
"username": f"USERNAME-country-{country}-session-{sid}-time-20",
"password": "PASSWORD",
},
locale=locale,
timezone_id=tz,
)
page = context.new_page()
page.goto("https://ipinfo.io/json")
print(country, page.inner_text("body"))
context.close()
browser.close()In Node.js the same object goes to browser.newContext({ proxy: { ... }, locale, timezoneId }). Pages in one context share its proxy. There is no per-page proxy.
Rotating or sticky
Loading one page opens several connections, often one per host. On a rotating username, those connections can leave from different IPs, so one page view can arrive from several addresses. For logins, carts and multi-step forms, use a session ID per context and a time longer than the task. To get a new IP, close the context and open a new one with a new session ID. See Rotating and sticky sessions.
Skip the proxy for some hosts
bypass takes a comma-separated list of hosts to reach directly:
browser = p.chromium.launch(proxy={
"server": "http://geo.gw.nyxon.sh:8080",
"username": "USERNAME",
"password": "PASSWORD",
"bypass": "localhost,127.0.0.1,.internal.example",
})A leading dot matches subdomains. List local addresses yourself if they should go direct: Playwright sends 127.0.0.1 through the proxy otherwise.
Save traffic: block heavy files
Images, fonts and video make up most of a page's weight. Abort them before they leave the browser and they never reach the proxy:
def block_heavy(route):
if route.request.resource_type in {"image", "media", "font"}:
return route.abort()
return route.continue_()
page.route("**/*", block_heavy)
page.goto("https://www.wikipedia.org/")Leave stylesheets alone if you take screenshots or depend on the layout.
SOCKS5
Chromium cannot log in to a SOCKS5 proxy. With a username and password on a socks5:// server, the launch fails with Browser does not support socks5 proxy authentication. Use the HTTP port: it carries HTTPS sites through an encrypted tunnel, so you lose nothing.
Errors
Chrome's codes appear in Playwright's errors with a net:: prefix:
| Error | Cause |
|---|---|
ERR_PROXY_CONNECTION_FAILED | Wrong host or port, or a firewall. |
ERR_INVALID_AUTH_CREDENTIALS | No credentials were sent, for example because they were written into server. |
ERR_HTTP_RESPONSE_CODE_FAILURE | Credentials were sent and refused, usually a wrong password. |
ERR_TUNNEL_CONNECTION_FAILED | The gateway answered the tunnel request with an error such as 502. |
Browser does not support socks5 proxy authentication | A SOCKS5 server with credentials. Use the HTTP port. |
TimeoutError on page.goto | The page took too long. Residential routes are slower than direct ones, so raise the limit, for example page.goto(url, timeout=60000). |
Last updated
Still stuck?
People answer the live chat around the clock. Send the proxy line you used (without the password) and the error you see.