32

I found the following code to detect a desktop browser. But the method also detects some mobile browsers. How can I detect only desktop browsers like Safari, IE, Firefox, Opera etc?

is_desktopBrowser : function() {
    var ua = navigator.userAgent.toLowerCase();

    var rwebkit = /(webkit)[ \/]([\w.]+)/;
    var ropera = /(opera)(?:.*version)?[ \/]([\w.]+)/;
    var rmsie = /(msie) ([\w.]+)/;
    var rmozilla = /(mozilla)(?:.*? rv:([\w.]+))?/;

    var match = rwebkit.exec(ua) ||
            ropera.exec(ua) ||
            rmsie.exec(ua) ||
            ua.indexOf("compatible") < 0 && rmozilla.exec(ua) ||
            [];

    return { browser: match[1] || "", version: match[2] || "0" };
},
dgvid
  • 26,293
  • 5
  • 40
  • 57
fabian
  • 5,433
  • 10
  • 61
  • 92
  • 1
    Use the search feature on Stack overflow. For each browser you're trying to detect, there're several answer already. – Rob W Nov 03 '11 at 13:34
  • 1
    Just a double check here, you're doing this because you can't detect a certain feature? – scottheckel Nov 03 '11 at 13:35
  • 3
    Browser detection is the devil, don't ever do it. – Raynos Nov 03 '11 at 13:38
  • @Raynos There are reasons,,, for example advertising a desktop browser extensions (my case) – David Callanan Feb 17 '20 at 18:17
  • @Raynos User-Agent sniffing is the real devil. Definitely don't do that on the client side when you have many other tools at your disposal, such as testing for the existence of certain functions/mehtods (i.e. feature detection - which may amount to browser detection, but is much more robust and future-proof). – Jake Jan 28 '23 at 03:00
  • @DavidCallanan Might your browser extensions be available for more than one browser - e.g. Edge and Chrome are both now Chromium-based, as is almost every other browser apart from Firefox - and is there a more accurate way of detecting that? – Jake Jan 28 '23 at 03:00
  • @Jake That's a good point. It would be nice if browsers which supported an extension API would expose some way of checking this. (e.g. `window.supportsChromiumExtensionStandard` etc.) – David Callanan Jan 29 '23 at 12:56

10 Answers10

30

jQuery.browser can be helpful when trying to figure out which browser. jQuery.browser was removed in jQuery 1.9.

I believe it is based on navigator.UserAgent, however navigator.UserAgent can tell you the OS on its own if you want.

Try this:

var isMobile = navigator.userAgent.match(/(iPad)|(iPhone)|(iPod)|(android)|(webOS)/i)

source

Jeffrey C
  • 364
  • 4
  • 13
sky-dev
  • 6,190
  • 2
  • 33
  • 32
  • 8
    `jQuery.browser` is deprecated in jQuery. Can't use it anymore. – tim Apr 22 '13 at 21:10
  • @DaanHeskes There's good reason for this, browser UA detecting that jQuery.browser is doing is a bad idea because years from now everyone that is using FirefoxOS, Ubuntuphone, blackberry/blueberryphone, MSEdgeTablet10.5, supernewphone1.0, or whatever other devices are popular, will not be detected. If you want to do something on smaller screen mobile devices, by all means do so... without detecting each possible OS individually! https://developer.mozilla.org/en-US/docs/Web/API/Screen – NoBugs Feb 12 '17 at 08:57
19

I check for

('ontouchstart' in window)

since that will tell me if I'm on a touch capable device. Of course that also returns true for an ipad, which might not be considered a "mobile device", but then I just check window.width for layout purposes.

tim
  • 3,823
  • 5
  • 34
  • 39
  • 26
    This approach returns false positive for touch-enabled desktops such as Microsoft's Surface and numerous other notebooks with Windows 8. – Andrew Sklyarevsky Mar 09 '15 at 13:34
  • 1
    I tried the same in the latest Chrome and according to this, my desktop Chrome is a mobile, so it's a no. – Lajos Mészáros May 26 '16 at 08:23
  • 2
    @LajosMeszaros It returns `false` under desktop Chrome on Windows. – adi518 Feb 21 '18 at 00:14
  • 1
    ('ontouchstart' in window || navigator.maxTouchPoints > 0 || navigator.msMaxTouchPoints > 0) for touch-enabled desktops such as Microsoft's Surface and numerous other notebooks with Windows 8 – Zvi Redler Jan 29 '20 at 09:42
