Patchright Proxy Setup: Launch, Contexts, Auth and Docker
Patchright patches the CDP leaks that out Playwright before the browser starts. It does not touch your IP reputation — and its recommended stealth setup quietly changes how you rotate proxies.
Patchright is a patched, undetected build of Playwright that works as a drop-in replacement: change the import, keep the code. The patches land before the browser process starts — they remove the automation flags and the Chrome DevTools Protocol calls that let a site fingerprint a Playwright session in its first few milliseconds. What they do not touch is the network. Every Patchright proxy question comes back to that split, and to one detail the README buries: the setup the project recommends for maximum stealth is a persistent context, which quietly changes how you rotate exits. This is the proxy-focused guide — launch versus context, authenticated gateways, Docker, and an honest account of the ceiling.
Install and the drop-in proxy
Patchright ships for Python, Node and .NET, and only patches Chromium — Firefox and WebKit are explicitly unsupported. Install it and pull real Google Chrome rather than the bundled Chromium, which the project recommends for stealth:
pip install patchright
patchright install chrome
# Node: npm i patchright && npx patchright install chrome
The proxy API is Playwright's, unchanged, because proxies are one of the few things Patchright deliberately leaves alone. Credentials go in dedicated fields, never inside the server URL — which is why authenticated proxies need no extension shim here, unlike Selenium or raw Puppeteer:
from patchright.sync_api import sync_playwright
PROXY = {
"server": "http://gate.quantumproxies.io:PORT",
"username": "USER",
"password": "PASS",
}
with sync_playwright() as p:
browser = p.chromium.launch(channel="chrome", proxy=PROXY)
page = browser.new_page()
page.goto("https://httpbin.org/ip")
print(page.text_content("body")) # the exit IP
browser.close()
That is the whole "does Patchright support proxies" answer: yes, identically to upstream Playwright, including the bypass list and the Chromium quirk that loopback addresses skip the proxy entirely — so testing against a local mock server will always look like the proxy is being ignored. If you are new to the underlying model, our Playwright proxy integration guide covers the base behaviour, and the anti-detect framework proxy map compares which stacks accept credentials natively.
Per-context proxies and the global stub
Contexts are the cheap rotation unit: separate cookies, storage and cache, created in milliseconds instead of the seconds a browser launch costs. Each one takes its own proxy option, so a single process can hold a US identity and a German identity at the same time. There is one documented Playwright gotcha that trips people up here — the browser must be launched with a global proxy for per-context proxies to work on Chromium. If every context overrides it, the global value is never used and can be any placeholder string:
const { chromium } = require('patchright');
(async () => {
// the global proxy is never used — it only enables the per-context option
const browser = await chromium.launch({
channel: 'chrome',
proxy: { server: 'http://per-context' },
});
for (const job of jobs) {
const context = await browser.newContext({
proxy: {
server: 'http://gate.quantumproxies.io:PORT',
username: 'USER-country-' + job.country, // geo in the username
password: 'PASS',
},
});
const page = await context.newPage();
try {
await page.goto(job.url, { timeout: 30000 });
// ...extract...
} finally {
await context.close(); // burns the cookies with the exit
}
}
await browser.close();
})();
Pointed at a rotating gateway, each context leaves from a different address in a 90M+ residential pool with no list management on your side — that is what rotating proxies do server-side. Note where the geo and session controls live in that snippet: in the username, not in a custom header. That matters more in Patchright than in plain Playwright, because the project's own guidance is to avoid custom headers and user-agent overrides, since injected values are themselves a detection surface. Username-parameter control keeps the browser's request shape untouched.

