Compare / browsers
Camoufox vs Patchright
Two stealth browsers, two philosophies: a Firefox that spoofs the whole device at the C++ level, or a Chromium that patches the automation leaks and otherwise tells the truth. What each is like to drive, and what a site sees.
Camoufox is a Firefox build (152 on the fleet) that generates a complete device identity at launch — operating system, screen, GPU, cores, fonts, locale, timezone, geolocation — and answers every JavaScript and HTTP question from that identity, inside the engine rather than through injected scripts. Patchright is Playwright's own Chromium (148) with the things that give automation away removed: no Runtime.enable leak, no --enable-automation, console API disabled, closed shadow roots reachable. It doesn't pretend to be another machine. Both run headful by default on the fleet (2 threads) and both were launched through the same proxy for this page.
As a developer: driving them
| Camoufox | Patchright | |
|---|---|---|
| Engine, Playwright client | Gecko (Firefox 152). Connect with firefox. | Blink/V8 (Chromium 148). Connect with chromium. |
| Launch options | The richest set on the fleet: os, locale, geoip, humanize, screen, window, fonts, webgl_config, a full BrowserForge fingerprint, block_images/block_webrtc/block_webgl, pinned version, main_world_eval. | The common set only: proxy, proxy_rules, headless, timeouts. Identity is whatever the Linux server is. |
Where page.evaluate runs | In an isolated world. Globals you set there are invisible to the page, and vice versa; for fingerprint checks use main_world_eval: true and prefix the expression with mw: (measured: works). | In the page's own world — a <script> on the page sees what you set (measured). Patchright reaches it without Runtime.enable. |
addInitScript | Runs in the isolated world: the page's scripts don't see its globals (measured). | Works as in Playwright, implemented through routes; the README warns this can interfere with other route handlers. |
| Console events | Work. | Don't fire (measured): Patchright disables the Console API to close the Console.enable leak. Log from the page to the DOM or to your own endpoint instead. |
| PDF, mobile emulation | No PDF (page.pdf is Chromium-only). No device emulation: isMobile is not supported in Firefox. | Both work (measured; PDF also worked in this headful run). |
| Request interception, screenshots, tracing | Work. | Work. |
| Headless modes | false (virtual display, default), true. | false (default), "new", "shell". |
As a scraper: what the site sees
| Camoufox | Patchright | |
|---|---|---|
| TLS and HTTP/2 | Real Firefox: JA4 t13d1617h2_…, Firefox's HTTP/2 SETTINGS and header order (user-agent before accept). Identical on every OS Firefox runs on, so it matches whatever OS the persona claims. | Real Chromium: JA4 t13d1516h2_…, Chromium's HTTP/2 SETTINGS and pseudo-header order, sec-ch-ua client hints. Matches the Chrome user agent it sends. |
| Who it says it is | Firefox on a desktop OS picked per session (Windows, macOS or Linux; pin it with os), with a matching screen, GPU string ("… or similar"), core count and fonts — different each launch unless you pass a fingerprint. | Chrome 148 on Linux x86_64, brand Chromium (not Google Chrome) in the client hints, 1280×720 screen, the server's 64 cores and 32 GB. Honest, and visibly a Linux server. |
| Locale and time | geoip (default on) reads the proxy's exit and sets the timezone, locale and geolocation to match — measured: our rotating residential proxy exited in Spain in one run and Brazil in another, and the browser followed (Europe/Madrid/es, then America/Sao_Paulo/pt) without any code. | UTC and en-US whatever the proxy says. Set timezoneId, locale and geolocation in newContext yourself, or the IP-vs-clock mismatch is the first thing a risk engine sees. |
| Headless tells | None in headful: no Headless UA, 5 plugins, consistent notification permission, navigator.webdriver false. | None in headful: same list, webdriver false, window.chrome present. |
| WebGL | A consumer GPU from the persona ("Apple M1, or similar", "NVIDIA GeForce GTX 980 …"). | No WebGL context in headful mode on the fleet today (measured; headless has SwiftShader), so bot.sannysoft.com marks "WebGL Vendor" and "WebGL Renderer" red. Cause: Patchright's launcher adds Chromium's --enable-unsafe-swiftshader (software WebGL without a GPU) only on macOS, where Playwright adds it everywhere. A fleet-side fix is in progress; this page will be re-measured. |
| bot.sannysoft.com | 1 of 57 checks red: "Chrome (New)" — it is not Chrome, and says so. | 2 of 57 red: the two WebGL checks above. Everything else green. |
| The limit | Cannot pass "is this really Chromium" checks: V8-specific behaviour is impossible to fake from Gecko, and the Camoufox authors say so. Some sites block or degrade Firefox outright. | Cannot pretend to be a Windows or Mac desktop without you faking it, and anything you fake in JavaScript is a Chromium build that can be inspected. The leaks it closes are the automation ones. |
Which to pick
- Camoufox when the site must see a consistent consumer device and you don't want to build that identity yourself: geo personas (three countries, one script), account work, anything where IP, timezone, language and screen must agree. Accept Firefox rendering and the isolated-world rule.
- Patchright when the site needs Chromium — Chromium-only APIs, client hints, V8 quirks — or your tooling does (PDFs, device emulation, console-free is fine). Plan on setting timezone, locale and viewport per context, and on headless mode if WebGL matters until the headful gap is closed.
- Neither replaces real Chrome: for sites that check the
Google Chromebrand or exact Chrome behaviour, launch Chrome itself — headless tells shows what headful real Chrome still gives away (the GPU), and stealth builds compares all four patched builds.
Measured on the fleet (2026-10-04)
One launch of each with the defaults above, through the same proxy, on the production fleet. Camoufox's persona is regenerated every launch, so its OS, screen, GPU, cores and locale differ between runs; Patchright's values are the server's.
Launch and cost
Single run; timings depend on the proxy and on fleet load.
| Camoufox | Patchright | |
|---|---|---|
| Launch body | {"headless":false,"main_world_eval":true} | {"headless":false} |
| Threads used | 2 (linux_headful) | 2 (linux_headful) |
| Browser version | 152.0.4-beta.30 | 148.0.7778.96 |
| Launch request → browser ready | 3.0 s | 0.7 s |
| Playwright connect | 0.0 s | 0.1 s |
| Load example.com | 7.2 s | 3.6 s |
| Load tls.peet.ws/api/all | 2.9 s | 1.4 s |
What the network sees
From tls.peet.ws/api/all, requested by the browser itself. JA3 hashes change between runs of the same build (GREASE), so compare JA4 and the HTTP/2 fingerprint.
| Camoufox | Patchright | |
|---|---|---|
| HTTP version | h2 | h2 |
| JA4 | t13d1617h2_86a278354501_3cbfd9057e0d | t13d1516h2_8daaf6152771_d8a2da3f94cd |
| Peetprint hash | fd4547eeb41f073156b7bc8125a79a3c | 1d4ffe9b0e34acac0bd883fa7f79d7b5 |
| Akamai HTTP/2 fingerprint | 1:65536;2:0;4:131072;5:16384|12517377|0|m,p,a,s | 1:65536;2:0;4:6291456;6:262144|15663105|0|m,a,s,p |
| Cipher suites / extensions | 16 / 17 | 16 / 18 |
| Header order (first 12) | method, path, authority, scheme, user-agent, accept, accept-language, accept-encoding, upgrade-insecure-requests, sec-fetch-dest, sec-fetch-mode, sec-fetch-site | method, authority, scheme, path, sec-ch-ua, sec-ch-ua-mobile, sec-ch-ua-platform, upgrade-insecure-requests, user-agent, accept, sec-fetch-site, sec-fetch-mode |
What page scripts see
Read with page.evaluate on example.com. Cores and memory are the server's and vary between fleet nodes.
| Camoufox | Patchright | |
|---|---|---|
| navigator.userAgent | Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:152.0) Gecko/20100101 Firefox/152.0 | Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.0.0 Safari/537.36 |
| UA-CH brands | — | Not/A)Brand 99 · Chromium 148 |
| UA-CH full version list | — | Not/A)Brand 99.0.0.0 · Chromium 148.0.7778.96 |
| navigator.platform / vendor | MacIntel / "" | Linux x86_64 / Google Inc. |
| Languages | pt-BR, pt | en-US |
| Timezone / locale | America/Sao_Paulo / pt | UTC / en-US |
| Screen (w×h×availW×availH×depth) | 1440x900x1440x900x30 | 1280x720x1280x720x24 |
| Window outer / inner / DPR | 1440x900 / 1280x720 / 1 | 1288x805 / 1280x720 / 1 |
| hardwareConcurrency / deviceMemory | 2 / — | 36 / 32 |
| WebGL vendor | Apple | — |
| WebGL renderer | Apple M1, or similar | — |
| WebGL version | WebGL 2.0 | — |
| WebGPU (navigator.gpu) | no | yes |
| Canvas hash | c6b0b0da | f5a94624 |
| navigator.webdriver | no | no |
| window.chrome / navigator.connection | no / no | yes / yes |
| Plugins / PDF viewer | 5 / yes | 5 / yes |
| Notification.permission / permissions.query | default / prompt | default / prompt |
Web platform features
Presence probes; a user agent that claims one version while exposing another's features is a detectable inconsistency.
| Camoufox | Patchright | |
|---|---|---|
Iterator.prototype.includes (new in Chrome 154) | no | no |
FontFace.width (new in Chrome 154) | no | no |
CSS text-decoration-inset (new in Chrome 154) | yes | no |
Iterator.prototype.join (Chrome 153) | no | no |
Iterator.zip (Chrome 153) | yes | no |
CSS scroll-axis-lock (Chrome 153) | no | no |
<camera> element (Chrome 153) | no | no |
document.requestStorageAccessFor (deprecated in 153) | no | yes |
Topics API (document.browsingTopics) | no | yes |
Protected Audience (navigator.joinAdInterestGroup) | no | yes |
Shared Storage (window.sharedStorage) | no | yes |
Attribution Reporting (window.attributionReporting) | no | no |
| Private Aggregation | no | no |
WebHID (navigator.hid) | no | yes |
bot.sannysoft.com
The classic headless-detection test page; what it marks red.
| Camoufox | Patchright | |
|---|---|---|
| Checks / failed | 57 / 1 | 57 / 2 |
| Failed checks | Chrome (New) | WebGL Vendor, WebGL Renderer |
A plain-HTTP URL (http://ip-api.com/json)
Chrome 154 warns before loading insecure HTTP by default — does that reach an automated session?
| Camoufox | Patchright | |
|---|---|---|
| Final URL | http://ip-api.com/json/?fields=status | http://ip-api.com/json/?fields=status |
| HTTP status | 200 | 200 |
| Content loaded / warning page first | yes / no | yes / no |
Playwright over the remote connection
Which client features work on this side.
| Camoufox | Patchright | |
|---|---|---|
| page.evaluate runs in the page's own world | no | yes |
main_world_eval option (mw: prefix) | yes | — |
| addInitScript visible to page scripts | no | yes |
| Console events | yes | no |
| Request interception (page.route) | yes | yes |
| Screenshot | yes | yes |
| no — Error: page.pdf: PDF generation is only supported for Headless Chromium | yes | |
| Mobile device emulation | no — Error: browser.newContext: options.isMobile is not supported in Firefox | yes |
| Tracing | yes | yes |
Rows where the two sides differ are highlighted. IP addresses are replaced with placeholders (203.0.113.x). The probe is compare/probe.mjs in our repository; the raw result is below.
Raw output
{
"ran_at": "2026-10-04T21:09:08.778Z",
"sides": [
{
"label": "Camoufox",
"engine": "camoufox",
"body": {
"headless": false,
"main_world_eval": true
},
"launch": {
"browser": "camoufox",
"resource_class": "linux_headful",
"weight": 2,
"launch_ms": 3015,
"connect_ms": 32,
"example_ms": 7174,
"peet_ms": 2899
},
"network": {
"http_version": "h2",
"ja4": "t13d1617h2_86a278354501_3cbfd9057e0d",
"ja3_hash": "6447ab086255d194909d4013b1a89e87",
"peetprint_hash": "fd4547eeb41f073156b7bc8125a79a3c",
"ciphers": 16,
"extensions": 17,
"akamai_h2": "1:65536;2:0;4:131072;5:16384|12517377|0|m,p,a,s",
"akamai_h2_hash": "6ea73faa8fc5aac76bded7bd238f6433",
"header_order": [
"method",
"path",
"authority",
"scheme",
"user-agent",
"accept",
"accept-language",
"accept-encoding",
"upgrade-insecure-requests",
"sec-fetch-dest",
"sec-fetch-mode",
"sec-fetch-site"
]
},
"page": {
"user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:152.0) Gecko/20100101 Firefox/152.0",
"platform": "MacIntel",
"vendor": "",
"languages": [
"pt-BR",
"pt"
],
"hardware_concurrency": 2,
"device_memory": null,
"max_touch_points": 0,
"webdriver": false,
"plugins": 5,
"pdf_viewer": true,
"ua_data": null,
"screen": "1440x900x1440x900x30",
"window": {
"outer": "1440x900",
"inner": "1280x720",
"dpr": 1
},
"timezone": "America/Sao_Paulo",
"locale": "pt",
"webgl": {
"vendor": "Apple",
"renderer": "Apple M1, or similar",
"version": "WebGL 2.0"
},
"canvas_hash": "c6b0b0da",
"webgpu": false,
"chrome_object": false,
"chrome_runtime": false,
"notification_permission": "default",
"notification_query": "prompt",
"has_focus": true,
"connection_api": false,
"stack_read_by_debugger": false,
"features": {
"iterator_includes": false,
"iterator_join": false,
"iterator_zip": true,
"fontface_width": false,
"css_text_decoration_inset": true,
"css_scroll_axis_lock": false,
"websocket_options_bag": null,
"camera_element": false,
"topics_api": false,
"protected_audience": false,
"shared_storage": false,
"attribution_reporting": false,
"request_storage_access_for": false,
"webhid": false,
"private_aggregation": false
}
},
"page_main_world": {
"user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:152.0) Gecko/20100101 Firefox/152.0",
"platform": "MacIntel",
"vendor": "",
"languages": [
"pt-BR",
"pt"
],
"hardware_concurrency": 2,
"device_memory": null,
"max_touch_points": 0,
"webdriver": false,
"plugins": 5,
"pdf_viewer": true,
"ua_data": null,
"screen": "1440x900x1440x900x30",
"window": {
"outer": "1440x900",
"inner": "1280x720",
"dpr": 1
},
"timezone": "America/Sao_Paulo",
"locale": "pt",
"webgl": {
"vendor": "Apple",
"renderer": "Apple M1, or similar",
"version": "WebGL 2.0"
},
"canvas_hash": "c6b0b0da",
"webgpu": false,
"chrome_object": false,
"chrome_runtime": false,
"notification_permission": "default",
"notification_query": "prompt",
"has_focus": true,
"connection_api": false,
"stack_read_by_debugger": false,
"features": {
"iterator_includes": false,
"iterator_join": false,
"iterator_zip": true,
"fontface_width": false,
"css_text_decoration_inset": true,
"css_scroll_axis_lock": false,
"websocket_options_bag": null,
"camera_element": false,
"topics_api": false,
"protected_audience": false,
"shared_storage": false,
"attribution_reporting": false,
"request_storage_access_for": false,
"webhid": false,
"private_aggregation": false
}
},
"sannysoft": {
"checks": 57,
"failed": 1,
"failed_names": [
"Chrome (New)"
],
"passed": 30
},
"plain_http": {
"final_url": "http://ip-api.com/json/?fields=status",
"status": 200,
"title": "",
"loaded": true,
"warning_page": false,
"page_text": "{\"status\":\"success\"}"
},
"playwright": {
"evaluate_in_main_world": false,
"console_events": true,
"init_script": false,
"route": true,
"screenshot": true,
"pdf": false,
"pdf_error": "Error: page.pdf: PDF generation is only supported for Headless Chromium",
"mobile_emulation": false,
"mobile_emulation_error": "Error: browser.newContext: options.isMobile is not supported in Firefox",
"tracing": true,
"main_world_eval_option": true
},
"browser_version": "152.0.4-beta.30"
},
{
"label": "Patchright",
"engine": "patchright",
"body": {
"headless": false
},
"launch": {
"browser": "patchright",
"resource_class": "linux_headful",
"weight": 2,
"launch_ms": 668,
"connect_ms": 136,
"example_ms": 3555,
"peet_ms": 1369
},
"network": {
"http_version": "h2",
"ja4": "t13d1516h2_8daaf6152771_d8a2da3f94cd",
"ja3_hash": "4501f4f24ffd84ab8f9cd850eace9a3a",
"peetprint_hash": "1d4ffe9b0e34acac0bd883fa7f79d7b5",
"ciphers": 16,
"extensions": 18,
"akamai_h2": "1:65536;2:0;4:6291456;6:262144|15663105|0|m,a,s,p",
"akamai_h2_hash": "52d84b11737d980aef856699f885ca86",
"header_order": [
"method",
"authority",
"scheme",
"path",
"sec-ch-ua",
"sec-ch-ua-mobile",
"sec-ch-ua-platform",
"upgrade-insecure-requests",
"user-agent",
"accept",
"sec-fetch-site",
"sec-fetch-mode"
]
},
"page": {
"user_agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.0.0 Safari/537.36",
"platform": "Linux x86_64",
"vendor": "Google Inc.",
"languages": [
"en-US"
],
"hardware_concurrency": 36,
"device_memory": 32,
"max_touch_points": 0,
"webdriver": false,
"plugins": 5,
"pdf_viewer": true,
"ua_data": {
"brands": [
{
"brand": "Not/A)Brand",
"version": "99"
},
{
"brand": "Chromium",
"version": "148"
}
],
"mobile": false,
"platform": "Linux",
"architecture": "x86",
"bitness": "64",
"formFactors": [
"Desktop"
],
"fullVersionList": [
{
"brand": "Not/A)Brand",
"version": "99.0.0.0"
},
{
"brand": "Chromium",
"version": "148.0.7778.96"
}
],
"model": "",
"platformVersion": "",
"uaFullVersion": "148.0.7778.96",
"wow64": false
},
"screen": "1280x720x1280x720x24",
"window": {
"outer": "1288x805",
"inner": "1280x720",
"dpr": 1
},
"timezone": "UTC",
"locale": "en-US",
"webgl": {
"vendor": null,
"renderer": null,
"version": null
},
"canvas_hash": "f5a94624",
"webgpu": true,
"chrome_object": true,
"chrome_runtime": false,
"notification_permission": "default",
"notification_query": "prompt",
"has_focus": true,
"connection_api": true,
"stack_read_by_debugger": false,
"features": {
"iterator_includes": false,
"iterator_join": false,
"iterator_zip": false,
"fontface_width": false,
"css_text_decoration_inset": false,
"css_scroll_axis_lock": false,
"websocket_options_bag": null,
"camera_element": false,
"topics_api": true,
"protected_audience": true,
"shared_storage": true,
"attribution_reporting": false,
"request_storage_access_for": true,
"webhid": true,
"private_aggregation": false
}
},
"page_main_world": null,
"sannysoft": {
"checks": 57,
"failed": 2,
"failed_names": [
"WebGL Vendor",
"WebGL Renderer"
],
"passed": 29
},
"plain_http": {
"final_url": "http://ip-api.com/json/?fields=status",
"status": 200,
"title": "",
"loaded": true,
"warning_page": false,
"page_text": "{\"status\":\"success\"}"
},
"playwright": {
"evaluate_in_main_world": true,
"console_events": false,
"init_script": true,
"route": true,
"screenshot": true,
"pdf": true,
"mobile_emulation": true,
"tracing": true
},
"browser_version": "148.0.7778.96"
}
]
}Bottom line
The two aren't rivals so much as answers to different questions. Patchright asks "how do I stop Playwright from announcing itself?" and answers it well, leaving the machine's identity to you. Camoufox asks "what should the machine look like?" and answers that, at the price of being Firefox.
In practice: Chromium-shaped problems go to Patchright (with your own context settings), identity-shaped problems go to Camoufox, and when a site must see genuine Chrome, run genuine Chrome.