Browser sniffing


Skip navigation.

Site search

Site navigation

Details and download

Script test results

What it is and how it works

Although not a good technique, and far inferior to object detection, there are some times when it becomes necessary to detect a user's browser. These are usually when the support detect shows that a browser supports something, but in reality, it does not, or when you need to give specific information to users of specific browsers, like telling them how to change their security or privacy settings.

Most browsers (all of the ones that I care about) provide properties of the window.navigator object that give the full name of the browser and operating system. Of all of these, the userAgent is the most reliable, as most browsers do not put the correct information in the other properties. However, because many web developers use poor sniffing techniques and do not allow for all browsers, they often inadvertently shut minor browsers out. To combat this, many minor browsers allow users to change the userAgent information (known as spoofing) to make these sites think they are a more popular browser. In fact, even browsers like Internet Explorer allow you to change the userAgent header, if you are willing to modify the registry.

I have devoted much time to perfecting the browser sniffer to detect these browsers, even when they try to hide their identity. This defies the purpose of spoofing, so use it wisely, and do not shut browsers out, just because you don't know if they will work. Sniffing should only be used to avoid browser specific bugs. To perfect the browser sniffer, I look for other properties, often more uncommon ones, that the browsers provide. I will only attempt to detect a browser whose userAgent header has been changed through the browser's menus, not, for example, changing the Windows registry.

Specific browsers

KHTML/WebKit Konqueror allows users to input any userAgent string they want. However, in spite of this, it always provides the same vendor property: 'KDE'. For this reason, we must attempt to detect this before doing any userAgent detects. WebKit Safari can spoof (using the debug add-ons) and becomes completely unidentifiable. The important thing to note is that it will then be identified as Konqueror (which it is anyway), Gecko or Internet Explorer by this script. However, there are subtle differences that makes Safari stand out from these other browsers. It does not support document.all (unlike its Konqueror 2 predecessor, and more importantly, Internet Explorer) or navigator.taintEnabled like Gecko (tainting was only supported in Netscape 3, but Gecko browsers still support the method, it just always returns false). Checking for the taintEnabled method causes errors in Internet Explorer (because it is stupid!) so the check for document.all must be done first. I also check for document.childNodes to make sure the browser is advanced enough to be Safari, as there may be lesser browsers that do not support document.all or navigator.taintEnabled. WebKit OmniWeb 4.5+ is identical to Safari in every way (except its user agent, but that can spoof), except it also provides the 'accentColorName' property of the navigator object.

ICEbrowser can spoof, but it always provides the __ice_version property.

iCab 3- can spoof, but always provides the ScriptEngine method that returns a string containing 'InScript'.

HotJava must be discounted as a layers browser using its userAgent.

Escape 4 can spoof and identifies itself as Netscape 4, but has a few subtle differences, which I look for.

Escape/Evo 5 can spoof and identifies itself as MSIE 5 Mac, but it can be identified because it supports the savePreferences method of the navigator object, as well as both document.all and document.getElementById. It produces uncatchable errors if checking for document.childNodes, so the check for Escape 5 must come before the check for KHTML/WebKit browsers.

Omniweb 4.2- can spoof, and in fact allows users to input several navigator properties besides userAgent. For this reason it must be detected before any userAgent detects. However, it can easily be mis detected as HotJava, so I check if the navigator.accentColorName property exists - supported by OmniWeb but not HotJava - to distinguish between them. Other than that, OmniWeb 4.2- is detectable as a layers browser with a significant difference from the others.

Netscape 4 is the default layers browser.

Opera can spoof but always has the word 'Opera' in its userAgent.

Netgem NetBox, Open TV, and WebTV are easily detectable via their unchanging userAgent or appName properties. I assume the iPanel MicroBrowser is the same.

Gecko engine always provides the product property 'Gecko'.

Netfront uses different userAgent strings, and JavaScript objects on different devices. Normally the UA string contains "NetFront" but on PlayStation devices, it has "PSP" or "PLAYSTATION 3" in the appName. On PalmOS, the appName is "Blazer". Future versions try to replicate Gecko for all properties, but still have a few methods that Gecko does not have.

Clue browser supports document.getElementById but is not 5th generation.

The other browsers that can handle DHTML are in the Internet Explorer series.

This algorithm will fail if a browser that I do not know about is being used. That is highly possible. I'm sure that there are others that I do not know about. I am sure that there are some that this script can detect that you did not know about. This script will also fail if future versions of these browsers are released that behave differently to their ancestors. Every type of 'browser sniffer' will fail if that happens. That means that every time a new browser is released, you will have to rewrite every browser sniffer you use and update it for the new browser.

