All guides
DEVELOPER GUIDES · 6 MIN READ

How to set up a proxy in Patchright Python

Install Patchright Chromium, configure proxy authentication, and check the exit IP. Diagnose launch, navigation, and init-script errors.

How to set up a proxy in Patchright Python

Configure the proxy in chromium.launch(proxy=...), then use a browser page to check both a permitted target and an IP endpoint. Patchright’s Python package patches Chromium-based browsers only; proxy routing does not guarantee that a target will accept a session.

Audience: Python developers familiar with asynchronous browser automation. This guide covers macOS/Linux shell commands.

Warning: Browser requests may consume paid traffic, and proxy credentials can grant account access. Start with a sandbox allocation and an authorized test target. Load credentials from a secret manager, keep them out of source and logs, and stop the worker if they appear in output.

With an http:// proxy, Basic proxy credentials cross the client-to-proxy hop without encryption. HTTPS on the target does not protect that hop. Use a trusted network or a supported TLS proxy endpoint.

Install Patchright and Chromium

This guide was checked with Python 3.12.0 from the official downloads page and Patchright 1.63.0. Create an isolated environment and install the pinned package and its Chromium build:

python3 -m venv .venv
.venv/bin/python -m pip install 'patchright==1.63.0'
.venv/bin/patchright install chromium

Set a credential-free proxy server URL and inject optional credentials through the worker’s secret environment. Use the scheme, host, and port supplied by the proxy operator. The example below uses an HTTP proxy endpoint.

export PROXY_SERVER='http://<PROXY_HOST>:<PROXY_PORT>'
export PROXY_USERNAME='<PROXY_USERNAME>'

Load PROXY_PASSWORD from the same secret manager before the run. When the endpoint does not require authentication, omit both credential variables. Save the program below as patchright-proxy-check.py; edit the target URL and marker for an authorized page.

import asyncio
import ipaddress
import json
import os
from urllib.parse import urlsplit

from patchright.async_api import async_playwright


TARGET_URL = "https://example.com/"
EXPECTED_MARKER = "Example Domain"
IP_CHECK_URL = "https://api.ipify.org?format=json"
NAVIGATION_TIMEOUT_MS = 15_000


async def main() -> None:
    proxy_server = os.environ["PROXY_SERVER"]
    endpoint = urlsplit(proxy_server)
    if (
        endpoint.scheme not in {"http", "https"}
        or not endpoint.hostname
        or not endpoint.port
        or endpoint.username is not None
        or endpoint.password is not None
        or endpoint.path not in {"", "/"}
        or endpoint.query
        or endpoint.fragment
    ):
        raise ValueError("PROXY_SERVER needs a credential-free HTTP(S) host and port")
    proxy = {"server": proxy_server}
    username = os.environ.get("PROXY_USERNAME")
    password = os.environ.get("PROXY_PASSWORD")
    if bool(username) != bool(password):
        raise ValueError("Set both proxy username and password, or neither")
    if username and password:
        proxy.update(username=username, password=password)

    async with async_playwright() as playwright:
        browser = await playwright.chromium.launch(proxy=proxy, headless=True)
        try:
            page = await browser.new_page()
            ip_response = await page.goto(
                IP_CHECK_URL,
                wait_until="domcontentloaded",
                timeout=NAVIGATION_TIMEOUT_MS,
            )
            if ip_response is None or ip_response.status != 200:
                status = ip_response.status if ip_response is not None else "no response"
                raise RuntimeError(f"IP check failed with HTTP {status}")
            ip_data = json.loads(await page.locator("body").inner_text(timeout=5_000))
            ip_value = ip_data.get("ip") if isinstance(ip_data, dict) else None
            if not isinstance(ip_value, str):
                raise ValueError("IP endpoint must return a JSON object with a string ip")
            exit_ip = ipaddress.ip_address(ip_value)

            target_response = await page.goto(
                TARGET_URL,
                wait_until="domcontentloaded",
                timeout=NAVIGATION_TIMEOUT_MS,
            )
            if target_response is None or target_response.status != 200:
                status = target_response.status if target_response is not None else "no response"
                raise RuntimeError(f"target check failed with HTTP {status}")
            if EXPECTED_MARKER not in await page.locator("body").inner_text(timeout=5_000):
                raise RuntimeError("target response did not contain the expected marker")

            print(f"Target accepted: HTTP {target_response.status}; marker found")
            print(f"Observed exit address: {exit_ip}")
        finally:
            await browser.close()


