Patchright Deep-Dive: Undetected Playwright with Residential Proxies

A technical deep-dive on Patchright, the undetected Playwright fork: CDP leak closure, TLS/JA3 fingerprint alignment, and how to pair it with ProxyHat residential proxies to pass Cloudflare Turnstile and DataDome.

Patchright Deep-Dive: Undetected Playwright with Residential Proxies
In this article

If you've ever built a Playwright scraper that works perfectly in local testing but gets a 403 the moment it hits a Cloudflare-protected page, you already know the problem. Playwright leaks automation signals through at least three independent channels: JavaScript properties, Chrome DevTools Protocol activity, and TLS fingerprint mismatches. Patchright is a drop-in Playwright fork that closes the first two channels — but the third, and the IP reputation layer beneath it, still requires residential proxies.

This Patchright Deep-Dive covers exactly what the fork patches, what it leaves untouched, and how to pair it with ProxyHat residential proxies so your automation passes Cloudflare Turnstile and DataDome cleanly. We'll examine concrete detection signals — from navigator.webdriver to CDP Runtime.enable leaks to JA3/JA4 fingerprint alignment — and walk through a working code example.

What Patchright Deep-Dive Means for Modern Automation

Patchright is a maintained fork of Playwright (Python and Node.js) that patches the browser automation layer to avoid detection by anti-bot systems. It is not a stealth plugin injected at runtime — it modifies the Playwright source itself, so the patches execute before any page script runs. This matters because runtime-injected stealth patches (like those in playwright-stealth) can be detected by checking whether properties have been overridden.

The core problem Patchright solves: standard Playwright leaves detectable traces in the browser it controls. Anti-bot vendors like Cloudflare, DataDome, and PerimeterX check for these traces as part of their bot scoring. If any signal fires, your request gets challenged or blocked — regardless of whether your IP is clean. Patchright closes the browser-layer leaks so that, when combined with a clean residential IP, the traffic looks like a real user on a real browser.

The Detection Signals Patchright Targets

The navigator.webdriver property is a W3C-standard flag that returns true when the browser is controlled by automation. Standard Playwright sets this to true. Anti-bot scripts check it as a first-pass filter — if navigator.webdriver === true, the request is almost always flagged.

Patchright patches this at the browser level so that navigator.webdriver returns false or undefined, matching the behavior of a manually launched Chrome instance. The patch is applied before any page context is created, so there's no window where the property is true and then flipped.

CDP Runtime Leaks

Playwright communicates with the browser via the Chrome DevTools Protocol (CDP). When Playwright connects, it enables several CDP domains by default — notably Runtime.enable. Anti-bot scripts can detect this by observing side effects: certain JavaScript APIs behave differently when the Runtime domain is active, and the timing of CDP round-trips creates detectable patterns.

Patchright avoids enabling Runtime.enable unless absolutely necessary, and it patches the methods that would normally trigger it. This closes a leak that most stealth plugins don't address — they focus on JavaScript properties but miss the CDP-level signals that more sophisticated anti-bot systems probe.

Command-Line Flag Tells

When Playwright launches Chromium, it passes several command-line flags that are detectable. The most well-known is --enable-automation, which sets the navigator.webdriver property and displays the "Chrome is being controlled by automated test software" banner. Other flags like --disable-blink-features=AutomationControlled are actually counter-signals — if a script detects that this flag is set, it knows automation was involved.

Patchright removes --enable-automation and related automation flags entirely. It also injects --disable-blink-features=AutomationControlled in a way that prevents the flag itself from being detected as an automation tell. The fork essentially makes the launched browser's command-line arguments indistinguishable from a user-started Chrome.

Real Chrome TLS/JA3 Stack with channel='chrome'

This is where Patchright separates itself from standard Playwright. By default, Playwright uses its bundled Chromium binary. Chromium's TLS ClientHello — the basis for JA3/JA4 fingerprinting — differs subtly from real Chrome's. The cipher suite order, extensions, and supported groups can differ, producing a JA3 hash that anti-bot systems associate with automation tooling.

