| function retry(isDone, next) { | |
| var current_trial = 0, max_retry = 50, interval = 10, is_timeout = false; | |
| var id = window.setInterval( | |
| function() { | |
| if (isDone()) { | |
| window.clearInterval(id); | |
| next(is_timeout); | |
| } | |
| if (current_trial++ > max_retry) { | |
| window.clearInterval(id); | |
| is_timeout = true; | |
| next(is_timeout); | |
| } | |
| }, | |
| 10 | |
| ); | |
| } | |
| function isIE10OrLater(user_agent) { | |
| var ua = user_agent.toLowerCase(); | |
| if (ua.indexOf('msie') === 0 && ua.indexOf('trident') === 0) { | |
| return false; | |
| } | |
| var match = /(?:msie|rv:)\s?([\d\.]+)/.exec(ua); | |
| if (match && parseInt(match[1], 10) >= 10) { | |
| return true; | |
| } | |
| return false; | |
| } | |
| function detectPrivateMode(callback) { | |
| var is_private; | |
| if (window.webkitRequestFileSystem) { | |
| window.webkitRequestFileSystem( | |
| window.TEMPORARY, 1, | |
| function() { | |
| is_private = false; | |
| }, | |
| function(e) { | |
| console.log(e); | |
| is_private = true; | |
| } | |
| ); | |
| } else if (window.indexedDB && /Firefox/.test(window.navigator.userAgent)) { | |
| var db; | |
| try { | |
| db = window.indexedDB.open('test'); | |
| } catch(e) { | |
| is_private = true; | |
| } | |
| if (typeof is_private === 'undefined') { | |
| retry( | |
| function isDone() { | |
| return db.readyState === 'done' ? true : false; | |
| }, | |
| function next(is_timeout) { | |
| if (!is_timeout) { | |
| is_private = db.result ? false : true; | |
| } | |
| } | |
| ); | |
| } | |
| } else if (isIE10OrLater(window.navigator.userAgent)) { | |
| is_private = false; | |
| try { | |
| if (!window.indexedDB) { | |
| is_private = true; | |
| } | |
| } catch (e) { | |
| is_private = true; | |
| } | |
| } else if (window.localStorage && /Safari/.test(window.navigator.userAgent)) { | |
| try { | |
| window.localStorage.setItem('test', 1); | |
| } catch(e) { | |
| is_private = true; | |
| } | |
| if (typeof is_private === 'undefined') { | |
| is_private = false; | |
| window.localStorage.removeItem('test'); | |
| } | |
| } | |
| retry( | |
| function isDone() { | |
| return typeof is_private !== 'undefined' ? true : false; | |
| }, | |
| function next(is_timeout) { | |
| callback(is_private); | |
| } | |
| ); | |
| } |
| <!DOCTYPE html> | |
| <html> | |
| <head> | |
| <meta charset="utf-8"> | |
| </head> | |
| <body> | |
| <div id="result"></div> | |
| <script src="detect-private-browsing.js"></script> | |
| <script> | |
| detectPrivateMode( | |
| function(is_private) { | |
| document.getElementById('result').innerHTML = typeof is_private === 'undefined' ? 'cannot detect' : is_private ? 'private' : 'not private'; | |
| } | |
| ); | |
| </script> | |
| </body> | |
| </html> |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
thelinuxlich
commented
Oct 21, 2014
|
Fantastic! It works! |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
AndreSchwarzer
commented
Jan 21, 2015
|
Doesn't work in chrome :( |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
apastuhov
Jun 1, 2015
I tried to test in Chrome and IE 11. Your script return "private" even when it is not private.
apastuhov
commented
Jun 1, 2015
|
I tried to test in Chrome and IE 11. Your script return "private" even when it is not private. |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
alexesDev
Aug 25, 2015
Eslint check...
2:41 error interval is defined but never used no-unused-vars
40:15 error e is defined but never used no-unused-vars
90:16 error is_timeout is defined but never used no-unused-vars
alexesDev
commented
Aug 25, 2015
|
Eslint check...
|
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
yukulele
commented
Jan 5, 2016
|
how it works? |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
chickenwing
commented
Feb 7, 2016
|
hmm, could this be expanded to work in the edge browser? |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
sundip111
Apr 5, 2016
Awesome, works in all major browsers on both desktop and mobile.
Modify "isIE10OrLater" function as following for it to work with Edge browser:
function isIE10OrLater(user_agent) { var ua = user_agent.toLowerCase(); if (ua.indexOf('msie') === 0 && ua.indexOf('trident') === 0) { return false; } var match = /(?:msie|rv:)\s?([\d\.]+)/.exec(ua); if (match && parseInt(match[1], 10) >= 10) { return true; } var edge = /edge/.exec(ua); if(edge && edge[0] == "edge"){ return true; } return false; }
sundip111
commented
Apr 5, 2016
|
Awesome, works in all major browsers on both desktop and mobile. Modify "isIE10OrLater" function as following for it to work with Edge browser:
|
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
jimmywarting
May 5, 2016
Is userAgent sniffing good? how about:
var isSafari = /constructor/i.test(window.HTMLElement);
var isFF = 'MozAppearance' in document.documentElement.style;
var isIE10OrLater = document.body.style.msTouchAction !== undefined;From: http://browserhacks.com
Btw, i ended up with 1/4 of that code using other methods: https://jsfiddle.net/Lj2fs5kr/
tested in latest Chrome, FF, Safari everything is good there. Don't have IE on Mac
I think you are overusing try/catch more then necessary...?
Also found something about InPrivateFilteringEnabled in IE, maybe that could be to any use?
Update: tried InPrivateFilteringEnabled in edge 13, didn't work
jimmywarting
commented
May 5, 2016
•
|
Is userAgent sniffing good? how about: var isSafari = /constructor/i.test(window.HTMLElement);
var isFF = 'MozAppearance' in document.documentElement.style;
var isIE10OrLater = document.body.style.msTouchAction !== undefined;From: http://browserhacks.com
|
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
radyk
Jun 1, 2016
https://jsfiddle.net/Lj2fs5kr/
How do I use this above to test at the appropriate point in my forum. I need something like this as a test but I have no idea how to actually use this code in the real world. I can determine where to test but not how to call this code.
radyk
commented
Jun 1, 2016
|
https://jsfiddle.net/Lj2fs5kr/ How do I use this above to test at the appropriate point in my forum. I need something like this as a test but I have no idea how to actually use this code in the real world. I can determine where to test but not how to call this code. |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
slonoed
Jun 30, 2016
This line in FF incognito raise InvalidStateError
https://gist.github.com/cou929/7973956#file-detect-private-browsing-js-L48
It looks like error happened in different thread. How catch it?
slonoed
commented
Jun 30, 2016
|
This line in FF incognito raise InvalidStateError |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
dev0x10
Oct 3, 2016
https://gist.github.com/cou929/7973956#file-detect-private-browsing-js-L48
should has listener
db.onError = function(e) { //indexedb is not available here }
Ref: https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API/Using_IndexedDB
dev0x10
commented
Oct 3, 2016
•
|
https://gist.github.com/cou929/7973956#file-detect-private-browsing-js-L48 should has listener Ref: https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API/Using_IndexedDB |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
charltoons
Jan 13, 2017
@slonoed You can catch the error by returning true in onerror. That one took me a few hours.
charltoons
commented
Jan 13, 2017
|
@slonoed You can catch the error by returning |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
kylestev
commented
Jan 14, 2017
•
|
@charltoons Glad I saw your comment! Thanks for saving me a few hours |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
jonathanlermitage
commented
Feb 22, 2017
|
Doesn't work if you use uBlock Origin :) |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
bkstorm
commented
Mar 28, 2017
|
It works well with Chrome, Firefox and Safari. Good job |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
Vamshidharredy
commented
Mar 29, 2017
|
Broken for the latest Chrome. Chrome 57. |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
Vadimgorlenko
Apr 12, 2017
Works fine for me in latest Chrome and FF (Win 10), but does not work in Edge
Vadimgorlenko
commented
Apr 12, 2017
|
Works fine for me in latest Chrome and FF (Win 10), but does not work in Edge |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
lucasrodriguex
commented
Apr 24, 2017
|
Doesn't work with Chrome version 57+ |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
cesky84
commented
Apr 27, 2017
|
Doesn't work with FF 53 on mac return only private result |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
rohankhudedev
Jun 21, 2017
i did testing on some latest browser versions
Working-
Firefox - 54(latest), 53
Chrome - 58(latest)
Safari - 6.0.2, 5.1
IE - 11, 10
Opera - 45(latest)
Not working on -
UC browser - 11.3(latest)
rohankhudedev
commented
Jun 21, 2017
•
|
i did testing on some latest browser versions Working- Firefox - 54(latest), 53 Not working on - UC browser - 11.3(latest) |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
PunKeel
Jul 8, 2017
Safari throws an error when cookies are disabled globally (private mode or not) because it also breaks the localStorage.
The script aborts, and callback is never called :-(
> window.localStorage; console.log("hello");
< SecurityError (DOM Exception 18): The operation is insecure.
The fix: use a try-catch to interact with the localStorage
Bonus (thanks to @jherax): use navigator.cookieEnabled to detect if cookies are enabled. cf https://gist.github.com/jherax/a81c8c132d09cc354a0e2cb911841ff1
My fix, which might not work in every cases (but works fine for me): check if cookies are enabled before checking if localStorage is available:
- } else if (window.localStorage && /Safari/.test(window.navigator.userAgent)) {
+ } else if (/Safari/.test(window.navigator.userAgent) && navigator.cookieEnabled && window.localStorage) {
PunKeel
commented
Jul 8, 2017
•
|
Safari throws an error when cookies are disabled globally (private mode or not) because it also breaks the localStorage.
The fix: use a try-catch to interact with the localStorage Bonus (thanks to @jherax): use My fix, which might not work in every cases (but works fine for me): check if cookies are enabled before checking if localStorage is available: - } else if (window.localStorage && /Safari/.test(window.navigator.userAgent)) {
+ } else if (/Safari/.test(window.navigator.userAgent) && navigator.cookieEnabled && window.localStorage) { |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
BlueCutOfficial
Jul 25, 2017
Microsoft Edge passes the case for Safari.
Add this at the top of Safari case block :
if (!window.indexedDB && (window.PointerEvent || window.MSPointerEvent)) {
is_private = true;
}
No problem for Firefox / Chrome / Safari, nice job ! :)
BlueCutOfficial
commented
Jul 25, 2017
•
|
Microsoft Edge passes the case for Safari.
No problem for Firefox / Chrome / Safari, nice job ! :) |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
JessicaYeh
Aug 16, 2017
On iOS 11 Safari (and probably the new version of desktop Safari too? but didn't check that one), that trick of seeing if window.localStorage.setItem('test', 1); throws an error no longer works, because it no longer throws an error, and it also properly sets the localStorage item. Has anyone figured out any other way to check for private browsing mode in the new versions of Safari?
JessicaYeh
commented
Aug 16, 2017
|
On iOS 11 Safari (and probably the new version of desktop Safari too? but didn't check that one), that trick of seeing if |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
N1CHTN3BIH
commented
Sep 13, 2017
|
IE and Mozilla is returning private, but its not. |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
Maykonn
commented
Sep 27, 2017
|
@JessicaYeh on desktop version 11 not works more too. |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
Maykonn
commented
Oct 6, 2017
•
|
On Firefox ESR 53.0 not working. The script always returns as private. |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
Maykonn
Oct 6, 2017
I asked a question on Stackoverflow with more details about Firefox specific errors, here.
Maykonn
commented
Oct 6, 2017
|
I asked a question on Stackoverflow with more details about Firefox specific errors, here. |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
forberg
Oct 6, 2017
@Maykonn Seems like navigator.doNotTrack is not null in Safari private mode on iOS
forberg
commented
Oct 6, 2017
•
|
@Maykonn Seems like |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
jdc20181
Oct 15, 2017
Seems to be giving a false "Not private" - Meaning it should say private but it isn't - Using GeckFX (FireFox) .NET Control, I have the appropriate configurations for private mode, I just don't think its compatible with FF- Information on what I am using: https://bitbucket.org/geckofx/geckofx-45.0/issues/94/private-browsing
Not sure if its a JS issue or its something with the control/engine itself. My guess is it has something to do with the JS, with how it is detecting it via the code - or the version fo the engine itself although that should be ok.
jdc20181
commented
Oct 15, 2017
|
Seems to be giving a false "Not private" - Meaning it should say private but it isn't - Using GeckFX (FireFox) .NET Control, I have the appropriate configurations for private mode, I just don't think its compatible with FF- Information on what I am using: https://bitbucket.org/geckofx/geckofx-45.0/issues/94/private-browsing Not sure if its a JS issue or its something with the control/engine itself. My guess is it has something to do with the JS, with how it is detecting it via the code - or the version fo the engine itself although that should be ok. |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
Maykonn
Oct 24, 2017
I'm testing in various FF versions and from version 52 below don't working. Always returning as private browsing.
Safari latest version don't working too. I'm making tests with navigator.doNotTrack @forberg, thanks.
Maykonn
commented
Oct 24, 2017
|
I'm testing in various FF versions and from version 52 below don't working. Always returning as private browsing. |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
mtage70
Oct 27, 2017
navigator.doNotTrack is just a Safari feature that asks sites not to track the user, it can be opted into by going to safari->preferences->privacy. navigator.doNotTrack is not null if the user has checked that option, it is not indicative of whether the user is in private mode or not.
I'm still investigating how to detect private browsing in Safari, if anyone else is interested in this feature we should join forces
mtage70
commented
Oct 27, 2017
|
navigator.doNotTrack is just a Safari feature that asks sites not to track the user, it can be opted into by going to safari->preferences->privacy. navigator.doNotTrack is not null if the user has checked that option, it is not indicative of whether the user is in private mode or not. |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
unlox775
Nov 29, 2017
Note: this does not seem to detect private browsing for iOS 11 Safari. It detects find in iOS 10 and 9 Safari.
unlox775
commented
Nov 29, 2017
•
|
Note: this does not seem to detect private browsing for iOS 11 Safari. It detects find in iOS 10 and 9 Safari. |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
ckimy
Nov 30, 2017
Guys I found a solution.
You can detect private browsing in iOS 11 using below code.
No matter user's DNT option is checked or not, you can detect private browsing mode properly.
var isPrivate = false;
try {
window.openDatabase(null, null, null, null);
} catch (_) {
isPrivate = true;
}
alert((isPrivate ? 'You\'re' : 'You aren\'t') + ' in private browsing mode');
It worked for me perfectly. If it doesn't, please let me know.
ckimy
commented
Nov 30, 2017
|
Guys I found a solution.
It worked for me perfectly. If it doesn't, please let me know. |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
yimaneilicj
commented
Dec 15, 2017
|
@ckimy Think you very much! Let's dance! |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
yimaneilicj
commented
Dec 15, 2017
|
@ckimy This code does not work in ios10 above |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
dkuryakin
Dec 19, 2017
Hey, guys! There is my own version of snippet, based on original gist and some comments.
Check this out: https://jsfiddle.net/n0hnu5te/1/
It works for me in:
- IE11
- Chrome 63.0
- Mobile Chrome 62.0 (Android)
Let's test it on different devices/oses/browsers!
dkuryakin
commented
Dec 19, 2017
•
|
Hey, guys! There is my own version of snippet, based on original gist and some comments. It works for me in:
Let's test it on different devices/oses/browsers! |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
ckimy
Dec 21, 2017
@yimaneilicj Of course, this snippet is only for ios11. You can combine this snippet with another library/modules for other browsers. @dkuryakin had done this job for us! :)
ckimy
commented
Dec 21, 2017
•
|
@yimaneilicj Of course, this snippet is only for ios11. You can combine this snippet with another library/modules for other browsers. @dkuryakin had done this job for us! :) |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
smarajitdasgupta
Jan 11, 2018
Does anyone have a snippet that detects private mode on Safari on iOS11 as well as older Safari?
Update: Here is a pen that attempts to combine the storage and openDatabase try-catch blocks.
https://codepen.io/anon/pen/zpMZjp
The test window.openDatabase(null, null, null, null)
is not expected to throw an exception in Safari non-private browser mode, but it does (exception code 18).
In Safari new versions (11+ or iOS11+ Safari) normal browser mode, the second test (for openDatabase) enters the catch and isPrivate gets set to true. So, in Safari 11+ non-private mode is also detected as private mode. Anyone with a working solution on a server? It seems to work as expected in localhost, but window.openDatabase(null, null, null, null) throws exception both in normal and private mode when hosted in some server, as can be seen in the pen.
smarajitdasgupta
commented
Jan 11, 2018
•
|
Does anyone have a snippet that detects private mode on Safari on iOS11 as well as older Safari? Update: Here is a pen that attempts to combine the storage and openDatabase try-catch blocks. The test In Safari new versions (11+ or iOS11+ Safari) normal browser mode, the second test (for openDatabase) enters the catch and isPrivate gets set to true. So, in Safari 11+ non-private mode is also detected as private mode. Anyone with a working solution on a server? It seems to work as expected in localhost, but |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
gaplyk
Mar 8, 2018
IE can return true when it's not when you have your restriction on your policy to disable indexedDB
gaplyk
commented
Mar 8, 2018
|
IE can return true when it's not when you have your restriction on your policy to disable indexedDB |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
mtage70
Apr 17, 2018
I've noticed in Safari 11 normal browsing mode window.openDatabase(null, null, null, null) will throw an exception if a user has just cleared their history and refreshed.
mtage70
commented
Apr 17, 2018
|
I've noticed in Safari 11 normal browsing mode |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
bigmike7801
May 7, 2018
I'm using Safari 11.1 (11605.1.33.1.4) on OSX 10.11.6 and am getting "not private" when using a private window.
bigmike7801
commented
May 7, 2018
|
I'm using Safari 11.1 (11605.1.33.1.4) on OSX 10.11.6 and am getting "not private" when using a private window. |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
bigmike7801
commented
May 8, 2018
•
|
I switched line 82 to "true" and that seemed to fix it for me. |
Fantastic! It works!