Categories:

Using the navigator object to detect client's browser

Last updated: January 20th, 15'

Until one browser remains standing on the web (if ever), browser detection will continue to be part of any good JavaScripter's life. Whether you're gliding a div across the screen or creating an image rollover, it's fundamental that only relevant browsers pick up on your code. In this tutorial we'll probe the navigator object of JavaScript, and show how to use it to perform browser detection, whether the subject is Firefox, Internet Explorer, Opera, etc.

The navigator object

The navigator object was conceived back in the days when Netscape Navigator reined supreme. These days it serves as much as an irony of Netscape's demise as way of probing browser information.

The navigator object of JavaScript contains the following core properties:

Properties Description
appCodeName The code name of the browser.
appName The name of the browser. In Firefox for example the returned value is "Netscape", while in IE10 and below, it's "Microsoft Internet Explorer" as can be expected. Starting in IE11+, however, the returned value of appName is also "Netscape".
appVersion Version information for the browser (ie: 5.0 (Windows)).
cookieEnabled Boolean that indicates whether the browser has cookies enabled.
language Returns the default language of the browser version (ie: en-US). NS and Firefox only.
maxTouchPoints The maximum number of simultaneous touch contacts supported by the device. IE10+ only.
mimeTypes[] An array of all MIME types supported by the client. NS and Firefox only.
onLine A Boolean that returns true if the browser is online, false if not. Note that different browsers have different minimum requirements when deciding if the browser is online, which may not accurately correlate to whether the browser is in fact able to access the web. In other words, you should not solely rely on the onLine property to detect whether the user is online.
platform[] The platform of the client's computer (ie: Win32).
plugins An array of all plug-ins currently installed on the client. NS and Firefox only.
systemLanguage Returns the default language of the operating system (ie: en-us). IE only.
userAgent String passed by browser as user-agent header. The userAgent value for IE9 is "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1;)" while for Mozilla Firefox 35, it's "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0".

Starting in IE11+, the userAgent return value is a drastic departure from all older versions' of IE. In IE11 Windows 8 the returned string is "Mozilla/5.0 (Windows NT 6.3; Trident/7.0; rv:11.0) like Gecko". This is different from previous versions on the following notable ways:

  • The compatible ("compatible") and browser ("MSIE") keywords have been removed, meaning you can no longer just look for "MSIE" in the userAgent to sniff out IE in IE11 or above browsers.
  • The version of the browser is now reported by a new revision ("rv") keyword.

You can probe the userAgent property for mobile browsers such as iPhone, iPad, or Android. The following variable returns true if the user is using one of the following mobile browsers:

//returns true if user is using one of the following mobile browsers
var ismobile=navigator.userAgent.match(/(iPad)|(iPhone)|(iPod)|(android)|(webOS)/i)

userLanguage Returns the preferred language setting of the user (ie: en-ca). IE only.

Let's see exactly what these properties reveal of the browser you're currently using:

At a glance

At a glance at the above table, you may be swayed towards turning to the following two properties to do your browser detection bidding:

navigator.appName
navigator.appVersion

After all, you are trying to detect a browser's name and version right? However, they both will most likely mislead you. In browsers such as various versions of Netscape and Firefox, these two properties return simply "Netscape" for appName, and 5.0 for appVersion without any further distinction for Firefox and its version, and hence are pretty much useless in the real world. For example, in both Firefox 5.x and Firefox 35, these two properties return:

appName: Netscape
appVersion: 5.0 (Windows)

We need to turn to a property that's more thorough in its investigative work if we want more consistency and accuracy, and that turns out to be navigator.userAgent.

Detecting Firefox x.x

In Firefox 5.0 for example, the userAgent property reads:

UserAgent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:5.0) Gecko/20100101 Firefox/5.0

And in Firefox 35:

Mozilla/5.0 (Windows NT 6.1; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0

The detail we're interested in apparently lies at the very end, or Firefox/35.0 for example. Different versions of Firefox will contain a different version number, but the pattern is consistent enough. The part we're interested in occurs after the string "Firefox/", or the exact version number. There are many ways to get to it using either standard String or RegExp methods- I'm opting for the later here:

<script type="text/javascript">
//Note: userAgent in FF2.0.0.13 WinXP returns: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.13) Gecko/20080311 Firefox/2.0.0.13
// userAgent in FF35 Win7 returns: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0

if (/Firefox[\/\s](\d+\.\d+)/.test(navigator.userAgent)){ //test for Firefox/x.x or Firefox x.x (ignoring remaining digits);
 var ffversion=new Number(RegExp.$1) // capture x.x portion and store as a number
 if (ffversion>=35)
document.write("You're using FF 35 or above")
 else if (ffversion>=5)
document.write("You're using FF 5.x or above")
 else if (ffversion>=4)
document.write("You're using FF 4.x or above")
 else if (ffversion>=3)
document.write("You're using FF 3.x or above")
 else if (ffversion>=2)
document.write("You're using FF 2.x")
 else if (ffversion>=1)
document.write("You're using FF 1.x")
}
else
 document.write("n/a")

</script>

Output:

Basically, I'm capturing just the versonMajor.versionMinor portion of the full version number of Firefox (ie: 2.0.0.13 becomes simply 2.0), and using that as basis to detect the various versions of Firefox. Delving any deeper, and the returned version may no longer be a number but a string (ie: 2.0.0), which makes numeric comparisons cumbersome.

Detecting IE x.x

In IE until the advent of IE11, the token "MSIE" exist inside the userAgent property that tells us the pedigree of the browser. In IE 7.0 for example, the userAgent property reads:

UserAgent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; .NET CLR 2.0.50727)

However, starting in IE11, the userAgent return value takes a drastic departure from all older versions' of IE. For example in IE11 Windows 8 the returned string is:

UserAgent: Mozilla/5.0 (Windows NT 6.3; Trident/7.0; rv:11.0) like Gecko

This is different from previous versions in the following notable ways:

  • The compatible ("compatible") and browser ("MSIE") keywords have been removed, meaning you can no longer just look for "MSIE" in the userAgent to sniff out IE in IE11 or above browsers.
  • The version of the browser is now reported by a new revision ("rv") keyword.

Details of the change is discussed in this IE blog post. With the dramatic change, it means testing for IE now needs to take two separate routes, one that looks for the "MSIE" token and version number that follows, and the other, the version number contained inside the "rv" token where the "Trident" token exists inside the userAgent string.

Note that some variants of older IE versions also contain "Trident" in its userAgent string, so do not rely just on "Trident" alone to separate IE11+ from the rest of the herd- it's only the presence of BOTH "Trident' and a "rv" token that uniquely indicates this is a IE11 or above browser.

The following detection scheme takes into account this and sniffs out any version of IE:

<script type="text/javascript">
//userAgent in IE7 WinXP returns: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; .NET CLR 2.0.50727)
//userAgent in IE11 Win7 returns: Mozilla/5.0 (Windows NT 6.3; Trident/7.0; rv:11.0) like Gecko

if (navigator.userAgent.indexOf('MSIE') != -1)
 var detectIEregexp = /MSIE (\d+\.\d+);/ //test for MSIE x.x
else // if no "MSIE" string in userAgent
 var detectIEregexp = /Trident.*rv[ :]*(\d+\.\d+)/ //test for rv:x.x or rv x.x where Trident string exists

if (detectIEregexp.test(navigator.userAgent)){ //if some form of IE
 var ieversion=new Number(RegExp.$1) // capture x.x portion and store as a number
 if (ieversion>=12)
  document.write("You're using IE12 or above")
 else if (ieversion>=11)
  document.write("You're using IE11 or above")
 else if (ieversion>=10)
  document.write("You're using IE10 or above")
 else if (ieversion>=9)
  document.write("You're using IE9 or above")
 else if (ieversion>=8)
  document.write("You're using IE8 or above")
 else if (ieversion>=7)
  document.write("You're using IE7.x")
 else if (ieversion>=6)
  document.write("You're using IE6.x")
 else if (ieversion>=5)
  document.write("You're using IE5.x")
}
else{
 document.write("n/a")
}
</script>

Output:

If you're only interested in detecting IE11 or greater, you can simply test for the presence of "Trident" while at the same time the absense of "MSIE" inside userAgent:

var ie11andabove = navigator.userAgent.indexOf('Trident') != -1 && navigator.userAgent.indexOf('MSIE') == -1 // IE11 or above Boolean

Or, should you only be interested in detecting IE browsers less than 11, the following will do:

var ie10andbelow = navigator.userAgent.indexOf('MSIE') != -1 // IE10 or below Boolean

Detecting Opera 15 and above

Opera starting in Opera 15+ on both desktop and Android uses the Chromium engine under their hood (the same engine that powers Google Chrome), and with the brain transplant, now returns a userAgent string that's more Chrome than Opera. In Opera 25 for example, this is the returned string:

UserAgent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0.2125.101 Safari/537.36 OPR/25.0.1614.50

Straight from Opera itself: On all platforms, the digits after "OPR/" tell you version and minor version number - in this case "25.0" (The subsequent numbers are internal identifiers and build numbers.). Opera 15+ for Android contains the string "Mobile" and also contains "OPR/" followed by version number, as both Opera 15+ for desktop and Android are based on Chromium 28.

This means to detect if the user is using Opera 15+, we can simply look for the "OPR/" token inside userAgent, and to detect the specific version, parse out the floating point number that follows. Here's an example of each:

var opera15andabove = navigator.userAgent.indexOf('OPR/') != -1 // Opera 15+ Boolean

var opera15andabovever = /OPR\/(\d+\.\d+)/i.test(navigator.userAgent) // test and capture Opera 15+ version
if (opera15andabovever){
 var operaver = new Number(RegExp.$1) // contains exact Opera15+ version, such as 25 for Opera 25.0
 document.write("You're using Opera" + operaver)
}
else{
 document.write("n/a")
}

Output:

Detecting old versions of Opera (pre Opera 15)

In Opera pre version 15, there exists a property window.opera that returns true to quickly filter out those browsers as a group. However, getting the exact version gets a lot more confounding, stemming from the browser's past split personality. You see, Opera 8 and below by default identifies itself as IE6 (or lower) in the navigator object. Users can override this setting under "Edit Site Settings" in the toolbar to identify as Opera or even another browser instead. Starting in Opera 9, the browser regains its confidence and identifies by default as itself, Opera, though users can still modify this setting manually in the toolbar. The bottom line is, Opera can appear as either Opera, Internet Explorer, or another browser within a designated list in the navigator object.

Lets take a look at what navigator.userAgent in Opera 8.5 returns depending on what it has chosen to identify itself as (whether automatically or manually):

As IE6: Mozilla/4.0 (compatible; MSIE 6.0; Windows XP) Opera 8.5 [en]
As Moz5: Mozilla/5.0 (Windows XP; U) Opera 8.5 [en]
As Opera: Opera/8.5 (Windows XP; U) [en]

Notice how if it's set to identify as IE, MSIE 6.0 appears within the string, while if set to identify as Mozilla, Mozilla/5.0 appears instead. As Opera itself, Opera/8.5 appears. In all three cases, the one commonality that we can exploit to actually detect Opera and its true version regardless of which identify it's decided to take on is the string "Opera x.x" or "Opera/x.x" within navigator.userAgent. In other words, there are two versions of the target string we need to be aware of. With that said, here's how you might go about testing for a specific version of Opera, which turns out to be no different than the technique used for detecting, say, Firefox:

<script type="text/javascript">
//Note: userAgent in Opera9.24 WinXP returns: Opera/9.24 (Windows NT 5.1; U; en)
//         userAgent in Opera 8.5 (identified as IE) returns: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 8.50 [en]
//         userAgent in Opera 8.5 (identified as Opera) returns: Opera/8.50 (Windows NT 5.1; U) [en]

if (/Opera[\/\s](\d+\.\d+)/.test(navigator.userAgent)){ //test for Opera/x.x or Opera x.x (ignoring remaining decimal places);
 var oprversion=new Number(RegExp.$1) // capture x.x portion and store as a number
 if (oprversion>=10)
  document.write("You're using Opera 10.x or above")
 else if (oprversion>=9)
  document.write("You're using Opera 9.x")
 else if (oprversion>=8)
  document.write("You're using Opera 8.x")
 else if (oprversion>=7)
  document.write("You're using Opera 7.x")
 else
  document.write("n/a")
}
else
 document.write("n/a")
</script>

Output:

Conclusion

We've seen how to use navigator to detect the browser type of your visitors. If the potential pitfalls and complexity of usage of it is a little too much for you, an alternative is to use Object Detection. Whichever method you choose, just be sure to choose one!