Patchright supports channel='chrome', which launches the system-installed Google Chrome instead of the bundled Chromium. This gives you the exact TLS stack of a real Chrome installation — the same ClientHello, the same HTTP/2 SETTINGS frame, the same ALPN negotiation. When a Cloudflare edge node fingerprints your connection, it sees a genuine Chrome TLS fingerprint, not a Chromium one. In patchright cloudflare scenarios, this TLS alignment is often the difference between a clean 200 and an interactive challenge.

What Patchright Patches — and What It Doesn't

Patchright closes the browser automation layer comprehensively, but it deliberately does not touch certain fingerprint surfaces. Understanding the boundary is critical for choosing the right tool.

Canvas, WebGL, and Font Fingerprints

Canvas fingerprinting works by rendering text or shapes on a <canvas> element and hashing the pixel output. The result depends on GPU, driver, OS, and font rendering settings — it's unique to the machine. WebGL fingerprinting probes the GPU via the WebGL API, exposing vendor, renderer, and extension lists. Font enumeration checks which system fonts are available.

Patchright does not spoof canvas, WebGL, or font fingerprints. If you run Patchright on a headless Linux server with a virtual framebuffer, the canvas hash will be consistent with that environment — not with a desktop Chrome on Windows. Anti-bot systems that compare the claimed User-Agent against the canvas/WebGL fingerprint can detect this mismatch.

Behavioral Signals

Anti-bot systems increasingly analyze behavioral patterns: mouse movement entropy, click timing, scroll velocity, and typing cadence. A script that jumps directly to an element and clicks it in 0ms looks nothing like a human. Patchright does not add behavioral mimicry — you must implement human-like interaction patterns yourself.

How Camoufox and playwright-stealth Differ

Three tools, three approaches:

Feature Patchright Camoufox playwright-stealth
Browser engine Chromium / Chrome Firefox (custom build) Chromium (Playwright)
Patch level Playwright source C++ browser source Runtime JS injection
navigator.webdriver Patched Patched Patched (overridable)
CDP Runtime.enable leak Closed N/A (Firefox) Not addressed
Real Chrome TLS Yes (channel='chrome') No (Firefox TLS) No (Chromium TLS)
Canvas/WebGL spoofing No Yes (C++ level) Partial (JS level)
Font enumeration spoofing No Yes No
Drop-in Playwright replacement Yes No (separate API) Yes (plugin)

Camoufox takes a different approach: it's a custom Firefox build with patches at the C++ source level. It spoofs canvas, WebGL, and fonts natively, making it more comprehensive for fingerprint resistance. However, it uses Firefox's TLS stack, which has a different JA3/JA4 profile than Chrome. If your target site expects Chrome traffic, Camoufox's Firefox fingerprint could itself be a signal.

playwright-stealth applies JavaScript patches at runtime using addInitScript. It overrides navigator.webdriver, navigator.plugins, navigator.languages, and other properties. The problem: these overrides are detectable. A script can check if navigator.webdriver is a getter that returns false (patched) versus a native property. More sophisticated anti-bot systems probe for the override itself.

Patchright's source-level patches avoid this detection vector entirely — the properties are never set to true in the first place, so there's nothing to override.

Why IP Reputation Still Scores You After CDP Leaks Are Closed

Here's the scenario that catches teams off-guard: they switch from Playwright to Patchright, verify that navigator.webdriver returns false, confirm the TLS fingerprint matches Chrome, and still get blocked. The reason is IP reputation.

Anti-bot systems like Cloudflare Turnstile and DataDome don't rely on a single signal. They score requests across dozens of dimensions: TLS fingerprint, HTTP/2 settings, JavaScript challenges, behavioral analysis, and — critically — IP reputation. A datacenter IP from AWS, DigitalOcean, or Hetzner carries a fundamentally different risk profile than a residential IP from Comcast, AT&T, or Verizon.

Even with a perfect browser fingerprint, if your traffic comes from an ASN associated with cloud providers, the bot score rises. Cloudflare maintains lists of datacenter ASNs and applies stricter challenges to them. DataDome does the same. The IP layer is checked independently of the browser layer — closing CDP leaks doesn't help if your IP screams "server." This is why choosing the right patchright proxy configuration is as important as the browser patches themselves.

