docs: warn about true-headless gotcha in public config API

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.
This commit is contained in:
feder-cr 2026-05-28 17:10:48 -07:00
parent c5c1ef9559
commit 32965afefb
2 changed files with 11 additions and 0 deletions

View file

@ -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

View file

@ -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