Browser detection using the user agent

  • Revision slug: Browser_detection_using_the_user_agent
  • Revision title: Browser detection using the user agent
  • Revision id: 17919
  • Created:
  • Creator: teoli
  • Is current revision? No
  • Comment 516 words added

Revision Content

Serving different Web pages or services to different browsers is usually a bad idea. The Web is meant to be accessible to everyone, regardless of which browser or device they're using. There are ways to develop your web site to progressively enhance itself based on the availability of features rather than by targeting specific browsers.

But browsers and standards are not perfect, and there are still some edge cases where detecting the browser is needed. Using the user agent to detect the browser looks simple, but doing it well is in fact a very hard problem. This document will guide you in doing this as correctly as possible.

Important: It's worth re-iterating: it's very rarely a good idea to use user agent sniffing. You can almost always find a better, more broadly compatible way to solve your problem!

Considerations before using browser detection

When considering using the user agent string to detect which browser is being used, your first step is to try to avoid it if possible. Start by trying to identify why you want to do it.

Are you trying to work around a specific bug in some version of a browser?
Look, or ask, in specialized forums: you're unlikely to be the first to hit this problem. Also experts, or simply people with another point of view, can give you ideas for working around the bug. You can start by checking if this bug has been reported to the browser vendor; don't hesitate to asks on forum or to report it on their bug tracking system (Mozilla; WebKit; Opera) This step may seem unhelpful, but it is not! First, contrary to popular belief, browser makers pay attention to bug reports (though some may occasionally pass unnoticed through their triaging teams); second, analysis may hint about other work-arounds for the bug; third, without a bug report, the odds that the bug will be corrected in the future is lower.
Are you trying to check for the existence of a specific feature?
Your site needs to use a specific Web feature that some browsers don't yet support, and you want to send those users to an older Web site with fewer features but that you know will work. This is the worst reason to use user agent detection, because odds are eventually all the other browsers will catch up. You should do your best to avoid using user agent sniffing in this scenario.
Do you want to provide different HTML depending on which browser is being used?
This is usually a bad practice, but there are some cases in which this is necessary. In these cases, you should first analyze your situation to be sure it's really necessary. Can you prevent it by adding some non-semantic {{ HTMLElement("div") }} or {{ HTMLElement("span") }} elements? The difficulty of successfully using user agent detection is worth a few disruptions to the purity of your HTML. Also, rethink your design: can you use progressive enhancement or fluid layouts to help remove the need to do this?

Avoiding user agent detection

If you want to try to avoid using user agent detection, there are options in some cases!

Feature detection
Feature detection is where you don't try to figure out which browser is rendering your page, but instead you check to see if the specific feature you need is available. If it's not, you use a fallback. You should, of course, never use feature detection to try to determine which browser you're using, since other browsers may implement the feature in the future, but differently. Bugs caused by this can be insidiously hard to find and fix.
Progressive enhancement
This design technique involves developing your Web site in layers, using a bottom-up approach, starting with a simpler layer and improving the capabilities of the site in successive layers, each using more features.
Graceful degradation
This is a top-down approach in which you build the best possible site using all the features you want, then tweaking it to make it work on older browsers. This can be harder to do, and less effective, than progressive enhancement, but may be useful in some cases.

Which part of the user agent contains the information you are looking for

As there is no uniformity of the different part of the user agent string, this is the tricky part.

Browser Name

Most browser set the name and version in the format BrowserName/VersionNumber format, with the notable exception of Internet Explorer. But as the name is not the only information in a user agent string that is in that format, you can not discover the name of the browser, you can only check if the name you are looking for. But pay attention that some browsers are lying: Chrome for example reports both as Chrome and Safari. So to detect Safari you have to check for the Safari string and the absence of the Chrome string, Chromium often reports himself as Chrome too or Seamonkey sometimes reports himself as Firefox.

Also pay attention not to use a simple regular expression on the BrowserName, user agents also contains strings outside the Keyword/Value syntax. Safari & Chrome contains a string 'like Gecko', for instance.

  Must contains Must not contains  
Firefox Firefox/xyz Seamonkey/xyz  
Seamonkey Seamonkey/xyz    
Chrome Chrome/xyz Chromium/xyz  
Chromium Chromium/xyz    
Safari Safari/xyz Chrome/xyz or Chromium/xyz Safari gives two version number, one technical in the Safari/xyz token, one user-friendly in a Version/xyz token
Opera Opera/xyz   Pay attention to the position of the version number at Opera: since version 10 a new Version/xyz token has been added to contains it.
Internet Explorer ;MSIE xyz;   Internet Explorer doesn't put its name in the BrowserName/VersionNumber format