This is why residential proxies are not optional for serious automation against modern anti-bot systems. A residential exit IP from a real ISP tells the anti-bot system: "this is a consumer connection." Combined with a clean Chrome TLS fingerprint and no CDP leaks, the request looks like a real user browsing from home.

TLS/HTTP2 Fingerprint Alignment with Residential Exits

The alignment between your TLS fingerprint and your IP matters more than most engineers realize. Anti-bot systems cross-reference signals: if your User-Agent claims Chrome on Windows, your TLS ClientHello should match Chrome on Windows, your HTTP/2 SETTINGS frame should match Chrome's defaults, and your IP should be a residential IP consistent with a consumer browsing from a home connection.

When you use channel='chrome' with Patchright, the TLS ClientHello is genuine Chrome — typically offering 15+ cipher suites in Chrome's specific order, with the correct extensions including GREASE values, supported groups, and signature algorithms. The JA3 hash (a 32-character MD5 digest of the ClientHello) matches what Cloudflare's edge expects from a Chrome browser.

But if that Chrome TLS fingerprint arrives from a DigitalOcean IP, the mismatch is obvious: no consumer browses from a datacenter IP with a desktop Chrome fingerprint. The residential proxy makes the IP and fingerprint agree — a Chrome TLS handshake from a Comcast residential IP is exactly what a real user produces.

HTTP/2 adds another layer. Chrome sends specific SETTINGS parameters (HEADER_TABLE_SIZE, INITIAL_WINDOW_SIZE, etc.) that differ from Chromium's defaults. Patchright with channel='chrome' gets this right because it uses the real Chrome binary. But if you're routing through a proxy that modifies HTTP/2 frames — some datacenter proxies do — you can break the alignment. ProxyHat's residential proxies operate at the HTTP CONNECT level, passing TLS through without modification, so the ClientHello that reaches the target server is exactly what Chrome sent.

Worked Example: Patchright + ProxyHat Sticky Residential IP

Here's a complete, working example of Patchright with a persistent context routed through a ProxyHat residential proxy with a sticky US session. This setup gives you a real Chrome TLS fingerprint, no CDP leaks, and a residential IP that stays consistent across requests.

from patchright.sync_api import sync_playwright

# ProxyHat residential proxy with sticky US session
proxy = {
    "server": "http://gate.proxyhat.com:8080",
    "username": "user-country-US-session-abc123",
    "password": "YOUR_PROXYHAT_PASSWORD"
}

with sync_playwright() as p:
    # Launch real Chrome with persistent context
    browser = p.chromium.launch_persistent_context(
        user_data_dir="/tmp/patchright-profile",
        channel="chrome",          # Use real Chrome for authentic TLS/JA3
        headless=False,            # Some anti-bot systems detect headless
        proxy=proxy,
        no_viewport=True,          # Avoid viewport-based detection
        args=[
            "--disable-blink-features=AutomationControlled",
        ]
    )

    page = browser.new_page()

    # Navigate to a protected page
    response = page.goto("https://example.com/protected", wait_until="domcontentloaded")
    print(f"Status: {response.status}")

    # Verify webdriver is not exposed
    is_webdriver = page.evaluate("() => navigator.webdriver")
    print(f"navigator.webdriver: {is_webdriver}")  # Should print: False

    # Extract content
    title = page.title()
    print(f"Page title: {title}")

    browser.close()

Key points about this configuration:

  • channel="chrome" — Uses the system-installed Google Chrome, not bundled Chromium. This gives you the authentic Chrome TLS/JA3 fingerprint and HTTP/2 settings.
  • headless=False — Some anti-bot systems detect headless mode through rendering differences. Running headed (even on a virtual display) avoids this. If you need headless, use headless="new" which uses Chrome's new headless mode that's harder to detect.
  • Persistent context — Using launch_persistent_context with a user_data_dir preserves cookies and localStorage between runs, mimicking a real browser session that accumulates state.
  • Sticky session — The session-abc123 flag in the username keeps the same residential IP for the duration of your session. Without it, ProxyHat rotates IPs per request, which is useful for high-volume scraping but can break session-based flows.

