65

Most modern browsers support "private browsing mode" (also known in Chrome as "Incognito mode"), where the browser does not save any information to disk about your browsing while in this mode.

In modern browsers, can a web site detect whether a user who is visiting the web site has private browsing mode enabled or not?

The background research I've done. Here's what I've been able to find related to this question. Unfortunately, it doesn't really answer the question above.

  • A 2010 study of private browsing mode showed that it is possible for web sites to detect whether the browser is in private browsing mode, by using a CSS history sniffing attack. (In private browsing mode, sites are not added to the history, so you can use history sniffing to check whether the visitor is in private browsing mode.) Since then, though, modern browsers have incorporated defenses against CSS history sniffing attacks.

    Consequently, I would not expect that method of detecting whether the browser is in private browsing mode to be successful any longer. (I realize the defenses against history sniffing are not perfect, but they may be good enough for these purposes.)

  • There may be ways for a website you're visiting to learn whether you are currently logged into other sites (think: Facebook). If the user is currently logged into other services (like Facebook), a website could plausibly guess that the user is not currently using private browsing mode -- this is not a sure thing, but perhaps one could make some kind of probabilistic inference. However, if the user isn't logged into other services, then I guess all we can say is that we don't know whether private browsing mode is in use. It is possible this might yield a partial leak of information, I suppose, but it sounds unreliable at best -- if it even works. It is also possible that this might not work at all.

So, can anyone provide any more recent information about whether there's a way for a website to test whether its visitors are using private browsing mode?

D.W.
  • 98,420
  • 30
  • 267
  • 572
  • 8
    What's the end goal? What can the website achieve by detecting private browsing mode? Which aspect of private browsing is important to you -- cookies, history, cache, etc? What's the difference between private browsing and, say, a throwaway firefox profile? Or using privoxy set to nuke all cookies? – bstpierre Nov 19 '11 at 12:33
  • 20
    "_The background research I've done._" +1 The question itself is worth reading. Thank you. – curiousguy Nov 19 '11 at 17:09
  • 1
    Some additional information here: http://apple.stackexchange.com/questions/131587/how-can-a-web-site-determine-if-safari-private-browsing-is-turned-on Notably, that specific to Safari under Mavericks, Private Browsing mode does not send requests for favicons, so this could be a vector for discovering whether P.B. is on. – pseudon May 22 '14 at 19:23
  • I'm quite intrested in this. I have configured my browser (Chrome) to delete all userdata when I close it (i.e. cookies, form data (which I don't save anyway), sessions, ...). So I need to re-login every time I closed my browser. I wonder if this would create a false positive for Icognito Modus scanning methods. I also use Incognito quite often when visiting torrents sites and other sites I expect to encounter malware/adware/... I'd also like to know wether some extensions can leak this info, they are not enabled in Incognito Mode tho' (AdBlock+, DoNotTrackMe, HTTPS Everywhere, ...) – BlueCacti May 23 '14 at 11:32
  • If the end goal is to track users, regardless of normal or incognito mode, this might be helpful: http://www.radicalresearch.co.uk/lab/hstssupercookies – racec0ndition May 26 '15 at 17:55
  • 1
    It would be helpful to have answers with more up to date information. I think the situation has changed quite a bit since this question was asked in 2011. Now, in 2019, it seems pretty standard for newspaper web sites to refuse access if they detect/think you're in private mode. So it may just be a heuristic, but it's no longer hypothetical, it's in common use. I would have liked to offer a bounty for a more recent answer, but apparently the SE software won't let me offer even a small bounty because my rep is only 244. –  Jun 11 '19 at 15:40
  • 2
    @BenCrowell I started a bounty on this question. – gparyani Jun 11 '19 at 19:24

7 Answers7

30

Note this answer was given in 2011. Today the answer is an unequivocal YES -- as of this writing in 2020 there are reliable techniques in wide use and have been for a while. Please see one of the good current answers below 1 2 for more up to date information.

I'm not sure you could reliably detect private browsing, but I think you may be able to apply some heuristics to make a good guess that a user is using various privacy-enhancing features. As indicated in my comment on the question, whether this is good enough or fits your application depends on what you want to be able to do in reaction to detecting private browsing. As Sonny Ordell mentioned, I'm also not sure that you can distinguish private browsing from the ad hoc use of various privace-enhancing features (e.g. manually clearing history or cookies).