12

I came up with this:

    var isTouchDevice = function() {  return 'ontouchstart' in window || 'onmsgesturechange' in window; };
    var isDesktop = window.screenX != 0 && !isTouchDevice() ? true : false;

It leverages two things we can hold on to. One, window.screenX will ALWAYS be 0 on any tablet / mobile device. You can't move windows on these devices, it is always full screen.

Two, isTouchDevice is a pretty reliable way to know if it's mobile (android / iphone tablet) or Windows Surfacey thing. It has a touch event. Combining the two gives us a high degree of certainty that it's a mobile or tablet. If you're not one of those, you must be desktop.

Yes, you might have a desktop that somehow reports itself as touch and has the browser maxxed to the upper left. In my case, I can let that go.

httpete
  • 2,765
  • 26
  • 34
  • 1
    You should have window.screenX === 0 in the isTouchDevice check, rather than the other way around. window.screenX can be 0 on a desktop. – hexalys Jun 19 '13 at 04:24
  • Not a reliable option imo. There are laptops with touch screens. – Mark Knol Nov 08 '13 at 11:56
  • Mark this is true. But in some cases, it is close enough given the brevity of the code. There are cases where the outcome, although not ideal - is still usable for most and the code is compact enough to warrant value. – httpete Aug 02 '14 at 02:02
  • 1
    I thought I would add some input here as well (although an old answer). Some tablets will allow you to move windows, such as the Surface Pro. Just keep this in mind when coding your next project. – David Aug 20 '14 at 09:54
  • It's true David, and this code could be tweaked a bit to add detection for surface as an outlier. Most touch devices have no window movement, thus the screenX is a pretty good call. Depends on the use case. – httpete Sep 17 '15 at 14:13
  • 3
    `window.screenX != 0 && !isTouchDevice() ? true : false;` You can write this shorter as `window.screenX != 0 && !isTouchDevice();` – Janneman96 Mar 24 '17 at 13:59
7

I have been investigating this for my ReView (Responsive Viewport) project. I use a combination of the following.

  • window.screenX

Most mobile browsers have the 'window' locked to the left hand side. So if this isn't zero, likely to be a desktop browser window.

  • window.devicePixelRatio and screen.width

If dpr is 1 and screen width is reported as large via screen.width, likely to be desktop.

  • window.orientation

It is rare to find a desktop monitor in portrait mode. However, this could happen.

More unlikely is multiple orientation changes while using your site/app. This implies a desktop user would be spinning their screen... very unlikely.

A combination of these with some common sense and you can achieve a pretty solid guess.

The project mentioned along with more info is at http://responsiveviewport.com

Hope that helps.

Edward
  • 291
  • 4
  • 7
3

You can go to http://detectmobilebrowsers.com and generate a JS script which will detect whether a browser is a mobile browser. Unless you are worried about Smart TVs or some other non mobile nor desktop appliances, you can use that script and assume that if the browser is NOT a mobile browser then it should be a desktop browser.

Here is an example solution using the regex-es generated by that site:

var ua = navigator.userAgent.toLowerCase();
var isDesktop = !(/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino/i.test(a)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(ua.substr(0,4)));
Enigo
  • 3,685
  • 5
  • 29
  • 54
Dj.
  • 39
  • 1
  • Your answer is the best one in the post, but I leave a downvote because this code has a syntax error, you declare `ua` but in the regex use an `a` variable that is not defined. fix it, then I will change the downvote to an upvote. – AmerllicA Apr 06 '20 at 20:02
  • Geez. Look at the hall monitor. – SRCP Jun 19 '20 at 08:02
  • @AmerllicA I've fixed that typo, thanks for pointing it out! – Enigo Mar 12 '22 at 10:43
  • I copy/pasted this and my console says : "Uncaught ReferenceError: a is not defined" ? – Lego Apr 04 '22 at 16:03