For Node.js, the equivalent setup:

const { chromium } = require('patchright');

const proxy = {
  server: 'http://gate.proxyhat.com:8080',
  username: 'user-country-US-session-abc123',
  password: 'YOUR_PROXYHAT_PASSWORD'
};

(async () => {
  const browser = await chromium.launchPersistentContext('/tmp/patchright-profile', {
    channel: 'chrome',
    headless: false,
    proxy,
    noViewport: true,
  });

  const page = await browser.newPage();
  await page.goto('https://example.com/protected');
  
  const isWebdriver = await page.evaluate(() => navigator.webdriver);
  console.log('navigator.webdriver:', isWebdriver);
  
  await browser.close();
})();

For SOCKS5, swap the port to 1080:

proxy = {
    "server": "socks5://gate.proxyhat.com:1080",
    "username": "user-country-US-session-abc123",
    "password": "YOUR_PROXYHAT_PASSWORD"
}

You can also target specific cities for finer geo-control: user-country-US-city-newyork-session-abc123. See ProxyHat locations for available countries and cities.

Common Mistakes and Edge Cases

Using Bundled Chromium Instead of Real Chrome

If you forget channel="chrome", Patchright falls back to the bundled Chromium. The automation patches still work, but the TLS fingerprint is Chromium's, not Chrome's. Against systems that check JA3/JA4 against a database of known browser fingerprints, this mismatch can trigger a challenge. Always specify channel="chrome" unless you have a specific reason not to.

Rotating IPs Mid-Session

If you use a rotating proxy (no session flag) with a persistent browser context, the IP changes on every request while cookies and TLS session tickets stay the same. Anti-bot systems can detect this: the same browser session making requests from 50 different IPs in 10 minutes is a clear bot signal. Use sticky sessions (session-abc123) for session-based flows, and reserve rotating IPs for stateless per-request scraping. For high-volume web scraping, rotating IPs without a persistent context is the right pattern.

Ignoring Canvas/WebGL Mismatches

If you run Patchright on a Linux server with Xvfb, the canvas and WebGL fingerprints will reflect that environment. A site that cross-references your User-Agent (claiming Windows or macOS) against your canvas hash (reflecting Linux Mesa drivers) will flag the mismatch. Solutions:

  • Run Patchright on the OS that matches your claimed User-Agent.
  • Use Camoufox if you need canvas/WebGL spoofing.
  • Use a managed browser service that provides consistent fingerprints.

Headless Detection

Even with Patchright's patches, headless Chrome has subtle differences: missing GPU rendering, different screen dimensions, and absent media codecs. If headless mode is detected, the rest of your stealth setup is wasted. Use headless=False with a virtual display (Xvfb on Linux), or use Chrome's new headless mode (headless="new") which is closer to headed behavior.

Overlooking HTTP/2 Fingerprinting

Beyond TLS, HTTP/2 has its own fingerprint: the SETTINGS frame values, window size, header table size, and priority frames. Chrome sends specific values that differ from Chromium. Using channel="chrome" aligns this automatically, but if you're using a proxy that terminates and re-establishes HTTP/2, the fingerprint can change. ProxyHat's residential proxies use HTTP CONNECT tunneling, which passes the TLS and HTTP/2 streams through without modification.

Where This Is Appropriate — and Where It Isn't

Patchright with residential proxies is a powerful combination for legitimate automation. Appropriate use cases include:

  • Authorized security research — Testing your own applications or participating in authorized bug bounty programs where the scope explicitly permits automated testing.
  • Public data collection — Scraping publicly accessible pages that don't require login, respecting robots.txt and the site's terms of service.
  • Price monitoring — Tracking publicly listed prices on e-commerce sites for competitive analysis, at reasonable rates that don't overload the target.
  • SERP tracking — Monitoring search engine result positions for SEO purposes. See our SERP tracking use case for more detail.
  • QA and testing — Running automated tests against staging environments that use the same anti-bot protection as production.

What this is not appropriate for:

  • Circumventing authentication on login-walled services.
  • Fraudulent activities including credential stuffing, payment fraud, or account takeover.
  • Scraping at volumes that constitute a denial-of-service.
  • Violating robots.txt or explicit terms of service prohibitions.
  • Accessing or collecting personal data in violation of GDPR, CCPA, or other privacy regulations.

The combination of Patchright and residential proxies is a tool. Like any tool, its legitimacy depends on how it's used. For more on compliant scraping practices, see our web scraping use case guide.

Key Takeaways

  • Patchright closes browser-layer detection signals (navigator.webdriver, CDP Runtime.enable, automation flags) at the source level — not via runtime JS injection.
  • Using channel='chrome' gives you the real Chrome TLS/JA3/JA4 fingerprint, which is critical against systems that fingerprint the ClientHello.
  • Patchright does not spoof canvas, WebGL, fonts, or behavioral signals. If your environment doesn't match your claimed User-Agent, you can still be detected.
  • IP reputation is scored independently of browser fingerprinting. Datacenter IPs get challenged regardless of how clean your browser looks. Residential proxies are required.
  • TLS fingerprint + IP reputation must agree: Chrome TLS from a residential ISP IP is the combination that passes Cloudflare Turnstile and DataDome.
  • Use sticky sessions for session-based flows and rotating IPs for stateless per-request scraping. Check ProxyHat pricing for residential proxy plans.
  • This toolset is for legitimate automation — security research, public data collection, QA — never for fraud or ToS violations.

Ready to pair Patchright with clean residential IPs? Explore ProxyHat's proxy locations or check the ProxyHat documentation for full integration details.

Frequently asked questions

What is Patchright Deep-Dive?

Patchright Deep-Dive refers to the comprehensive technical analysis and implementation of Patchright, an undetected fork of Playwright that patches browser automation signals at the source level. It closes navigator.webdriver leaks, CDP Runtime.enable detection, and automation command-line flags, while using real Chrome for authentic TLS/JA3 fingerprints. Unlike runtime stealth plugins, Patchright modifies Playwright's source so patches execute before any page script runs, making the overrides themselves undetectable.

Why does Patchright Deep-Dive matter for proxy users?

Even with perfect browser fingerprinting, IP reputation is scored independently by anti-bot systems like Cloudflare Turnstile and DataDome. A datacenter IP from AWS or DigitalOcean triggers stricter challenges regardless of how clean the browser looks. Patchright Deep-Dive matters because it addresses both layers: closing browser-level detection signals and pairing them with residential proxy IPs that match the claimed browser environment, so the TLS fingerprint and IP reputation agree.

Which proxy type works best for Patchright Deep-Dive?

Residential proxies work best for Patchright Deep-Dive because they provide IPs from real ISPs that match consumer browsing patterns. When Chrome's TLS fingerprint arrives from a residential IP, the signals agree. Datacenter proxies fail because anti-bot systems maintain ASN lists for cloud providers and apply higher bot scores. Mobile proxies also work but are slower and more expensive. For most use cases, residential proxies with sticky sessions are the optimal choice.

How do you avoid blocks when implementing Patchright Deep-Dive?

Use channel='chrome' for authentic TLS/JA3 fingerprints, run headed mode or Chrome's new headless to avoid headless detection, use sticky residential proxy sessions so IP and cookies stay consistent, and implement human-like behavioral patterns since Patchright does not add behavioral mimicry. Avoid rotating IPs mid-session, ensure your canvas/WebGL fingerprint matches your claimed User-Agent OS, and respect rate limits to avoid triggering behavioral analysis thresholds.

Does Patchright bypass Cloudflare Turnstile?

Patchright alone does not bypass Cloudflare Turnstile. Turnstile scores requests across TLS fingerprint, IP reputation, JavaScript challenges, and behavioral signals. Patchright closes browser-layer leaks and provides authentic Chrome TLS, but residential proxies are required for clean IP reputation. The combination of Patchright with channel='chrome' and residential proxy IPs is what allows legitimate automation to pass Turnstile challenges — neither component alone is sufficient.

Test your proxies against real anti-bot defenses

Free proxy checker — latency, anonymity and block signals in one click.

Run a free check
← Back to Blog