Let's assume you operate a web application, and you want to detect when one of your users (with an account) switches to private browsing. I'm specifying that the user has an account, because this strategy relies on tracking various bits of behavior data. The aspects of private browsing are (at least in Firefox): history, form/search entries, passwords, downloads, cookies, cache, DOM storage. I'm not sure how to probe for downloads, but I think the others can be probed. If you get a positive detection on all of them, it seems more likely that your user is private browsing.

  • In the trivial case, you keep track of (IP, user-agent) for each user. When you get a cookie-less request for a matching (IP, UA) record, you might infer that the corresponding user is private browsing. This method fails (no detection) if:
  1. He uses something like ProxySwitchy or TorButton to activate Tor during private browsing, thus changing IP.
  2. He switches to a different browser (e.g. usually uses FF and switches to Chrome for Incognito mode).
  3. The switch to private browsing is not immediate and his ISP has issued a new IP (e.g. on Friday he was 10.1.2.3, he didn't use your app over the weekend, and on Monday he is 10.1.4.5).

As mentioned in Sonny Ordell's answer, if another person uses the same browser in private browsing mode to access a separate account on your site, you will get a detection -- but this is a slightly different case than if the "normal" user simply switches to private browsing mode.

You'll get a false-positive if the user simply clears his cookies for your site, or uses a secondary profile (e.g. I keep a few different Firefox profiles with different sets of plugins for certain testing and/or to avoid tracking, though I'd guess this is very uncommon).

  • As a more complex check, you could use something like EFF's panopticlick and maintain a browser fingerprint (or collection of fingerprints) instead of just the UA for each user. This fails in situation 2 mentioned above (e.g. if the user exclusively uses FF for identifiable browsing and Chrome for incognito). The fingerprint will be much more generic (and thus much less useful) if the user has javascript disabled. The fingerprint will change if the user selectively enables javascript in different sessions (e.g. NoScript with temporarily allowed sites).

  • You may be able to defeat issue 1 (Tor) by detecting access via a Tor exit node, and combining this with fingerprinting. This seems like it would only be helpful in a narrow range of cases.

  • Instead of just cookies for the checks above, test localStorage. If it's typically enabled, and your key isn't in the storage for this visit, and the fingerprint matches, then this is probably private browsing. Obviously, if the user normally has storage disabled, then you can't use it. The failure modes are similar to those described above for cookies.

  • I haven't tested or developed the idea, but I suppose you could play games with Cache-Control. (A quick search reveals that this isn't an original idea -- that project has what looks like proof-of-concept code.) This strategy fails if the user goes through a shared caching proxy -- the meantime page mentions anonymizer.com. Firefox, at least, doesn't use the cache in private browsing mode. (See this site for a demo of cache-based tracking.) So you could combine this with the UA/fingerprinting mentioned above: if your cache tracker indicates this is a first visit, then you can guess that the user is private browsing. This fails with a false positive if the user cleans his cache; combine with other techniques to get a better guess.

  • You could detect and track, for each user, whether the browser autofills a certain form element. If you detect that a given user doesn't get autofill on that form element, you might infer private browsing. This is brittle -- perhaps the user is not using his "primary" computer, but you could combine it with fingerprinting as mentioned above for a more reliable guess.

  • Side-channel timing attack: detect and track the typical time it takes for each user to log into your app. There will be variations, but I'm guessing that you could get an accurate guess about whether someone is using password autofill. If a user normally uses password autofill (i.e. fast transition through the login page), and then for a given visit (with a matching fingerprint) is not using autofill, you can infer private browsing. Again this is brittle; combine with other techniques for a better guess. You'll also want to detect and correct for network latency on a given page load (e.g. perhaps the user's network is just slow on a given day, and a slow login page transition is just latency and not a lack of autofill). You can be slightly evil and auto-logout the user (give them a bogus error message, "please try again") to get a second data point if you're willing to annoy your users a bit.

  • Combine this with what you mentioned in the question about detecting if the user is logged in to other services (e.g. Facebook), and you can have more confidence in your guess.

  • If you're really motivated, you could play games with DNS and tracking page load times. A quick test of FF 3.6 and Chrome 15 seems to indicate that neither browser clears the DNS cache in private browsing mode. And the browser has absolutely no control over the local system's DNS cache. If you use a side-channel DNS timing attack to perform user tracking as an alternative (or in addition to) fingerprinting, you may get a more reliable guess. I'm not sure how reliable tracking via DNS timing will be.

Detection of "anonymous" users in private browsing mode will be much harder, since you haven't had the opportunity to accumulate data on their "typical" behavior. And, since most of the features only kick in when they end the browser session, you don't really know if they're ever going to be back.

With that said, here's an idea to detect private browsing by anonymous users, if you're willing to be evil, and you had some resource for which you knew a user was willing to give your site a second chance, and you can force the user to enable javascript. Track fingerprint, set a persistent cookie, localStorage, cache -- whatever you can do to track the user. If it's a first visit according to your fingerprint, crash/hang the browser via javascript (or flash, or whatever evil tricks you know). Suck up tons of memory, or get stuck in a loop, or whatever it takes so that the user closes the browser. Then when they return, you see (from the fingerprint) that it's a second visit. If the cookie/storage/cache/etc aren't set, then you can infer that the first session was private browsing, and I suppose you might infer that the second session is probably also private browsing. This obviously fails if the user doesn't come back, or if you can't crash / convince them to kill the browser window. As a bonus, if you send them to a custom URL, and they're in non-private-mode and restore the browsing session then you can guess they aren't in private browsing mode (unless they bookmarked the URL).

Everything above is full of holes -- plenty of room for false positives or negatives. You'll probably never know if I'm using private browsing, or if I'm running a browser in a VM with no persistent storage. (What's the difference?)

