Detecting if a browser is using Private Browsing mode
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.
Steve
Updated on July 05, 2022Comments
-
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 about 14 yearsOr put the whole site behind a password protected, encrypted connection with caching aggressively disabled.
-
Matt S about 14 yearsWhat 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 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 about 14 yearshmmm... 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 about 14 yearsThanks 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 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 over 12 yearsA recommendation need not know if the user is implementing the suggestion.
-
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 over 12 yearshow would you do a security leak test?
-
Lee Louviere over 12 yearsAttempt to do things that you're trying to secure against. If you don't want cookies, attempt to make one.
-
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 almost 9 yearsWhile Chrome and Firefox do support webstorage, the Safari and Android market share is significant enough that this should be a concern.
-
kaiser almost 9 yearsOh, 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 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 over 8 yearsInteresting read. The "try it" link is broken at the moment. :(
-
ChrisWren about 8 yearsMaybe also add localStorage.test = null; so it doesn't pollute storage for other browsers?
-
Kevin Dice almost 8 yearsNote: Promises aren't natively supported in IE10 or 11. I'd assume you used a polyfill here? caniuse.com/#search=promise
-
Ithar over 7 years@PaulAnnekov yes as stated in the answer this only works for Safari browser
-
Mahmoud Mostafa about 7 yearsThis 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 almost 7 years@kevinDice I changed it to a simple callback
-
Dave White almost 7 years@ChrisWren Each browser has their own localstorage. They don't share it.
-
Etienne Martin almost 7 yearsDNT is broken in the latest beta version of Safari 11. It's not longer exposed to JavaScript, only via the HTTP header.
-
Graham over 6 yearsWe'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 over 6 yearsThanks, 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 almost 6 yearsExists a lib to detect browsing mode: github.com/Maykonn/js-detect-incognito-private-browsing-paywall
-
proxiblue almost 6 yearsThis was only possible due to a bug in Safari, which has been fixed as of iOS 11
-
Riesling almost 6 yearsSafari 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 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 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 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 over 5 yearsThere 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 about 5 yearsThe 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 almost 5 yearsI have no idea why someone down rated you? Here's another: .... gist.github.com/jherax/a81c8c132d09cc354a0e2cb911841ff1
-
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 about 4 yearsThe New York Times site can detect Chrome 80 running in incognito mode, so there's something else besides this.
-
Hugo about 4 yearsI don't know how but the NYT can still detect if I am using private mode. imgur.com/a/7z6E388
-
Lii about 4 yearsI guess that this script was written before Chrome 76 and that it no longer works for Chrome?
-
gman about 4 yearsVanity 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 over 3 yearsThis one is the best answer I have ever read in this thread.
-
SandRock over 3 yearsThe naming of the method looks wrong. It should be
alertIfPrivateWindow
because the function is alert()ing. Using theis
prefix suggests a boolean is returned; which is false here. -
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 about 3 yearsThe Edge check is no longer valid as window.indexedDB exists in private mode also now.
-
mti2935 about 3 yearsAs 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 about 2 years@Endless Is there any alternative url instead of "httpbin.org/base64/…"
-
Endless about 2 yearsany 3th party site that has ` <script>onmessage = e => e.data.postMessage(navigator.cookieEnabled)</script>` can work
-
Daniel says Reinstate Monica almost 2 yearsThis is a top-tier joke