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