2

Even it's a bit overkill for your case, express-useragent is one of the best solution as it can be used on both server and browser. Your case:

Include js file in HTML

<script type="text/javascript" src="/path/to/express-useragent.js"></script>

Execute the plugin

var userAgent = new UserAgent().parse(navigator.userAgent);

Value of userAgent will be something like

{
  "isMobile":false,
  "isDesktop":true,
  "isBot":false,
  .....
  "browser":"Chrome",
  "version":"17.0.963.79",
  "os":"Windows 7",
  "platform":"Microsoft Windows",
  "source":"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.79..."
}
haotang
  • 5,520
  • 35
  • 46
2

Actually, it is easy to detect mobile or tablet device, then with a simple result inversion we can understand that is desktop or not, for easy accessing I write a simple function:

const isDesktop = () => {
  const navigatorAgent =
    navigator.userAgent || navigator.vendor || window.opera;
  return !(
    /(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series([46])0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino|android|ipad|playbook|silk/i.test(
      navigatorAgent
    ) ||
    /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br([ev])w|bumb|bw-([nu])|c55\/|capi|ccwa|cdm-|cell|chtm|cldc|cmd-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc-s|devi|dica|dmob|do([cp])o|ds(12|-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly([-_])|g1 u|g560|gene|gf-5|g-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd-([mpt])|hei-|hi(pt|ta)|hp( i|ip)|hs-c|ht(c([- _agpst])|tp)|hu(aw|tc)|i-(20|go|ma)|i230|iac([ \-/])|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja([tv])a|jbro|jemu|jigs|kddi|keji|kgt([ /])|klon|kpt |kwc-|kyo([ck])|le(no|xi)|lg( g|\/([klu])|50|54|-[a-w])|libw|lynx|m1-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t([- ov])|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30([02])|n50([025])|n7(0([01])|10)|ne(([cm])-|on|tf|wf|wg|wt)|nok([6i])|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan([adt])|pdxg|pg(13|-([1-8]|c))|phil|pire|pl(ay|uc)|pn-2|po(ck|rt|se)|prox|psio|pt-g|qa-a|qc(07|12|21|32|60|-[2-7]|i-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h-|oo|p-)|sdk\/|se(c([-01])|47|mc|nd|ri)|sgh-|shar|sie([-m])|sk-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h-|v-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl-|tdg-|tel([im])|tim-|t-mo|to(pl|sh)|ts(70|m-|m3|m5)|tx-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c([- ])|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas-|your|zeto|zte-/i.test(
      navigatorAgent.substr(0, 4)
    )
  );
};

Note: this function is based on ES6 and it should transpile, best case for ReactJS.

AmerllicA
  • 29,059
  • 15
  • 130
  • 154
1

Simply include Modernizr js file it adds the classes called no-touch to all desktop browsers so you can easily target using these classes

Simon Arnold
  • 15,849
  • 7
  • 67
  • 85
Shiva
  • 19
  • 1
1

The problem with your script is, that it's just trying to detect the browser with the UserAgent-string which is not quite accurate because everyone can fake his UserAgent.

For a pretty good read on browser detection, check out this link: http://www.quirksmode.org/js/detect.html

Neq
  • 66
  • 3
0

What is the specific feature of a desktop browser that means you want different behaviour?

Is it the input mechanism (mouse and physical keyboard vs touch and virtual keyboard), the larger screen size, or something else?

For example, in CSS4 you can use @media (any-pointer: coarse) for touch-enabled devices and @media (pointer: coarse) for devices where the primary input is touch (i.e. phones and tablets whether or not an external keyboard is plugged in). CSS4 is mostly fully supported by modern browsers.

In JavaScript, you can use Window.matchMedia() to test for any CSS media query (including those above) as suggested in this SO answer.

Jake
  • 948
  • 8
  • 19