if __name__ == "__main__":
    try:
        asyncio.run(main())
    except Exception as error:
        print(f"Check failed ({type(error).__name__})")
        raise SystemExit(1) from None

Run it in the environment that contains the proxy settings:

.venv/bin/python patchright-proxy-check.py

The browser launch applies one proxy configuration to this browser. The script checks the IP service and target in sequence through the same browser, then validates the target status and marker. Browser navigation follows redirects and loads page resources, so these two navigations can create more than two network requests.

The IP response shows the address reported by that endpoint; it does not prove location, anonymity, or target acceptance.

Illustrative output; the address below is a documentation address, not a captured exit:

Target accepted: HTTP 200; marker found
Observed exit address: 203.0.113.10

Use a small authorized test page. This example does not cap page size or subresource traffic; a navigation timeout is not a provider traffic budget. The IP-check endpoint must return a JSON object with a string ip containing an IPv4 or IPv6 address.

Choose session scope

Workload Browser state Proxy behavior to verify
Independent QA cases A fresh browser context for each case Each case returns the expected status and marker
Multi-step page flow Reuse one context for the flow Cookies and page state survive the steps
Region-sensitive page check Use a provider session that preserves the selected route Page data and the observed exit address match the intended check
Separate regions in parallel Isolate contexts and configure each route separately Each context reports its own observed address

A browser context keeps cookies and related page state. Provider session affinity is separate; choose a sticky route when the workflow requires the same exit during multiple steps. Do not share a persistent profile between unrelated jobs.

Handle a known init-script issue

Patchright issue #112 reported authenticated-proxy navigation failures when Python code called add_init_script(). The report was fixed in Patchright pull request #115, merged on 2026-05-21. The fix is included before the tested 1.63.0 release. Recheck the installed version when using an older package or a fork; do not apply the old workaround to this baseline.

Troubleshoot the failed phase

Symptom Check
Browser executable is missing Install the Chromium build using the same environment’s patchright install chromium command
Proxy returns HTTP 407 Verify the server URL and both credential values with the proxy operator
Navigation timeout Check endpoint reachability, target response behavior, and the per-navigation timeout
HTTP 3xx, 401, 403, or 429 Inspect the final response, target policy, origin auth, and rate limit; do not retry authorization failures
HTTP 200 without the marker Inspect the received page safely; a challenge or empty page is not valid target data
Login state disappears Reuse the intended browser context and confirm provider session affinity

The top-level handler prints only the exception class; it avoids logging request URLs and credentials. Keep TLS validation enabled, use only targets permitted by their owners, and treat the status, marker, and observed IP as separate checks. Patchright’s Python API follows Playwright’s browser launch proxy options. See the Patchright Python package and Playwright browser launch reference for API details.

Sources and further reading

ProxyLaneTraffic never expires

Premium residential proxies
From $2/GB

Scale your workflows with the tools you already use. Rotating or sticky sessions up to 72 hours.

Try 350 MB for $1.95 View plans

Keep reading

Amazon Scraper API vs Proxy: Choose a Product Data Source

Compare seller APIs, licensed Amazon product data and proxy page checks by record, access scope and reuse rights.

Read guide

Antidetect browser proxy setup: choose a profile guide

Choose the right anti-detect browser proxy guide, map the shared verification steps, and keep account access separate from the network route.

Read guide

Best Proxies for Market Research: Choose by Sample and Cost

Our picks for market research: ProxyLane for small, intermittent projects, plus options for regional tracking, monthly collection and managed extraction.

Read guide