Of course, there is absolutely no guarantee that another browser will not hijack some of these things (like Chrome hijacked the Safari string in the past). That's why browser detection using the user agent string is unreliable and should be done only with the check of version number (hijacking of past versions is less likely).

Browser version

The browser version is often, but not always, put in the value part of the BrowserName/VersionNumber token in the User Agent String. This is of course not the case for Internet Explorer (who put the version number right after the MSIE token, and for Opera after version 10, which has added a Version/VersionNumber token.

Here again, be sure to take the right token for the browser you are looking for, as there is no guarantee that other will contain a valid number.

Rendering engine

As seen earlier, in most cases, looking for the rendering engine is a better way to go. It allows not to exclude less known browsers build on the same engine that famous ones. Browsers sharing a common rendering engine will display a page in the same way: it is often a fair assumption that what will work in one will work in the other.

There are five major rendering engines: Trident, Gecko, Presto, and WebKit. As sniffing the rendering engines names is common, a lot of user agents added other rendering names to trigger detection. It is therefore important to pay attention not to trigger false-positive when detecting the rendering engine.

  Must contains  
Gecko Gecko/xyz Pay attention, Gecko version is not necessarily stored in that token
WebKit AppleWebKit/xyz Pay attention, WebKit browsers add a 'like Gecko' string that may trigger false positive for Gecko if the detection is not careful.
Presto Opera/xyz  
Trident Trident/xyz Internet Explorer put this token in the comment part of the User Agent String

Rendering engine version

Most rendering engine put the version number in the RenderingEngine/VersionNumber token, with the notable exception of Gecko. Gecko, up to version 14 (?), put the version number in the comment part of the User Agent after the rv: string. From Gecko 14, for mobile version, it also put this value in the Gecko/version token (previous version put there the build date, then a fixed date called the GeckoTrail). Desktop version still don't store it there, though it may change in the future.

OS

The Operating System is given in most Useragent, it is an entry, that is a fixed string between two semi-colons, in the comment part of the User Agent. These strings are specific for each browsers. They indicates the OS, but also often its version and information on the relying hardware (32 or 64 bits, or Intel/PPC for Mac).

Like in all cases, these strings may change in the future, one should use them only in conjunction for the detection of already released browsers. A technological survey must be in place to adapt the script when new browser versions are coming out.

Mobile, Tablet or Desktop

The most common case of user agent sniffing is to determine which can of device the browser runs on. The goal is to serve a different HTML to different computer types. Rather than testing the browser name or the rendering engine, this method is more effective in preventing exclusion of new browsers or of old browsers used on new types of devices

Never assumes that a browser or a rendering engine must run only on one kind of device. Especially don't make different defaults for different browsers or rendering engines.

Also never use the OS token to define if a browser is on mobile, tablet or desktop. The OS may be used on different set of devices in the future (like Android which is not necessarily on Mobile, but also on Tablet and even on Desktop).

The major browsers vendors have converged in their way to indicate on which type of computer the browser runs:

  • Mozilla (Gecko, Firefox) adds a ;Mobile; (resp. ;Tablet;) token in the comment part of the User Agent. (The absence of such token indicates Desktop)
  • WebKit-based use the token Mobile outside the comment part (they use a "Mobile Safari" token).
  • Microsoft uses the token IEMobile/xyz in the comment part of the user agent string
  • Opera uses the Opera Mobi/xyz token in the comment part of the user agent string.

Today, looking for these strings are the only way to know that the device runs on a mobile device (resp. a tablet) before serving the HTML.

Revision Source

<p>Serving different Web pages or services to different browsers is usually a bad idea. The Web is meant to be accessible to everyone, regardless of which browser or device they're using. There are ways to develop your web site to progressively enhance itself based on the availability of features rather than by targeting specific browsers.</p>
<p>But browsers and standards are not perfect, and there are still some edge cases where detecting the browser is needed. Using the user agent to detect the browser looks simple, but doing it well is in fact a very hard problem. This document will guide you in doing this as correctly as possible.</p>
<div class="warning"><strong>Important:</strong> It's worth re-iterating: it's very rarely a good idea to use user agent sniffing. You can almost always find a better, more broadly compatible way to solve your problem!</div>
<h2>Considerations before using browser detection</h2>
<p>When considering using the user agent string to detect which browser is being used, your first step is to try to avoid it if possible. Start by trying to identify <strong>why</strong> you want to do it.</p>
<dl> <dt>Are you trying to work around a specific bug in some version of a browser?</dt> <dd>Look, or ask, in specialized forums: you're unlikely to be the first to hit this problem. Also experts, or simply people with another point of view, can give you ideas for working around the bug. You can start by checking if this bug has been reported to the browser vendor; don't hesitate to asks on forum or to report it on their bug tracking system (<a class=" link-https" href="https://bugzilla.mozilla.org" title="https://bugzilla.mozilla.org">Mozilla</a>; <a class=" external" href="http://bugs.webkit.org" title="http://bugs.webkit.org">WebKit</a>; <a class=" link-https" href="https://bugs.opera.com/" title="https://bugs.opera.com/">Opera</a>) This step may seem unhelpful, but it is not! First, contrary to popular belief, browser makers pay attention to bug reports (though some may occasionally pass unnoticed through their triaging teams); second, analysis may hint about other work-arounds for the bug; third, without a bug report, the odds that the bug will be corrected in the future is lower.</dd> <dt>Are you trying to check for the existence of a specific feature?</dt> <dd>Your site needs to use a specific Web feature that some browsers don't yet support, and you want to send those users to an older Web site with fewer features but that you know will work. This is the worst reason to use user agent detection, because odds are eventually all the other browsers will catch up. You should do your best to avoid using user agent sniffing in this scenario.</dd> <dt>Do you want to provide different HTML depending on which browser is being used?</dt> <dd>This is usually a bad practice, but there are some cases in which this is necessary. In these cases, you should first analyze your situation to be sure it's really necessary. Can you prevent it by adding some non-semantic {{ HTMLElement("div") }} or {{ HTMLElement("span") }} elements? The difficulty of successfully using user agent detection is worth a few disruptions to the purity of your HTML. Also, rethink your design: can you use progressive enhancement or fluid layouts to help remove the need to do this?</dd>
</dl>
<h2>Avoiding user agent detection</h2>
<p>If you want to try to avoid using user agent detection, there are options in some cases!</p>
<dl> <dt>Feature detection</dt> <dd>Feature detection is where you don't try to figure out which browser is rendering your page, but instead you check to see if the specific feature you need is available. If it's not, you use a fallback. You should, of course, never use feature detection to try to determine which browser you're using, since other browsers may implement the feature in the future, but differently. Bugs caused by this can be insidiously hard to find and fix.</dd> <dt>Progressive enhancement</dt> <dd>This design technique involves developing your Web site in layers, using a bottom-up approach, starting with a simpler layer and improving the capabilities of the site in successive layers, each using more features.</dd> <dt>Graceful degradation</dt> <dd>This is a top-down approach in which you build the best possible site using all the features you want, then tweaking it to make it work on older browsers. This can be harder to do, and less effective, than progressive enhancement, but may be useful in some cases.</dd>
</dl>
<h2>Which part of the user agent contains the information you are looking for</h2>
<p>As there is no uniformity of the different part of the user agent string, this is the tricky part.</p>
<h3>Browser Name</h3>
<p>Most browser set the name and version in the format <em>BrowserName/VersionNumber</em> format, with the notable exception of Internet Explorer. But as the name is not the only information in a user agent string that is in that format, you can not discover the name of the browser, you can only check if the name you are looking for. But pay attention that some browsers are lying: Chrome for example reports both as Chrome and Safari. So to detect Safari you have to check for the Safari string and the absence of the Chrome string, Chromium often reports himself as Chrome too or Seamonkey sometimes reports himself as Firefox.</p>
<p>Also pay attention not to use a simple regular expression on the BrowserName, user agents also contains strings outside the Keyword/Value syntax. Safari &amp; Chrome contains a string 'like Gecko', for instance.</p>
<table border="1" cellpadding="1" cellspacing="1" style="table-layout: fixed; width: 100%;"> <thead> <tr> <th scope="col"> </th> <th scope="col">Must contains</th> <th scope="col">Must not contains</th> <th scope="col"> </th> </tr> </thead> <tbody> <tr> <td>Firefox</td> <td>Firefox/xyz</td> <td>Seamonkey/xyz</td> <td> </td> </tr> <tr> <td>Seamonkey</td> <td>Seamonkey/xyz</td> <td> </td> <td> </td> </tr> <tr> <td>Chrome</td> <td>Chrome/xyz</td> <td>Chromium/xyz</td> <td> </td> </tr> <tr> <td>Chromium</td> <td>Chromium/xyz</td> <td> </td> <td> </td> </tr> <tr> <td>Safari</td> <td>Safari/xyz</td> <td>Chrome/xyz or Chromium/xyz</td> <td>Safari gives two version number, one technical in the Safari/xyz token, one user-friendly in a Version/xyz token</td> </tr> <tr> <td>Opera</td> <td>Opera/xyz</td> <td> </td> <td>Pay attention to the position of the version number at Opera: since version 10 a new Version/xyz token has been added to contains it.</td> </tr> <tr> <td>Internet Explorer</td> <td>;MSIE xyz;</td> <td> </td> <td>Internet Explorer doesn't put its name in the <em>BrowserName/VersionNumber</em> format</td> </tr> </tbody>
</table>
<p>Of course, there is absolutely no guarantee that another browser will not hijack some of these things (like Chrome hijacked the Safari string in the past). That's why browser detection using the user agent string is unreliable and should be done only with the check of version number (hijacking of past versions is less likely).</p>
<h3>Browser version</h3>
<p>The browser version is often, but not always, put in the value part of the <em>BrowserName/VersionNumber</em> token in the User Agent String. This is of course not the case for Internet Explorer (who put the version number right after the MSIE token, and for Opera after version 10, which has added a Version/<em>VersionNumber</em> token.</p>
<p>Here again, be sure to take the right token for the browser you are looking for, as there is no guarantee that other will contain a valid number.</p>
<h3>Rendering engine</h3>
<p>As seen earlier, in most cases, looking for the rendering engine is a better way to go. It allows not to exclude less known browsers build on the same engine that famous ones. Browsers sharing a common rendering engine will display a page in the same way: it is often a fair assumption that what will work in one will work in the other.</p>
<p>There are five major rendering engines: Trident, Gecko, Presto, and WebKit. As sniffing the rendering engines names is common, a lot of user agents added other rendering names to trigger detection. It is therefore important to pay attention not to trigger false-positive when detecting the rendering engine.</p>
<table border="1" cellpadding="1" cellspacing="1" style="table-layout: fixed; width: 100%;"> <thead> <tr> <th scope="col"> </th> <th scope="col">Must contains</th> <th scope="col"> </th> </tr> </thead> <tbody> <tr> <td>Gecko</td> <td>Gecko/xyz</td> <td>Pay attention, Gecko version is not necessarily stored in that token</td> </tr> <tr> <td>WebKit</td> <td>AppleWebKit/xyz</td> <td>Pay attention, WebKit browsers add a 'like Gecko' string that may trigger false positive for Gecko if the detection is not careful.</td> </tr> <tr> <td>Presto</td> <td>Opera/xyz</td> <td> </td> </tr> <tr> <td>Trident</td> <td>Trident/xyz</td> <td>Internet Explorer put this token in the <em>comment</em> part of the User Agent String</td> </tr> </tbody>
</table>
<h2>Rendering engine version</h2>
<p>Most rendering engine put the version number in the <em>RenderingEngine/VersionNumber</em> token, with the notable exception of Gecko. Gecko, up to version 14 (?), put the version number in the comment part of the User Agent after the <code>rv:</code> string. From Gecko 14, for mobile version, it also put this value in the <code>Gecko/version</code> token (previous version put there the build date, then a fixed date called the GeckoTrail). Desktop version still don't store it there, though it may change in the future.</p>
<h2>OS</h2>
<p>The Operating System is given in most Useragent, it is an entry, that is a fixed string between two semi-colons, in the comment part of the User Agent. These strings are specific for each browsers. They indicates the OS, but also often its version and information on the relying hardware (32 or 64 bits, or Intel/PPC for Mac).</p>
<p>Like in all cases, these strings may change in the future, one should use them only in conjunction for the detection of already released browsers. A technological survey must be in place to adapt the script when new browser versions are coming out.</p>
<h3>Mobile, Tablet or Desktop</h3>
<p>The most common case of user agent sniffing is to determine which can of device the browser runs on. The goal is to serve a different HTML to different computer types. Rather than testing the browser name or the rendering engine, this method is more effective in preventing exclusion of new browsers or of old browsers used on new types of devices</p>
<p>Never assumes that a browser or a rendering engine must run only on one kind of device. Especially don't make different defaults for different browsers or rendering engines.</p>
<p>Also never use the OS token to define if a browser is on mobile, tablet or desktop. The OS may be used on different set of devices in the future (like Android which is not necessarily on Mobile, but also on Tablet and even on Desktop).</p>
<p>The major browsers vendors have converged in their way to indicate on which type of computer the browser runs:</p>
<ul> <li>Mozilla (Gecko, Firefox) adds a ;Mobile; (resp. ;Tablet;) token in the comment part of the User Agent. (The absence of such token indicates Desktop)</li> <li>WebKit-based use the token Mobile outside the comment part (they use a "Mobile Safari" token).</li> <li>Microsoft uses the token IEMobile/xyz in the comment part of the user agent string</li> <li>Opera uses the Opera Mobi/xyz token in the comment part of the user agent string.</li>
</ul>
<p>Today, looking for these strings are the only way to know that the device runs on a mobile device (resp. a tablet) before serving the HTML.</p>
Revert to this revision