The worst part is probably that if you do get an answer with a reliable method for detecting private browsing is that it seems unlikely to remain viable for very long as browsers either "fix" it or users find workarounds to avoid detection.

bstpierre
  • 4,868
  • 1
  • 21
  • 34
  • An interesting answer, but ultimately the answer to the question is still no. You can only guess as to whether the user has privacy features enabled or is actually using a private browsing mode. It's possible for a browser to be configured just as in private browsing mode permanently as well, in which case what of the question? – Sonny Ordell Dec 08 '11 at 16:30
  • 8
    @SonnyOrdell: I think my answer is full of enough disclaimers that it's obvious the short answer is "no". As I mention in my comment/questions on the OP, I think the real answer depends on what the web site operator wants to do with the detection. – bstpierre Dec 08 '11 at 16:49
  • 2
    This answer may need some updating in 2019, where many, many news sites commonly are able to detect private browsing mode. Your answer may be pedantically correct, but observationally, in June 2019 I find many newspaper sites are extremely accurate in determining when I have private/incognito mode on. – Steve Sether Jun 19 '19 at 20:29
9

HTML 5 local storage check allows you to reliably detect private browsing mode now (2019). It works by attempting to write then read "Local Storage".

see:

https://gist.github.com/jherax/a81c8c132d09cc354a0e2cb911841ff1

or

https://github.com/jLynx/PrivateWindowCheck with PoC

  ------ edit to add functional description ----

From the jherax link above:

