Skip to content

Akamai-protected sites block Camoufox but not stock Firefox via Playwright #555

@el-analista

Description

@el-analista

Akamai-protected sites block Camoufox but not stock Firefox via Playwright

What happens:
Navigating to Akamai-protected sites (e.g. https://www.hilton.com) with Camoufox returns 403, while stock Firefox via the same Playwright protocol loads the page normally.

Expected behavior:
The page should load normally, as it does with stock Firefox via the same Playwright protocol.

Key finding — detection is NOT TLS/HTTP2:
Both stock Firefox and Camoufox produce identical TLS and HTTP/2 fingerprints:

Signal Stock Firefox (Playwright) Camoufox
JA3 6f7889b9fb1a62a9577e685c1fcfa919 6f7889b9fb1a62a9577e685c1fcfa919
JA4 t13d1717h2_5b57614c22b0_3cbfd9057e0d t13d1717h2_5b57614c22b0_3cbfd9057e0d
Akamai H2 6ea73faa8fc5aac76bded7bd238f6433 6ea73faa8fc5aac76bded7bd238f6433
HTTP headers Identical (except UA version) Identical (except UA version)

This means something in Camoufox's C++ patches is being detected at the JS/browser-behavior level.

Test matrix (same machine, same IP, headless):

Site Stock Firefox 146 (Playwright) Camoufox 135 Notes
hilton.com 200 + Akamai challenge (5/5) 403 flat reject (5/5) Akamai won't even serve the challenge
nike.com 200 OK 200 OK Less strict Akamai config
nordstrom.com 200 OK 200 OK
dell.com 200 OK 200 OK
lowes.com 200 OK 200 OK
airbnb.com 200 OK 200 OK
homedepot.com 403 Blocked 403 Blocked Blocks all headless

The hilton.com case is particularly telling: stock Firefox gets a 200 with a behavioral JS challenge (which a real browser can solve), while Camoufox gets a flat 403 rejection — Akamai flags it before any JS executes.

Additional finding — viewport/screen dimension mismatch:

Camoufox spoofs JS-reported dimensions but the actual Playwright viewport doesn't match:

Playwright viewport: {'width': 1280, 'height': 720}
JS window.innerWidth: 1920
JS screen.width: 1920 (or randomized value)

CSS media queries and page layout render at the real 1280px width (responsive/mobile layout), while JS APIs report 1920px (desktop). This mismatch is detectable by any script that compares CSS layout breakpoints against window.innerWidth. Setting page.set_viewport_size() to match doesn't fix the Akamai block, but it's an additional inconsistency worth noting.

Configurations tested (all still blocked on hilton.com):

  • exclude_addons=[DefaultAddons.UBO] — no effect
  • os='linux' — no effect
  • block_webrtc=True — no effect
  • block_webgl=True — no effect
  • headless='virtual' (Xvfb) — no effect
  • config={'disableTheming': False} — no effect
  • config={'memorysaver': False} — no effect
  • enable_cache=True — no effect
  • window=(1920, 1080) + page.set_viewport_size() — no effect
  • Manually setting consistent Linux navigator properties — no effect

No runtime configuration fixes the block. The detection appears to be in the compiled patches themselves.

Suspected patches:
Based on issue #450 (where no-css-animations.patch was identified as a detection vector for DataShield), one or more of these compiled patches may be detectable by Akamai:

  • no-css-animations.patch
  • canvas-spoofing.patch
  • font-list-spoofing.patch (letter spacing randomization)
  • navigator-spoofing.patch
  • Other debloat/theming patches that alter default Firefox behavior

Environment:

  • OS: Linux (Ubuntu, x86_64)
  • Camoufox: v135.0.1-beta.24 (latest)
  • Python camoufox package: latest from PyPI
  • Playwright: 1.58.0
  • Proxy: No
  • Headless: True (also tested with virtual)

To Reproduce

# This gets blocked (403):
from camoufox.sync_api import Camoufox

with Camoufox(headless=True) as browser:
    page = browser.new_page()
    resp = page.goto("https://www.hilton.com", timeout=15000)
    print(resp.status)  # 403

# This works fine (200 + solvable challenge):
from playwright.sync_api import sync_playwright

with sync_playwright() as p:
    browser = p.firefox.launch(headless=True)
    page = browser.new_page()
    resp = page.goto("https://www.hilton.com", timeout=15000)
    print(resp.status)  # 200
    browser.close()

TLS fingerprint verification

Verified using https://tls.browserleaks.com/json — both browsers produce identical JA3, JA4, and Akamai HTTP/2 fingerprints, confirming the detection is at the application/JS layer, not the network layer.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions