From 143aff4bd29d0991248d83d532248700d77339a9 Mon Sep 17 00:00:00 2001 From: Federico <85809106+feder-cr@users.noreply.github.com> Date: Thu, 28 May 2026 17:19:26 -0700 Subject: [PATCH] docs: warn about true-headless gotcha in public config API (#27) Live smoke test caught a footgun: passing headless=True directly to playwright.firefox.launch() with our prefs puts Firefox in true headless mode (no rendering pipeline) which breaks canvas/audio/WebGL fingerprint coherence. InvisiblePlaywright translates user-facing headless=True to Playwright headless=False + virtual display automatically; the new public helpers do not, so the docstring + README now flag this explicitly. Verified: same prefs + headless=False via firefox.launch() reaches bot.sannysoft.com with 23 passed / 0 failed, matching what InvisiblePlaywright produces. --- README.md | 2 ++ src/invisible_playwright/config.py | 9 +++++++++ 2 files changed, 11 insertions(+) diff --git a/README.md b/README.md index 7629a68..3061a8e 100644 --- a/README.md +++ b/README.md @@ -189,6 +189,8 @@ async with async_playwright() as p: `get_default_stealth_prefs(seed, *, pin, locale, timezone, extra_prefs, humanize, virtual_display)` returns the same dict that `InvisiblePlaywright(seed=..., locale=..., ...)` would inject. Same deterministic seed semantics, same humanize toggle, same `extra_prefs` overlay. `ensure_binary()` downloads the patched Firefox on first call and returns its absolute path. +> Important: pass `headless=False` to `firefox.launch()` and manage display hiding yourself (Xvfb on Linux, hidden desktop on Windows). Passing `headless=True` directly puts Firefox in true headless mode and skips the real rendering pipeline, which breaks canvas / audio / WebGL fingerprint coherence. The `InvisiblePlaywright` context manager does this translation automatically; the public helpers leave it to the caller. + For everyday Python usage the `InvisiblePlaywright` context manager is still the recommended entry point. ## Related projects diff --git a/src/invisible_playwright/config.py b/src/invisible_playwright/config.py index 9d1a80b..3fa3dc5 100644 --- a/src/invisible_playwright/config.py +++ b/src/invisible_playwright/config.py @@ -22,6 +22,15 @@ blocks:: For everyday Python usage the ``InvisiblePlaywright`` context manager is still the recommended entry point; these helpers expose the same internals without the lifecycle ownership. + +.. note:: + When calling ``firefox.launch()`` yourself, pass ``headless=False`` and + manage the display hiding (Xvfb on Linux, hidden desktop on Windows) + externally. Passing ``headless=True`` directly to Playwright puts + Firefox in true headless mode, which skips the real rendering pipeline + and breaks canvas / audio / WebGL fingerprint coherence. The + ``InvisiblePlaywright`` context manager does this translation + automatically; the public helpers leave it to the caller. """ from __future__ import annotations