...
    // **Firefox**
    if ('MozAppearance' in document.documentElement.style) {
      if (indexedDB === null) return yes();
      const db = **indexedDB.open**('test');
      db.onerror = yes;
      db.onsuccess = not;
      return void 0;
---

From jLynx above

...
        } else if(navigator.userAgent.includes("Firefox")){
            //Firefox
            var db = indexedDB.open("test");
            db.onerror = function(){resolve(true);};
            db.onsuccess =function(){resolve(false);};
---

In both examples, the failure to open persistent local storage, indexDB for Firefox, (defined by HTML 5) indicates private browsing. Other browsers call local storage by different names such as localStorage, go figure.

user10216038
  • 7,552
  • 2
  • 16
  • 19
  • 1
    Pretty good answer, albeit link-only. Include the salient lines of code in this post and an explanation how it works, and I'll award this the bounty. – gparyani Jun 18 '19 at 18:20
  • 1
    Thanks for this. I did wonder how these websites were able to so accurately figure out private browsing mode. In June 2019 the top answer now looks silly since anyone knows that detection is easy. Maybe browsers will fix this in some way, and we'll go back to a no easy incognito mode detection world, and the top answer will be accurate again? – Steve Sether Jun 19 '19 at 20:37
8

You can use heuristics to make a solid guess. In IE10 and IE11 (and Safari, IIRC), for instance, exceptions thrown when attempting to use IndexedDB as a strong hint that the browser is InPrivate mode.

Similarly, Adobe's DRM system (used by HBOGO, apparently) surfaces an error code when the browser is InPrivate/Incognito, because required "license artifacts" are not permitted to be created in the private mode. https://forums.adobe.com/thread/1189199

EricLaw
  • 358
  • 2
  • 6
5

I see there's a bounty because you want a more precise and up-to-date answer, but the truth is that the right answer was already given by others. I can just give you a few more details, even though I'm not a JS developer and I've never known how this stuff works either.

The short answer is: they use JavaScript to implement some kind of heuristics that mainly checks if some functionality is available or not.

Take a look at bostonglobe.com for example. Click on an article while in private mode, and you'll see the notice: "You are in private mode, etc.". If you disable the JavaScript, that notice won't appear, which means it's done in JS. The same is true if you go to the New York Times, it's just JS. But how do they do it exactly? On bostonglobe.com I found the code in a JS file named meter.js in the source. If you search in that code for detectPrivateMode you'll see the function it uses. It's minified, so it's a pain to read. Prettifying the source in the browser's dev tools however gives the following code:

detectPrivateMode: function (t) {
  var e;
  if (window.webkitRequestFileSystem) window.webkitRequestFileSystem(window.TEMPORARY, 1, function () {
    e = !1
  }, function (t) {
    console.log(t),
    e = !0
  });
   else if (window.indexedDB && /Firefox/.test(window.navigator.userAgent)) {
    var i;
    try {
      i = window.indexedDB.open('test')
    } catch (t) {
      e = !0
    }
    void 0 === e && n(function () {
      return 'done' === i.readyState
    }, function (t) {
      t || (e = !i.result)
    })
  } else if (r(window.navigator.userAgent)) {
    e = !1;
    try {
      window.indexedDB || (e = !0)
    } catch (t) {
      e = !0
    }
  } else if (window.localStorage && /Safari/.test(window.navigator.userAgent)) {
    if (window.safariIncognito) e = !0;
     else {
      try {
        window.openDatabase(null, null, null, null)
      } catch (t) {
        e = !0
      }
      try {
        window.localStorage.setItem('test', 1)
      } catch (t) {
        e = !0
      }
    }
    void 0 === e && (e = !1, window.localStorage.removeItem('test'))
  }
  n(function () {
    return void 0 !== e
  }, function (n) {
    t(e)
  })
}

You can see for example that they are trying to use window.webkitRequestFileSystem, in Firefox they'll try window.indexedDB.open('test'), in Safary window.openDatabase, and so on. All those functions seem to rely on the fact that they behave differently in private mode (incognito mode). Most of the code seems to use functions related to local storage, which apparently behaves differently than in normal mode. There are several try-catch blocks, so most of those functions probably are not even available in private mode. If you google any of those functions (also maybe adding "private" or "incognito" in the search) you'll find a lot of results discussing the possible ways to detect private mode, and in the end the code you will find will look very similar to the one I quoted. You will find several questions on StackExchange and also code snippets GitHub. For example, this answer on StackExchange has some interesting information: https://stackoverflow.com/a/41322183

On the New York Times, if you click on an article, open the HTML source, and search for webkitRequestFileSystem, you will find similar code.

As you can see, there might be some differences in the code and the heuristics they use, but every website is likely detecting private mode by relying on the same small set of functions.

reed
  • 15,398
  • 6
  • 43
  • 64
  • Would be nice if your answer covered *how* the functions are different in private vs. normal modes. – gparyani Jun 12 '19 at 18:33
  • @gparyani, unfortunately I don't know that, I don't feel much like doing it, and it might even be off-topic for this site anyway (you might try on StackOverflow maybe?) However, while googling stuff for this answer, it seemed to me that it was not really clear *why* this stuff works. It might be hard to find official docs too, because I suspect some of this stuff is even non-standard. If anybody has something to add, or a better answer, then we will see. I hope this was helpful to you anyway. – reed Jun 12 '19 at 18:40
  • @reed thanks for updating the info from 2011 and running tests! – schroeder Jun 12 '19 at 19:09
3

Apparently there are some ways that web sites can detect when you are in Private Browsing mode, for desktop Safari and mobile Safari.

Desktop Safari does not request favicons when in Private Browsing mode, which gives things away. It also has other differences.

Mobile Safari does not support HTML5 local storage when in Private Browsing mode, which is also detectable by web sites.

D.W.
  • 98,420
  • 30
  • 267
  • 572
2

As of March 2020, it seems that it is still possible for sites to detect whether or not Firefox is running in private mode, based on the fact that IndexedDB does not function when Firefox is running in private mode. There are a number of mainstream media outlets that seem to be using the technique to block users from browsing their site in private mode, or force them to login.

GitHub gist with sample code:
https://gist.github.com/jherax/a81c8c132d09cc354a0e2cb911841ff1

Working demo of above code:
https://output.jsbin.com/tazuwif

Bugzilla threads with more info:
https://bugzilla.mozilla.org/show_bug.cgi?id=781982
https://bugzilla.mozilla.org/show_bug.cgi?id=1506680

mti2935
  • 19,868
  • 2
  • 45
  • 64
1

The simple answer is no.

Simply detecting that history is not saved does not mean that private browsing mode is being used, it simply means that history is not being saved, something easy to configure in any browser.

Why would being logged into another service mean you are not using private browsing mode? I often use Facebook in private browsing mode on other peoples computers, as it means I don't have to log them out and it is an easy way to have my own session without losing their state.

Private browsing mode simply enables features that you can configure for yourself in normal mode. It enables several features at once for a temporary time period for convenience. There is no way to tell if someone is using private browsing mode or that they simply have those features enabled.

Sonny Ordell
  • 3,476
  • 9
  • 33
  • 56
  • I don't think this is really responsive or accurate. There are certainly heuristics for this, and web sites such as newspapers use them. In my use, they really do seem to be able to detect when I'm in private mode. The fact that they're heuristics doesn't mean that they don't work at all. –  Jun 11 '19 at 14:45