[Compare](https://cdpfleet.com/docs/compare) / browsers

# Firefox vs Camoufox

Playwright's Firefox build against the anti-detect fork built on it (both based on Firefox source; not affiliated with Mozilla): what Camoufox changes in what a site sees, what it costs you as a developer, and when plain Firefox is the better tool.

[Firefox](https://cdpfleet.com/docs/browsers/firefox) [Camoufox](https://cdpfleet.com/docs/browsers/camoufox)

[Firefox](https://cdpfleet.com/docs/browsers/firefox) on the fleet is Playwright's own build (150 today), based on Firefox source and not affiliated with Mozilla: the Gecko engine with the patches Playwright needs to drive it, nothing hidden, nothing spoofed. [Camoufox](https://cdpfleet.com/docs/browsers/camoufox) (152) is a fork of that same engine whose purpose is the opposite: to look like a particular real person's computer — operating system, screen, GPU, fonts, locale, timezone and location generated at launch and answered consistently from inside the engine. Same Playwright client (`firefox`), same rendering engine, same TLS stack; very different answers to "who are you?". Both were launched headful through the same proxy for this page.

## As a developer: driving them

|  | Firefox | Camoufox |
| --- | --- | --- |
| Build | Playwright's Firefox 150 (`firefox` endpoint, `headless: false` or `true`). | Camoufox 152 (`camoufox` endpoint; `headless: false` virtual display, or `true`); pinned `version: "150"` available. |
| Launch options | The common set: `proxy`, `proxy_rules`, `headless`, timeouts. | The common set plus the persona: `os`, `locale`, `geoip`, `humanize`, `screen`, `window`, `fonts`, `webgl_config`, `fingerprint`/`config`, `ff_version`, `block_images`/`block_webrtc`/`block_webgl`, `main_world_eval`. |
| Where `page.evaluate` runs | In the page's world (measured): a page `<script>` sees globals you set. | In an isolated world (measured): the page can't see your globals and your checks don't see the persona unless you set `main_world_eval: true` and prefix expressions with `mw:` (measured: works). |
| `addInitScript` | Visible to page scripts (measured). | Runs in the isolated world; page scripts don't see it (measured). Use `config` for identity values instead of init-script patches. |
| Console events, routing, screenshots, tracing | Work. | Work. |
| PDF, mobile emulation | Neither: `page.pdf` is Chromium-only and Firefox has no `isMobile`. | Neither, same engine. |
| Threads | 2 headful, 1 headless. | 2 headful (virtual display), 1 headless. |

## As a scraper: what the site sees

|  | Firefox | Camoufox |
| --- | --- | --- |
| TLS and HTTP/2 | Firefox's: JA4 `t13d1617h2_…`, Firefox HTTP/2 SETTINGS and header order. | **Identical** — same NSS stack, same JA4, same HTTP/2 fingerprint (measured). Whatever OS the persona claims, real Firefox sends exactly this on every OS, so it never contradicts the user agent. |
| `navigator.webdriver` | **`true`** (measured). Playwright's Firefox build announces automation; bot.sannysoft.com marks "WebDriver" red. | `false` (measured). |
| Who it says it is | Firefox 150 on Linux x86\_64, `navigator.languages` empty, 1280×720 screen, the server's 64 cores, `llvmpipe` (Mesa) software renderer, 0 plugins, no PDF viewer — a Linux server running an automated browser, in plain sight. | Firefox 152 on a generated desktop (macOS in this run: `MacIntel`, 1440×900×30-bit screen, "Apple M1, or similar" GPU, 2 cores, 5 plugins, PDF viewer) — a consumer machine, different each launch unless you pin `os`/`fingerprint`. |
| Locale and time | `UTC`, no languages. Set `locale` and `timezoneId` in `newContext` yourself. | `geoip` matched the proxy exit: this run's exit was in Morocco and the browser reported `Africa/Casablanca` and `tzm-MA` without any code (Spain and Brazil in other runs). |
| Canvas | Deterministic for the build. | Different hash from Firefox (measured) — the persona's fonts and rendering, consistent within a session. |
| bot.sannysoft.com | 4 of 57 checks red: WebDriver, "Chrome (New)", two plugin checks. | 1 red: "Chrome (New)" — it is Firefox and says so. (The page rendered fewer rows in Camoufox before our 4-second cut-off; see raw output.) |
| The limit | Honest Linux automation: fine for rendering tests, screenshots and sites that don't care; the `webdriver` flag alone fails most bot checks. | Cannot be Chromium: sites that require Chrome-only behaviour or the `Google Chrome` client-hint brand see Firefox. Firefox-blocking sites block it too. |

## Which to pick

-   **Firefox** when you want Mozilla's engine as-is — cross-engine rendering checks, Gecko-specific bugs, a second opinion next to Chromium — and nobody is scoring the visitor. It is the cheaper mental model: what you set is what the page sees.
-   **Camoufox** whenever the site scores visitors: `webdriver` off, a consumer-hardware story, locale and clock that match the proxy exit, and the whole persona generated for you. Budget for the isolated-world rule (`main_world_eval`) and for Firefox-only behaviour.
-   **Neither for Chromium-only sites** — use [Chrome](https://cdpfleet.com/docs/browsers/chrome) or [Patchright](https://cdpfleet.com/docs/browsers/patchright); see [Camoufox vs Patchright](https://cdpfleet.com/docs/compare/camoufox-vs-patchright) for that choice.

## Measured on the fleet (2026-10-05)

One headful launch of each through the same rotating residential proxy. Camoufox's persona (OS, screen, GPU, cores, locale, timezone) is regenerated every launch; Firefox's values are the server's. `navigator.languages` came back empty for Firefox over the Playwright connection.

### Launch and cost

Single run; timings depend on the proxy and on fleet load.

|  | Firefox | Camoufox |
| --- | --- | --- |
| Launch body | {"headless":false} | {"headless":false,"main\_world\_eval":true} |
| Threads used | 2 (linux\_headful) | 2 (linux\_headful) |
| Browser version | 150.0.2 | 152.0.4-beta.30 |
| Launch request → browser ready | 2.8 s | 5.8 s |
| Playwright connect | 1.4 s | 0.0 s |
| Load example.com | 0.9 s | 0.8 s |
| Load tls.peet.ws/api/all | 0.8 s | 4.7 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.

|  | Firefox | Camoufox |
| --- | --- | --- |
| HTTP version | h2 | h2 |
| JA4 | t13d1617h2\_86a278354501\_3cbfd9057e0d | t13d1617h2\_86a278354501\_3cbfd9057e0d |
| Peetprint hash | fd4547eeb41f073156b7bc8125a79a3c | fd4547eeb41f073156b7bc8125a79a3c |
| Akamai HTTP/2 fingerprint | 1:65536;2:0;4:131072;5:16384|12517377|0|m,p,a,s | 1:65536;2:0;4:131072;5:16384|12517377|0|m,p,a,s |
| Cipher suites / extensions | 16 / 17 | 16 / 17 |
| 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, path, authority, scheme, user-agent, accept, accept-language, accept-encoding, upgrade-insecure-requests, sec-fetch-dest, sec-fetch-mode, sec-fetch-site |

### What page scripts see

Read with page.evaluate on example.com. Cores and memory are the server's and vary between fleet nodes.

|  | Firefox | Camoufox |
| --- | --- | --- |
| navigator.userAgent | Mozilla/5.0 (X11; Linux x86\_64; rv:150.0) Gecko/20100101 Firefox/150.0 | Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:152.0) Gecko/20100101 Firefox/152.0 |
| navigator.platform / vendor | Linux x86\_64 / "" | MacIntel / "" |
| Languages | — | tzm-MA, tzm |
| Timezone / locale | UTC / en-GB | Africa/Casablanca / en-GB |
| Screen (w×h×availW×availH×depth) | 1280x720x1280x720x24 | 1440x900x1440x900x30 |
| Window outer / inner / DPR | 1280x720 / 1280x720 / 1 | 1440x900 / 1280x720 / 1 |
| hardwareConcurrency / deviceMemory | 64 / — | 2 / — |
| WebGL vendor | Mesa | Apple |
| WebGL renderer | llvmpipe, or similar | Apple M1, or similar |
| WebGL version | WebGL 2.0 | WebGL 2.0 |
| WebGPU (navigator.gpu) | no | no |
| Canvas hash | 71eb6917 | 384a49dd |
| navigator.webdriver | yes | no |
| window.chrome / navigator.connection | no / no | no / no |
| Plugins / PDF viewer | 0 / no | 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.

|  | Firefox | Camoufox |
| --- | --- | --- |
| `Iterator.prototype.includes` (new in Chrome 154) | no | no |
| `FontFace.width` (new in Chrome 154) | no | no |
| CSS `text-decoration-inset` (Chrome 157) | yes | yes |
| `Iterator.prototype.join` (Chrome 153) | no | no |
| `Iterator.zip` (Chrome 153) | yes | yes |
| CSS `scroll-axis-lock` (Chrome 153) | no | no |
| `<camera>` element (Chrome 153) | no | no |
| `document.requestStorageAccessFor` (deprecated in 153) | no | no |
| Topics API (`document.browsingTopics`) | no | no |
| Protected Audience (`navigator.joinAdInterestGroup`) | no | no |
| Shared Storage (`window.sharedStorage`) | no | no |
| Attribution Reporting (`window.attributionReporting`) | no | no |
| Private Aggregation | no | no |
| WebHID (`navigator.hid`) | no | no |
| CSS `margin-trim` (Chrome 155) | no | no |
| CSS `text-decoration-skip-spaces` (Chrome 155) | no | no |
| CSS `corner` shorthand (listed for Chrome 160) | no | no |
| CSS `symbols()` (Chrome 155) | yes | yes |
| `Element.streamAppendHTML` (Chrome 157) | no | no |
| `WebTransport.reliability` (on stable from Chrome 157; listed for 158) | yes | yes |
| `window.maximize()` — Additional Windowing Controls (Chrome 155) | no | no |
| Canvas `srgb-linear` colour space (on stable from Chrome 157) | no | no |
| Permission policy `media-playback-while-not-visible` (Chrome 155) | no | no |

### bot.sannysoft.com

The classic headless-detection test page; what it marks red.

|  | Firefox | Camoufox |
| --- | --- | --- |
| Checks / failed | 57 / 4 | 37 / 1 |
| Failed checks | WebDriver (New), Chrome (New), Plugins Length (Old), Plugins is of type PluginArray | Chrome (New) |

### A plain-HTTP URL (http://ip-api.com/json)

Chrome 154 warns before loading insecure HTTP by default — does that reach an automated session?

|  | Firefox | Camoufox |
| --- | --- | --- |
| 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.

|  | Firefox | Camoufox |
| --- | --- | --- |
| page.evaluate runs in the page's own world | yes | no |
| `main_world_eval` option (`mw:` prefix) | — | yes |
| addInitScript visible to page scripts | yes | no |
| Console events | yes | yes |
| Request interception (page.route) | yes | yes |
| Screenshot | yes | yes |
| PDF | no — Error: page.pdf: PDF generation is only supported for Headless Chromium | no — Error: page.pdf: PDF generation is only supported for Headless Chromium |
| Mobile device emulation | no — Error: browser.newContext: options.isMobile is not supported in Firefox | no — Error: browser.newContext: options.isMobile is not supported in Firefox |
| 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-05T21:03:08.264Z",
  "sides": [
    {
      "label": "Firefox",
      "engine": "firefox",
      "body": {
        "headless": false
      },
      "launch": {
        "browser": "firefox",
        "resource_class": "linux_headful",
        "weight": 2,
        "launch_ms": 2796,
        "connect_ms": 1403,
        "example_ms": 922,
        "peet_ms": 823
      },
      "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 (X11; Linux x86_64; rv:150.0) Gecko/20100101 Firefox/150.0",
        "platform": "Linux x86_64",
        "vendor": "",
        "languages": [
          "undefined"
        ],
        "hardware_concurrency": 64,
        "device_memory": null,
        "max_touch_points": 0,
        "webdriver": true,
        "plugins": 0,
        "pdf_viewer": false,
        "ua_data": null,
        "screen": "1280x720x1280x720x24",
        "window": {
          "outer": "1280x720",
          "inner": "1280x720",
          "dpr": 1
        },
        "timezone": "UTC",
        "locale": "en-GB",
        "webgl": {
          "vendor": "Mesa",
          "renderer": "llvmpipe, or similar",
          "version": "WebGL 2.0"
        },
        "canvas_hash": "71eb6917",
        "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,
          "css_margin_trim": false,
          "css_text_decoration_skip_spaces": false,
          "css_corner_shorthand": false,
          "css_symbols": true,
          "stream_append_html": false,
          "webtransport_reliability": true,
          "window_maximize": false,
          "media_display_state": true,
          "canvas_srgb_linear": false,
          "policy_media_playback_while_not_visible": false
        }
      },
      "page_main_world": null,
      "sannysoft": {
        "checks": 57,
        "failed": 4,
        "failed_names": [
          "WebDriver (New)",
          "Chrome (New)",
          "Plugins Length (Old)",
          "Plugins is of type PluginArray"
        ],
        "passed": 26
      },
      "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": true,
        "init_script": true,
        "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
      },
      "browser_version": "150.0.2"
    },
    {
      "label": "Camoufox",
      "engine": "camoufox",
      "body": {
        "headless": false,
        "main_world_eval": true
      },
      "launch": {
        "browser": "camoufox",
        "resource_class": "linux_headful",
        "weight": 2,
        "launch_ms": 5833,
        "connect_ms": 28,
        "example_ms": 758,
        "peet_ms": 4685
      },
      "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": [
          "tzm-MA",
          "tzm"
        ],
        "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": "Africa/Casablanca",
        "locale": "en-GB",
        "webgl": {
          "vendor": "Apple",
          "renderer": "Apple M1, or similar",
          "version": "WebGL 2.0"
        },
        "canvas_hash": "384a49dd",
        "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,
          "css_margin_trim": false,
          "css_text_decoration_skip_spaces": false,
          "css_corner_shorthand": false,
          "css_symbols": true,
          "stream_append_html": false,
          "webtransport_reliability": true,
          "window_maximize": false,
          "media_display_state": true,
          "canvas_srgb_linear": false,
          "policy_media_playback_while_not_visible": 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": [
          "tzm-MA",
          "tzm"
        ],
        "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": "Africa/Casablanca",
        "locale": "en-GB",
        "webgl": {
          "vendor": "Apple",
          "renderer": "Apple M1, or similar",
          "version": "WebGL 2.0"
        },
        "canvas_hash": "384a49dd",
        "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,
          "css_margin_trim": false,
          "css_text_decoration_skip_spaces": false,
          "css_corner_shorthand": false,
          "css_symbols": true,
          "stream_append_html": false,
          "webtransport_reliability": true,
          "window_maximize": false,
          "media_display_state": true,
          "canvas_srgb_linear": false,
          "policy_media_playback_while_not_visible": false
        }
      },
      "sannysoft": {
        "checks": 37,
        "failed": 1,
        "failed_names": [
          "Chrome (New)"
        ],
        "passed": 9
      },
      "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"
    }
  ]
}
```

## Bottom line

Camoufox is Firefox with one job added: to make every identity question agree with a believable machine and with the proxy. It keeps Firefox's network fingerprint — which is a feature, since Firefox's TLS is the same on every OS — and replaces everything above it.

If you were about to patch stock Firefox with `newContext` options and init scripts to hide `webdriver`, fix the GPU string and set a timezone, that work is what Camoufox already did, inside the engine where a page can't inspect it.

---
Source: https://cdpfleet.com/docs/compare/firefox-vs-camoufox · Markdown: https://cdpfleet.com/docs/compare/firefox-vs-camoufox.md · All docs for AI tools: https://cdpfleet.com/llms.txt