The persistent-context trade-off
Patchright's recommended stealth configuration is not launch(). It is launch_persistent_context() with a real Chrome channel, a user data directory, no viewport override and headed mode — and explicitly without custom headers or a spoofed user agent. That setup also persists whatever clearance cookies a challenge hands you, so a solved challenge is reusable across runs. The proxy consequence is structural: a persistent context is the context. There is no newContext() to hang a second proxy on, so one process equals one exit identity.
from patchright.sync_api import sync_playwright
with sync_playwright() as p:
ctx = p.chromium.launch_persistent_context(
user_data_dir="profiles/it-01", # one profile per identity
channel="chrome",
headless=False,
no_viewport=True,
proxy={
"server": "http://gate.quantumproxies.io:PORT",
"username": "USER-country-it-session-it01", # sticky, pinned to the profile
"password": "PASS",
},
# do NOT pass user_agent or extra_http_headers here
)
page = ctx.new_page()
page.goto("https://example.com")
ctx.close()
So rotation becomes a process-level decision: one profile directory per identity, one sticky session pinned to it, and a worker pool instead of a context loop. Keep the pairing stable — a profile that accumulated cookies behind an Italian exit and then reappears behind a Brazilian one is a contradiction no CDP patch can hide. Practical rule: name the directory after the session id, delete the directory when you burn the session, and never share a profile across two exits.
Running Patchright in Docker behind a proxy
Containerising a stealth browser has two traps, and both have proxy consequences. The first is --no-sandbox: the usual fix for Chrome refusing to start as root, and a flag anti-bot vendors happily read. Run as a non-root user instead. The second is headless mode — the project recommends headed, so use a virtual display rather than reaching for the headless switch:
# Dockerfile
FROM python:3.12-slim
RUN apt-get update && apt-get install -y --no-install-recommends \
xvfb ca-certificates && rm -rf /var/lib/apt/lists/*
RUN pip install --no-cache-dir patchright \
&& patchright install --with-deps chrome
RUN useradd -m app
USER app
WORKDIR /home/app
COPY --chown=app:app scrape.py .
# headed under a virtual display: no --no-sandbox, no HeadlessChrome tell
CMD ["xvfb-run", "-a", "python", "scrape.py"]
# build & run:
# docker build -t patchright-worker .
# docker run --ipc=host --shm-size=1g patchright-worker
The --ipc=host and larger /dev/shm are the standard Chromium-in-Docker fixes for tab crashes under load, straight from the Playwright container docs. One proxy-specific trap: if you run a local relay to add credentials to a SOCKS5 endpoint, 127.0.0.1 inside the container is the container, not your host. Either put the relay in the same container, address the host explicitly, or run the relay as a sidecar on a shared network. And keep the profile directory on a volume if you are using persistent contexts, otherwise every container restart throws away the clearance cookies you paid bandwidth to earn.
What the patches cover, and what they never will
It is worth knowing exactly what you are buying. Patchright's headline fix is the Runtime.enable leak — it runs JavaScript in isolated execution contexts instead of enabling the domain that gives the game away. It disables the Console API to close Console.enable (so page.on("console") logging is gone, which is a real cost when you are debugging a proxy failure). It rewrites Playwright's default flags: adds --disable-blink-features=AutomationControlled, removes --enable-automation, and puts back --disable-popup-blocking, --disable-component-update, --disable-default-apps and --disable-extensions. It also reaches into closed shadow roots with ordinary locators.
Read that flag list as a bandwidth line item too. Restoring component updates and default apps means a browser that phones home in the background — through your metered exit. Measure a session's transfer before you scale, and block image, font and media resource types on the context to keep per-page cost down. None of it touches the other wall: a patched browser on a burnt datacentre IP is still a burnt IP, and the request is refused on reputation before any of this cleverness is evaluated. Check an address with the free IP quality checker before you conclude the patches failed, and put residential proxies under the browser so the two layers are solving different problems.

Frequently asked questions
How do I set a proxy in Patchright?
Exactly as in Playwright: pass proxy={"server": "http://host:port", "username": "USER", "password": "PASS"} to chromium.launch(), launch_persistent_context() or new_context(). Patchright does not patch the proxy layer, so every upstream behaviour — the bypass list, the loopback exception — applies unchanged.
Does Patchright support SOCKS5 proxy authentication?
No, and it is a Chromium limitation rather than a Patchright one: Chromium has no mechanism for SOCKS credentials, so authenticated SOCKS5 endpoints fail. Use the HTTP port of the same gateway with the username and password fields, or authenticate by IP whitelist and keep the SOCKS5 scheme — every QuantumProxies plan supports whitelisting as an alternative to user:pass. The full workaround set is in our Playwright SOCKS5 authentication guide, which applies unchanged here.
Can Patchright use a different proxy per context?
Yes, if you launched the browser with a global proxy value — even a placeholder — because Chromium only enables per-context proxies when one is present at launch. The exception is the persistent-context setup Patchright recommends for stealth: that gives you a single context, so rotation means a separate process with its own profile directory.
Is Patchright Chromium-only?
Yes. The project states plainly that only Chromium-based browsers are patched; Firefox and WebKit are unsupported. If you need Firefox-engine stealth with geo derived from the proxy exit, that is a different tool — see our Camoufox proxy and geoip guide.
Do I still get blocked with Patchright?
On hard targets, yes. Independent testing shows headless mode still leaking a HeadlessChrome tell, and challenge pages that a patched browser reaches but cannot clear. The patches close the cheap automation checks; IP reputation, TLS fingerprints and challenge solving are separate problems that need separate answers.
Treat Patchright as what it is: a very good fix for one specific class of leak, delivered without asking you to rewrite a line of Playwright. Pair it with exits that are clean, sticky where identity matters, and verified before the run — then the remaining failures are actually about the target, not about your setup. This is technical guidance, not legal advice: automate within the law and the site's terms.