What the script gives me

Four variables:

The code for the browser:
The name of the browser:
The code for the operating system:
The name of the operating system:

The script source

This script can be downloaded and used as a JavaScript header file. I do not authorise its use for determining script support. It is only to be used according to the guidelines given above.

To download the script(s), see the script license, and check details like browser compatibility, use the links on the navigation panel at the top of this page.

What I have worked out (detects correctly, even if the browser is spoofing)

My script does not actually distinguish between Opera 4, 5 and 6, or between IE 5 and 6, or between the various Geckos, or between the various KHTMLs, but here's how to if you need to:

navigator.vendor == 'KDE' || ( document.childNodes && !document.all && !navigator.taintEnabled )
navigator.vendor == 'KDE'
Safari (see later)
document.childNodes && !document.all && !navigator.taintEnabled && !accentColorName
OmniWeb 4.5+
document.childNodes && !document.all && !navigator.taintEnabled && accentColorName
iCab 3-
window.ScriptEngine && ScriptEngine().indexOf('InScript') + 1
iCab 2-
window.ScriptEngine && ScriptEngine().indexOf('InScript') + 1 && !document.createElement
iCab 3
window.ScriptEngine && ScriptEngine().indexOf('InScript') + 1 && document.createElement
navigator.userAgent.toLowerCase().indexOf('hotjava') + 1 && typeof( navigator.accentColorName ) == 'undefined'
OmniWeb 4.2-
!HotJava && document.layers && !document.classes
Escape 4
document.layers && document.classes && !navigator.mimeTypes['*']
Netscape 4
document.layers && navigator.mimeTypes['*']
Escape/Evo 5
document.all && document.getElementById && navigator.savePreferences
navigator.userAgent.toLowerCase().indexOf('opera') + 1
Opera 4-
navigator.userAgent.toLowerCase().indexOf('opera') + 1 && !window.opera
Opera 5
window.opera && !window.print
Opera 6
window.opera && window.print && !document.childNodes
Opera 7+
window.opera && document.childNodes
navigator.appName.indexOf('WebTV') + 1
iPanel MicroBrowser - I'm guessing this one
navigator.userAgent.toLowerCase().indexOf( 'ipanel' ) + 1
Netgem NetBox
navigator.userAgent.toLowerCase().indexOf( 'netgem' ) + 1
navigator.userAgent.toLowerCase().indexOf( 'opentv' ) + 1
Clue Browser
None_of_the_above && document.getElementById && !document.childNodes
Netscape 6+, Mozilla and other Gecko
navigator.product == 'Gecko' && !navigator.savePreferences
Netscape 6, Mozilla 0.9- and reduced Gecko
navigator.product == 'Gecko' && !window.find && !navigator.savePreferences
Netscape 7+, Mozilla 1+ and advanced Gecko
navigator.product == 'Gecko' && window.find && !navigator.savePreferences
document.getElementById && ( ( yourBro.ualc.indexOf( 'netfront' ) + 1 ) || navigator.appName == 'Blazer' || ( navigator.product == 'Gecko' && navigator.savePreferences ) || ( navigator.appName.indexOf('PSP') + 1 ) || ( navigator.appName.indexOf('PLAYSTATION 3') + 1 ) )
Internet Explorer
None_of_the_above && document.all
Internet Explorer 4
None_of_the_above && document.all && !document.getElementById
Internet Explorer 5
None_of_the_above && document.getElementById && !document.compatMode
Internet Explorer 6
None_of_the_above && document.getElementById && document.compatMode && !window.XMLHttpRequest
Internet Explorer 7
None_of_the_above && document.getElementById && document.compatMode && window.XMLHttpRequest && !document.documentMode
Internet Explorer 8
None_of_the_above && document.getElementById && document.compatMode && window.XMLHttpRequest && document.documentMode
Internet Explorer 9
None_of_the_above && document.getElementById && document.compatMode && window.XMLHttpRequest && document.documentMode && window.ScriptEngineMajorVersion && window.ScriptEngineMajorVersion >= 9
Pocket Internet Explorer
None_of_the_above && window.ActiveXObject && navigator.userAgent.toLowerCase().indexOf( 'msie' ) + 1

The various variables that browsers provide (some browsers may produce errors).

These tests are designed to help you find objects that can be used with browser sniffing techniques.

This site was created by Mark "Tarquin" Wilton-Jones.
Don't click this link unless you want to be banned from our site.