is-incognito-mode - v2.4.0
    Preparing search index...

    Interface DetectIncognitoOptions

    Options for detectIncognito.

    interface DetectIncognitoOptions {
        cache?: boolean;
        globals?: DetectionGlobals;
        privateQuotaThresholdBytes?: number;
        signal?: AbortSignal;
        timeoutMs?: number;
    }
    Index

    Properties

    cache?: boolean

    Memoize the verdict. Private / incognito state cannot change within a page load, so when true the first successful DetectionResult is cached and returned by every later cache: true call — skipping the storage probes entirely. Off by default.

    The cache is keyed by the live navigator object, so it lives exactly as long as the page (and is naturally per-document and per-origin). Nothing is stored globally; injecting a fresh globals (as tests and per-request SSR do) yields a fresh, isolated cache with no manual teardown.

    Only successful verdicts are cached — a TIMEOUT, ABORTED, or PROBE_FAILED rejection is never stored, so a later call retries cleanly.

    Footgun: the cache stores the verdict, not the inputs. A cached call ignores a later call's differing privateQuotaThresholdBytes (and timeoutMs) and returns the original verdict. If you vary the threshold per call, leave cache off.

    // First call probes; subsequent calls are instant for the page's lifetime.
    await detectIncognito({ cache: true });
    await detectIncognito({ cache: true }); // cached

    Override the global navigator / window / indexedDB lookups. Used in tests; in production the live globals are used.

    privateQuotaThresholdBytes?: number

    Advanced override. The Chromium strategy classifies a tab as private when its storage headroom (estimate().quota - estimate().usage) is below this many bytes. Defaults to 9.5 GiB — the midpoint between the 10 GiB headroom Chrome reports for a normal tab and the 9 GiB it reports for an incognito tab.

    Only change this if you have measured your audience.

    signal?: AbortSignal

    An AbortSignal that cancels detection. If it is already aborted when detectIncognito is called, the call rejects synchronously; if it aborts while a probe is running, the probe is abandoned. Either way the rejection is an IncognitoDetectionError with code: 'ABORTED'.

    Pair it with a component lifecycle so a verdict that arrives after the user has navigated away is discarded.

    const controller = new AbortController();
    onCleanup(() => controller.abort());
    await detectIncognito({ signal: controller.signal });
    timeoutMs?: number

    Maximum time, in milliseconds, to wait for a verdict. If detection has not settled by the deadline it rejects with an IncognitoDetectionError whose code is 'TIMEOUT', and any in-flight storage probe is abandoned.

    Defaults to undefinedno deadline (legacy behaviour). Because a storage probe can, in rare browser states, stall indefinitely (e.g. a Firefox indexedDB.open request that never fires success/error), passing a bound such as 5000 is recommended on any critical render path (paywalls, analytics gates) so a stalled probe can never freeze the calling code.

    await detectIncognito({ timeoutMs: 5000 });