Detecting if a browser is using Private Browsing mode

99,018

Solution 1

Update June 2019

Google is removing the ability to detect Private Browsing Mode permanently in Chrome 76 onwards. So, if you're wanting to detect private browsing it's now impossible (unless you find a way to do it that Google hasn't found). The ability to detect private browsing mode has been acknowledged as a bug and was never intended.

To anyone else coming across this question, please note as of 2014, there is no reliable or accurate way to detect if someone is browsing in an incognito/private/safe browsing mode through Javascript or CSS. Previous solutions that once worked like the CSS history hack have since been rendered unusable by all browser vendors.

There should never be a situation where needing to detect private browsing mode on a normal day-to-day website is ever needed. People are choosing to browse anonymously and or not anonymously for their own reasons.

Browsers like Chrome and Firefox do not disable functionality like localStorage any more. They simply namespace it in a temporary location to prevent websites that use it from erroring out. Once you're finished browsing, the namespace is erased and nothing is saved. If you are testing for localStorage support regardless of mode, it will always return true for browsers that support it.

Other means of detecting private mode in Chrome specifically have been completely patched and will no longer work.

If it is required internally by a company, you should develop a browser plugin. Chrome and Firefox, in particular, expose internal API's which allow plugins to check if the user is in private browsing/incognito mode and action accordingly. It cannot be done outside of a plugin.

Solution 2

Here's an easier way to do detect privacy mode. This works in Safari only. I created it because a web app I am developing uses localStorage. LocalStorage is not available in Safari when in privacy mode, thus my app will not work. On page load, run the script below. It shows an alert box if we cannot use localStorage.

try {
  // try to use localStorage
  localStorage.test = 2;        
} catch (e) {
  // there was an error so...
  alert('You are in Privacy Mode\nPlease deactivate Privacy Mode and then reload the page.');
}

Solution 3

Current state

Google Chrome has developed further and leaves no more space for detection when using incognito mode. Same might apply for other browsers.


Old solutions (might partially work)

It is possible to detect enabled private browsing modes for the majority of used browsers. This includes Safari, Firefox, IE10, Edge and Google Chrome.


Firefox

When the private browsing mode of Firefox is enabled, the IndexedDB throws an InvalidStateError because it is not available in private browsing mode.

To very if that:

var db = indexedDB.open("test");
db.onerror = function(){/*Firefox PB enabled*/};
db.onsuccess =function(){/*Not enabled*/};

Safari

For Safari, the key is the local storage service. It is disabled in privacy mode. So try to access it and use a try-catch clause. The following method works on both, OSX and iOS devices. Credits for this method are going to this question and answer

var storage = window.sessionStorage;
try {
    storage.setItem("someKeyHere", "test");
    storage.removeItem("someKeyHere");
} catch (e) {
    if (e.code === DOMException.QUOTA_EXCEEDED_ERR && storage.length === 0) {
        //Private here
    }
}

IE10/Edge

Internet Explore is even going to disable the IndexedDB when in privacy mode. So check for existence. But that's not sufficient enough, because older browsers maybe don't even have an IDB. So do another check, e.g. for events that only IE10 and subsequent browser have/trigger. A related question on CodeReview can be found here

if(!window.indexedDB && (window.PointerEvent || window.MSPointerEvent)){
 //Privacy Mode
}

Chrome

Update: This doesn't work since Chrome 76 (thanks to @jLynx)

Chromes Incognito mode can be verified by the file system. A great explanation can be found here on SO

var fs = window.RequestFileSystem || window.webkitRequestFileSystem;
if (!fs) {
    console.log("FS check failed..");
    return;
}

fs(window.TEMPORARY, 100, function (fs) {}, function (err) {
//Incognito mode
});

Solution 4

Chrome 83 arrives with redesigned security settings, third-party cookies blocked in Incognito by default!

So this one is easy, create a iframe to a third party site, have it send a postMessage back notifying you if navigator.cookieEnabled is true or false. Ofc users have the option to disable third party cookie as well. So i tested and disabled 3th party cookies in the settings. But it still said cookie was enabled on third-party iframes using navigator.cookieEnabled. it only became disabled once i used Incognito - perhaps a bug?

new Promise((rs, rj, m = new MessageChannel(), d = document, i = d.createElement('iframe')) => {
  i.src = 'https://httpbin.org/base64/PHNjcmlwdD5vbm1lc3NhZ2UgPSBlID0+IGUuZGF0YS5wb3N0TWVzc2FnZShuYXZpZ2F0b3IuY29va2llRW5hYmxlZCk8L3NjcmlwdD4='
  i.onload = _ => i.contentWindow.postMessage(m.port1, '*', [m.port1], m.port2.onmessage = e => i.remove(rs(e.data)))
  i.hidden = 1
  d.body.append(i)
}).then(thirdPartyCookieEabled => 
  console.log('Third party cookie enabled:', thirdPartyCookieEabled)
)

You could also probably do it using only js + ajax but didn't want to set up a 2 servers to test it myself. but for this SameSite=none have to be set as well.

res = await fetch('https://httpbin.org/cookies/set?enabled=1', {
  credentials: 'include' 
})
json = await res.json()
console.log(!!json.cookies.enabled)

Here is my take on detecting private mode

function detectPrivateMode(cb) {
    var db,
    on = cb.bind(null, true),
    off = cb.bind(null, false)

    function tryls() {
        try {
            localStorage.length ? off() : (localStorage.x = 1, localStorage.removeItem("x"), off());
        } catch (e) {
            // Safari only enables cookie in private mode
            // if cookie is disabled then all client side storage is disabled
            // if all client side storage is disabled, then there is no point
            // in using private mode
            navigator.cookieEnabled ? on() : off();
        }
    }

    // Blink (chrome & opera)
    window.webkitRequestFileSystem ? webkitRequestFileSystem(0, 0, off, on)
    // FF
    : "MozAppearance" in document.documentElement.style ? (db = indexedDB.open("test"), db.onerror = on, db.onsuccess = off)
    // Safari
    : /constructor/i.test(window.HTMLElement) || window.safari ? tryls()
    // IE10+ & edge
    : !window.indexedDB && (window.PointerEvent || window.MSPointerEvent) ? on()
    // Rest
    : off()
}

detectPrivateMode(function (isPrivateMode) {
    console.log('is private mode: ' + isPrivateMode)
})

edit found a modern, faster, synkronas way to try it in firefox (they don't have service workers in privat mode) similar to ie don't include indexedDB but the test only works in secure sites

: "MozAppearance" in document.documentElement.style ? navigator.serviceWorker ? off() : on()

Solution 5

There's no way for your web page to know, absolutely for sure, that the user is in private browsing mode. Any attempts to check for various browser features will need to change often as security implementations are updated. It may work for some time in some browsers, but not all.

If the company is that concerned about security, I'd suggest rolling your own Firefox or Chromium distribution with locked down privacy settings, and only allowing that custom client to connect to the extranet.

Share:
99,018
Steve
Author by

Steve

Updated on July 05, 2022

Comments

  • Steve
    Steve almost 2 years

    I'm building an extranet for a company paranoid about security. They want to make sure that (among other things) their users are browsing the site with the Private Browsing mode switched on in their web browser so that no cookies or history is kept.

    I found only this http://jeremiahgrossman.blogspot.com/2009/03/detecting-private-browsing-mode.html and https://serverfault.com/questions/18966/force-safari-to-operate-in-private-mode-and-detect-that-state-from-a-webserver

    The ideal solution would use no or minimal javascript. Would attempting to set a unique cookie work for all browsers and platforms? Anyone done this before?

    thanks!


    update

    http://crypto.stanford.edu/~collinj/research/incognito/ uses the CSS visited technique of the browser fingerprinters mentioned by other posters- thanks for the hints.

    I like it because it is small and elegant, but still want to be able to do it without javascript if possible.

  • Marcel Korpel
    Marcel Korpel about 14 years
    Or put the whole site behind a password protected, encrypted connection with caching aggressively disabled.
  • Matt S
    Matt S about 14 years
    What supporting evidence? The "fingerprint" that doesn't tell you if private browsing is on? The company is "paranoid about security", so relying on so-called fingerprints isn't sufficient.
  • Steve
    Steve about 14 years
    @The Rook: nah: its pretty interesting. There are some bizarre technical challenges like requiring all users to go via https but knowing that some countries block ssl connections, or knowing that 10% of my users will be logging in via very flaky 24k dial up lines and only have electricity for a couple of hours a day if they are lucky...
  • Steve
    Steve about 14 years
    hmmm... my own cross platform FF distribution? Thats a bit much effort... Are you aware of an 80% solution? (eg 80% of the time we can guess if the user is in private browsing mode). I'm looking to combine a number of security recommendations to the visitor: using private browsing is one of them. As others have suggested, not all visitors will be willing to do that, and maybe 1/4 of them will be in "safe" locations and will not need to.
  • Steve
    Steve about 14 years
    Thanks for the interesting links. I had a go but all it does is change the fingerprint. If I've done my job right I'll not be able to tell if a visitor has come before with a different fingerprint and therefore be able to detect private browsing?
  • rook
    rook about 14 years
    @Steve Although I haven't done much digging, I suspect that there is a part of the fingerprint that is always abnormal when private browsing is enabled. But this is highly browser specific.
  • Lee Louviere
    Lee Louviere over 12 years
    A recommendation need not know if the user is implementing the suggestion.
  • Lee Louviere
    Lee Louviere over 12 years
    -1 The OP said this is not a solution "10% of my users will be logging in via very flaky 24k dial up lines and only have electricity for a couple of hours a day if they are lucky"
  • Steve
    Steve over 12 years
    how would you do a security leak test?
  • Lee Louviere
    Lee Louviere over 12 years
    Attempt to do things that you're trying to secure against. If you don't want cookies, attempt to make one.
  • Pogrindis
    Pogrindis about 9 years
    There should never be a situation where needing to detect private browsing mode not strictly true, there are issues with apple: stackoverflow.com/questions/21159301/… where it would be nice to notify the client it will not work in private mode.
  • mattLummus
    mattLummus almost 9 years
    While Chrome and Firefox do support webstorage, the Safari and Android market share is significant enough that this should be a concern.
  • kaiser
    kaiser almost 9 years
    Oh, there are cases, believe me. WordPress for example stores if you are logged in in a cookie. Those get destroyed when you close the private mode tab or window. In one current case we have the problem that people keep ranting that they have to log in over and over again as the Safari private mode base window does not explain what happens to Cookies. They just think "history is not saved" and believe that this will help keeping their things private.
  • Professor Falken
    Professor Falken over 8 years
    "There should never be a situation where needing to detect private browsing mode on a normal day-to-day website is ever needed" - Actually, here is one. We are working on a site providing resources for violence against women. As part of that site, we want to educate users who are not browsing in private mode about the fact they need to use private mode to ensure that the site visit is not in their history. I wanted to detect if users are not in private mode and if that's the case provide appropriate instructions on how to clear recent cache and return in private mode.
  • Mrchief
    Mrchief over 8 years
    Interesting read. The "try it" link is broken at the moment. :(
  • ChrisWren
    ChrisWren about 8 years
    Maybe also add localStorage.test = null; so it doesn't pollute storage for other browsers?
  • Kevin Dice
    Kevin Dice almost 8 years
    Note: Promises aren't natively supported in IE10 or 11. I'd assume you used a polyfill here? caniuse.com/#search=promise
  • Ithar
    Ithar over 7 years
    @PaulAnnekov yes as stated in the answer this only works for Safari browser
  • Mahmoud Mostafa
    Mahmoud Mostafa about 7 years
    This is deprecated and not working in current version of firefox @Endless Answer seems the one working for me in latest Firefox and Chrome versions
  • Endless
    Endless almost 7 years
    @kevinDice I changed it to a simple callback
  • Dave White
    Dave White almost 7 years
    @ChrisWren Each browser has their own localstorage. They don't share it.
  • Etienne Martin
    Etienne Martin almost 7 years
    DNT is broken in the latest beta version of Safari 11. It's not longer exposed to JavaScript, only via the HTTP header.
  • Graham
    Graham over 6 years
    We've had multiple users not realize they were in private browsing mode and thought that there was an issue with our site. I completely disagree with your assumption that there is never a need to detect this.
  • Luc
    Luc over 6 years
    Thanks, that explains how some website detected this. I found it very creepy that a site could figure that out... (N.B. this was in Firefox 55.)
  • Maykonn
    Maykonn almost 6 years
  • proxiblue
    proxiblue almost 6 years
    This was only possible due to a bug in Safari, which has been fixed as of iOS 11
  • Riesling
    Riesling almost 6 years
    Safari didn't work for me anymore (11.1.2) but the referenced SO question got a new answer, which works for me: stackoverflow.com/a/47642304/333864
  • LWC
    LWC over 5 years
    @dwayne-charrington, that's quite a statement. More and more websites do detect it so obviously there are ways, like this for Chrome: stackoverflow.com/a/27805491/4829915
  • Dwayne Charrington
    Dwayne Charrington over 5 years
    @LWC Please take note of when this answer was posted, March 25th, 2014. The FileSystem API was and to be honest, still is not very well supported. The answer you link was posted 3 years after my response (a millennia in web years). From what I can see, all solutions to detect incognito mode are still unreliable hacks. Until there is a valid browser API to do this, all solutions are hacks.
  • LWC
    LWC over 5 years
    @dwayne-charrington, the Chrome solution still works, hack or not. In the current era of growing privacy awareness, an official global API to expose people's privacy preferences is unlikely.
  • Tomáš Kafka
    Tomáš Kafka over 5 years
    There are such cases - for example, we'd like to NOT offer the user saving of some items on site locally (without login) when he's in private mode - because he'll likely not realize that the saved items will disappear.
  • Matt K
    Matt K about 5 years
    The NY Times is now implementing this verification on their site and requiring you to log in or create an account. Previously (around a week ago) if you reached your "free article" limit you could just load the site in incognito mode and read all you want. I guess they caught on! It also disproves your statement that there is never a use case for detecting private browsing mode.
  • user10216038
    user10216038 almost 5 years
    I have no idea why someone down rated you? Here's another: .... gist.github.com/jherax/a81c8c132d09cc354a0e2cb911841ff1
  • Nathan
    Nathan over 4 years
    @professor-falken - it seems that would be information worth putting on the page whether they are in private mode or not? (cf. the cookie popups most sites now have).
  • Scott Martin
    Scott Martin about 4 years
    The New York Times site can detect Chrome 80 running in incognito mode, so there's something else besides this.
  • Hugo
    Hugo about 4 years
    I don't know how but the NYT can still detect if I am using private mode. imgur.com/a/7z6E388
  • Lii
    Lii about 4 years
    I guess that this script was written before Chrome 76 and that it no longer works for Chrome?
  • gman
    gman about 4 years
    Vanity Fair detects both Chrome Incognito and Firefox Privacy modes. You have pick an article and the start scrolling, a few seconds later it will pop up a "you're in privacy mode, stop it" msg.
  • Gunnar Vestergaard
    Gunnar Vestergaard over 3 years
    This one is the best answer I have ever read in this thread.
  • SandRock
    SandRock over 3 years
    The naming of the method looks wrong. It should be alertIfPrivateWindow because the function is alert()ing. Using the is prefix suggests a boolean is returned; which is false here.
  • jLynx
    jLynx over 3 years
    @SandRock in this example it alerts regardless on weather its private or not. So the suggested name change here doesn't quite make sense
  • Jacques Ramsden
    Jacques Ramsden about 3 years
    The Edge check is no longer valid as window.indexedDB exists in private mode also now.
  • mti2935
    mti2935 about 3 years
    As of May 2021, it seems that it is still possible for sites to detect whether or not Firefox is running in private mode. See security.stackexchange.com/questions/9037/….
  • Sunit Samanta
    Sunit Samanta about 2 years
    @Endless Is there any alternative url instead of "httpbin.org/base64/…"
  • Endless
    Endless about 2 years
    any 3th party site that has ` <script>onmessage = e => e.data.postMessage(navigator.cookieEnabled)</script>` can work
  • Daniel says Reinstate Monica
    Daniel says Reinstate Monica almost 2 years
    This is a top-tier joke