Private windows don't just hide history — they change how storage APIs behave, and that difference is exactly what sites use to detect Incognito mode.
Incognito and private browsing windows promise that a site won't be able to tell you've been there before. They don't promise the site can't tell you're currently in one — and for a decade, publishers, ad networks, and fraud tools have exploited exactly that gap. Because a private window has to behave differently under the hood — different storage limits, different on-disk behavior — a script that probes those differences can often conclude "this is a private window" with real confidence, all without reading a single cookie.
Key Takeaways
- Private browsing hides history, not behavior — storage APIs like
navigator.storage.estimate()still report real, measurable differences between normal and private sessions. - Chromium's oldest trick measured write speed to the (now-deprecated) FileSystem API, which ran in-memory in Incognito and was roughly 3–4× faster than the real disk writes used in normal mode.
- After Chrome closed that loophole in 2019, detection scripts pivoted to the storage quota Chrome reports via
navigator.storage.estimate()— smaller and more uniform in Incognito, larger and disk-proportional in normal mode. - Chrome has since started reporting a fixed, "predictable" quota in every mode specifically to kill that heuristic — an active, ongoing fix rather than a settled one.
- Firefox and Safari have their own histories of private-mode tells, mostly around
localStorageandIndexedDBbehaving differently (or failing outright) in a private session. - BrowserInsight's fingerprint check shows the storage, canvas, and other signals your browser currently exposes, private window or not.
Why Sites Bother Detecting Incognito
The two dominant motives are commercial, not adversarial in the security sense. Metered-paywall publishers — most famously the New York Times — use Incognito detection to stop readers from resetting their free-article count by opening a fresh private window each time. Ad-tech and fraud-prevention tools use it as one more signal: a disproportionate share of private-window traffic correlates with ad-fraud click farms and coupon/promo abuse, so flagging it feeds a broader risk score the same way bot detection systems combine many weak signals rather than trusting one.
Neither use case needs to identify who you are — only whether the window you're using right now is private. That narrower goal is what makes the technique different from browser fingerprinting: it isn't trying to build a persistent identifier, just to answer one yes/no question for the duration of a page load.
The FileSystem Write-Speed Trick
The earliest reliable Incognito detection technique targeted Chrome's implementation of the (now deprecated, Chromium-only) File and Directory Entries API — window.webkitRequestFileSystem and friends. In a normal window, Chrome backed this API with real files on disk. In Incognito, to avoid leaving any trace once the window closed, Chrome backed it with an in-memory virtual filesystem instead.
Memory is dramatically faster than disk, so a script could write a batch of temporary files, time how long the writes took, and get a clean signal: writes that complete three to four times faster than a normal-mode baseline mean the filesystem never touched disk, which means the window is private. No permission prompt, no user interaction — just a timing measurement against an API that was, at the time, exposed by default.
Chrome closed this specific loophole in version 76 (2019), switching Incognito's FileSystem implementation to also write to disk rather than memory, which erased the timing gap. It was a direct response to the paywall-detection use case getting mainstream press attention — closing a genuine loophole, not a cosmetic patch.
The StorageManager Quota Trick
The fix didn't end the cat-and-mouse game; it just moved it one API over. Every modern browser exposes navigator.storage.estimate(), part of the Storage API, which returns a promise resolving to the current storage usage and the quota available to the origin:
// Illustrative sketch — not the exact detectIncognito heuristic
async function looksLikeIncognito() {
const { quota } = await navigator.storage.estimate();
const ONE_TWENTY_MB = 120 * 1024 * 1024;
// Historically: Chromium capped Incognito quota well below
// the large, disk-proportional value normal windows report.
return quota < ONE_TWENTY_MB;
}
In normal browsing, Chromium historically computed the reported quota from a fraction of actual free disk space — often tens or hundreds of gigabytes. In Incognito, because the profile is temporary and typically capped by available RAM rather than disk, the quota came back far smaller and comparatively uniform across machines. A script only had to check whether the reported number fell under a low threshold (public write-ups cite roughly 120 MB as the cutoff) to make a confident call.
This exact heuristic — plus Chromium-specific fallbacks and separate checks for Firefox, Safari, Edge, and Opera — is maintained as an open-source reference implementation in Joe12387/detectIncognito on GitHub, which is a useful primary source for how varied and browser-specific these checks have become over time.
Firefox and Safari Have Their Own Tells
Chromium's storage-quota gap gets the most attention because Chrome's market share makes it the highest-value target, but Firefox and Safari have each shipped their own detectable private-mode quirks at different points:
| Browser | Historical private-mode tell | Root cause |
|---|---|---|
| Chrome / Chromium | FileSystem write speed (pre-2019); storage quota (post-2019) | In-memory filesystem; smaller RAM-based quota |
| Safari | localStorage.setItem() threw a quota-exceeded error | Private mode capped Web Storage quota at 0 bytes |
| Firefox | indexedDB was null or requests failed silently | IndexedDB was unavailable in private windows for years |
Safari's version was arguably the crudest: for years, calling localStorage.setItem() inside a private window threw an exception immediately, because Safari set the private-mode storage quota to zero rather than isolating it. Wrapping a single try/catch around a test write was enough to detect the mode with near-perfect accuracy. Apple fixed this in Safari 11 by making localStorage fully writable in private windows again — the data simply lives in memory and disappears when the session ends, instead of being blocked outright.
Firefox's IndexedDB told a similar story from the other direction: private windows either exposed no indexedDB object or failed open requests, which a script could catch just as easily as Safari's storage exception. Firefox has since moved toward supporting IndexedDB inside private browsing using encrypted, session-scoped storage, closing that particular gap the same way Chrome closed its FileSystem gap — by making the private-mode implementation behave enough like the normal one that the timing/availability signal disappears.
A Decade of Cat-and-Mouse
The pattern across every browser is the same three-step cycle, just on different timelines: an implementation detail leaks a private-mode difference → the difference gets weaponized for paywall or fraud detection → the vendor re-engineers the private-mode implementation to remove the gap, which usually opens a smaller, subtler one somewhere else. Storage APIs keep being the battleground because private mode's entire job is to behave differently with data — the one property detection scripts can always try to measure.
Where Things Stand in 2026
The StorageManager quota trick still works against current stable Chrome, but its days look numbered. Chrome has been shipping a mitigation called "predictable reported storage quota", which reports an artificial quota — usage plus the smaller of 10 GiB or your rounded disk size — in every browsing mode for sites without elevated storage permissions, specifically so normal and Incognito windows become indistinguishable by this measurement. As of mid-2026 it's rolling out for sites with limited storage permissions; sites that have been granted unlimited storage or that hit an enforced quota are explicitly unaffected, so the heuristic hasn't disappeared everywhere at once.
The practical takeaway is that no single storage check is a durable Incognito detector, and none of these techniques ever needed cookies, canvas, or a persistent identifier — they're a narrower, faster-moving game than fingerprinting, fought API by API rather than signal by signal.
Does Incognito Protect You From Fingerprinting?
Not by itself, and that's the more important point once the detection question is settled either way. A private window changes what gets stored — history, cookies, cached form data — not what your browser reveals on a live page: the same canvas hash, WebGL renderer string, fonts, and screen characteristics render identically whether the window is private or not. If you're using Incognito expecting anonymity from fingerprinting, Browser Fingerprinting Explained covers why that expectation doesn't hold and what actually reduces exposure.
Run BrowserInsight's fingerprint check once in a normal window and once in a private one — the underlying signals will look nearly identical, which is the clearest way to see that "private" and "unfingerprintable" are two different guarantees.
Frequently Asked Questions
Can a website always tell I'm in Incognito mode?
No. Detection has always depended on a specific implementation quirk in a specific browser version, and those quirks get patched. A technique that worked reliably last year can silently stop working after a browser update, and vice versa — it's an unstable arms race, not a settled capability.
Does clearing cookies or using a VPN stop Incognito detection?
No, because these techniques never look at cookies or your IP address in the first place. They measure how storage APIs behave for the current session, which is unrelated to what a VPN or cookie clearing changes.
Is detecting Incognito mode illegal?
Detecting it isn't inherently illegal, but what a site does with that information can raise separate legal and ethical questions — particularly when it's used to circumvent a user's deliberate privacy choice for commercial ends, such as forcing paywall resets. Regulations vary by jurisdiction and this isn't legal advice.
Why did Chrome take years to fully fix this?
Because each fix only closed one specific loophole, and the fundamental constraint — a private session's storage has to behave differently from a normal one somewhere — kept reopening new, narrower gaps. The FileSystem fix in 2019 didn't touch the StorageManager quota gap, and the current quota mitigation is itself still rolling out with carve-outs, which is a good illustration of how hard "indistinguishable by design" is to achieve completely.
Conclusion
Incognito detection is a narrower, faster-moving cousin of browser fingerprinting: instead of building a persistent identifier from dozens of signals, it asks one question — is storage behaving like a private session? — using whatever API currently answers it. Each fix closes a real gap and each new gap gets found again, which is exactly why understanding the mechanism matters more than trusting any specific "Incognito is undetectable" claim at face value.
Recommended Reading:


