1275

I'm looking for a function that returns a boolean value if the user is using a mobile browser or not.

I know that I can use navigator.userAgent and write that function by using regex, but user-agents are too various for different platforms. I doubt that matching all possible devices would be easy, and I think this problem has been solved many times so there should be some kind of complete solution for such a task.

I was looking at this site, but sadly the script is so cryptic that I have no idea how to use it for my purpose, which is to create a function that returns true/false.

L8R
  • 401
  • 5
  • 21
ave
  • 18,083
  • 9
  • 30
  • 39
  • 6
    Related: http://stackoverflow.com/questions/3514784/best-way-to-detect-handheld-device-in-jquery. – Frédéric Hamidi Jul 08 '12 at 08:16
  • 2
    Try reading this. http://stackoverflow.com/questions/743129/mobile-detection-using-javascript – KyelJmD Jul 08 '12 at 08:25
  • It would be better if server did this and sent across different versions of JS file.. – UltraInstinct Jul 08 '12 at 08:28
  • 5
    @Thrustmaster: It really wouldn't. Serving different JS to different browsers means you have to add `Vary: User-Agent` to your response, otherwise caching proxies will store one version and send it to the other kind of browser. But `Vary: User-Agent` makes the response uncachable in IE. – bobince Jul 08 '12 at 08:51
  • 24
    @ave: What are you trying to do by detecting a "mobile" browser? The distinction is highly arguable in today's world of tablets and hybrid computing devices. Are you looking to detect small screens, and present a different UI in that case? Are you looking to detect low-bandwidth connectivity? Are you looking to detect touch interfaces? – bobince Jul 08 '12 at 08:53
  • @bobince Thanks for that. Every single day I get to learn something new at SO! :) – UltraInstinct Jul 08 '12 at 09:07
  • 2
    So i've updated my answer to use the http://detectmobilebrowsers.com/ javascript method but return a boolean value if anyone still needs this. ( just in case ). Happy Detecting :) – Michael Zaporozhets Feb 03 '13 at 15:28
  • @ave : Just to throw in another way of thinking. I find it's easier to detect devices based on screen size in today's world of multiple portable devices. Using something like [Harvey.js](http://harvesthq.github.io/harvey) you can basically Media Query your JS. – canintex Jun 05 '13 at 15:31
  • @bob I came here and the reason why I need this is that I want to enable a background video. Mobiles and tablets stop autoplay of the video and it really shows there is a step too far between them STILL. But I echo your reasoning as today I feel this gap should not be there. After all RWD is based on this premise. – landed May 11 '15 at 07:35
  • It's generally regarded that it is better to [feature detect rather than browser detect these days](https://msdn.microsoft.com/en-us/library/hh273397%28v=vs.85%29.aspx) – Liam May 21 '15 at 13:15
  • @bobince Maybe "mobile" browser means touchable and small screen? – LCB Jan 16 '17 at 19:01
  • Most of the time ask isMobile is a weak question... what you do with this information? preferer a strategy of feature detection. such have screen size less than XXX? Have Bluetooth? have a touch screen? and so on... Use the user agent information to detect it's also a weak feature that could be outdated and fail in some cases. – Steven Koch Nov 24 '20 at 11:02
  • Just use the css media query, specify min-width and max-width. It's overkill to classify the userAgent. – MisterGeeky Feb 15 '21 at 19:15
  • For React users: [react-device-detect](https://www.npmjs.com/package/react-device-detect) – llobet Mar 25 '21 at 12:59
  • @ave I strongly lobby toward re-selection of a correct answer for this popular topic. `userAgent` string detection is fraught with problems and superior strategies such as feature detection have existed since your initial question almost 10y ago. Let's not lead people astray; better to lead to better/modern solutions. Thanks! – gdibble Apr 11 '22 at 21:10
  • try navigator.userAgentData. if(navigator.userAgentData) // only available in computer browser. If true then it opened from computer browser with developer console opened. If false then it opened from mobile device since mobile device browser doesn't have navigator.userAgentData – dhir Oct 12 '22 at 01:54

46 Answers46

1766

Using Regex (from detectmobilebrowsers.com):

Here's a function that uses an insanely long and comprehensive regex which returns a true or false value depending on whether or not the user is browsing with a mobile.

window.mobileCheck = function() {
  let check = false;
  (function(a){if(/(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(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|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(a.substr(0,4))) check = true;})(navigator.userAgent||navigator.vendor||window.opera);
  return check;
};

For those wishing to include tablets in this test (though arguably, you shouldn't), you can use the following function:

window.mobileAndTabletCheck = function() {
  let check = false;
  (function(a){if(/(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(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino|android|ipad|playbook|silk/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(a.substr(0,4))) check = true;})(navigator.userAgent||navigator.vendor||window.opera);
  return check;
};

Using navigator.userAgentData

You may also use navigator.userAgentData.mobile, but userAgentData is still experimental, so it is not recommended for use in production.

const isMobile = navigator.userAgentData.mobile; //resolves true/false

Compatibility chart for userAgentData


The Original Answer

You can do this by simply running through a list of devices and checking if the useragent matches anything like so:

  function detectMob() {
    const toMatch = [
        /Android/i,
        /webOS/i,
        /iPhone/i,
        /iPad/i,
        /iPod/i,
        /BlackBerry/i,
        /Windows Phone/i
    ];
    
    return toMatch.some((toMatchItem) => {
        return navigator.userAgent.match(toMatchItem);
    });
}

However since you believe that this method is unreliable, You could assume that any device that had a resolution of 800x600 or less was a mobile device too, narrowing your target even more (although these days many mobile devices have much greater resolutions than this)

i.e

  function detectMob() {
    return ( ( window.innerWidth <= 800 ) && ( window.innerHeight <= 600 ) );
  }

Reference:

Michael Zaporozhets
  • 23,588
  • 3
  • 30
  • 47
  • 32
    Hi I just visited the http://detectmobilebrowsers.com link on my iPad 3, iOS 6.1.2, and it says "No mobile browser detected". – Richard Lovejoy Mar 27 '13 at 18:28
  • 55
    @RichardLovejoy when building sites, the ipad is generally not considered a mobile. – Michael Zaporozhets Mar 28 '13 at 11:14
  • Thanks for shedding some light , the latest version on http://detectmobilebrowsers.com looks slightly different in that it takes the site it redirects to if mobile as parameter to the annonymouse function – John Apr 23 '13 at 06:47
  • @John indeed they've mixed some stuff up however the regex hasn't changed since October last year so the above code is still up to date :) – Michael Zaporozhets Apr 23 '13 at 07:03
  • 45
    From the [about](http://detectmobilebrowsers.com/about) page: Android tablets, iPads, Kindle Fires and PlayBooks are not detected by design. To add support for tablets, add `|android|ipad|playbook|silk` to the first regex. – Gras Double Jun 07 '13 at 00:28
  • 18
    Google TV is Android too. What define a mobile ? Screen Size ? Touch ? deviceOrientation ? When i design it's more a question of mousehover or not, big bouton or small links. So, for now, i run with "if (Modernizr.touch)" :) – molokoloco Jun 26 '13 at 22:26
  • The question is not "How should I go about detecting a mobile browser?" but "how can i get a boolean return from a function such as that which i saw on detectmobilebrowsers.com?"..not really understanding the downvotes but okay – Michael Zaporozhets Jun 26 '13 at 23:59
  • 43
    Gawd, this whole idea of user agents is awful and really, really needs to stop. We really need to stop allowing clients to fight against the tide and just stick with media queries. If they want to do redirects based on scale for particular pages, then just check the range of a particular media query via JS i.e. http://tylergaw.com/articles/reacting-to-media-queries-in-javascript – marksyzm Aug 15 '13 at 10:07
  • @ChristopherFrancisco I wish I could take credit for it hahaha – Michael Zaporozhets Sep 04 '13 at 03:27
  • 1
    That website is not detecting my Nokia Lumia 928 (Windows Phone) as being a mobile device, despite it have an `iemobile` check. Anyone know a workaround? – Hanna Sep 17 '13 at 21:05
  • @DoubleGras Would you mind showing where exactly to add that? Thank you so much in advance! –  Jan 10 '14 at 04:53
  • In each code, there are 2 regexes: the first one checks in the whole user agent, the second one only checks the first 4 characters. Add the provided fragment to the first regex, like so, as of today: `...|xda|xiino|android|ipad|playbook|silk/i` – Gras Double Jan 10 '14 at 22:00
  • 10
    For those who say we should just rely on media queries, this often doesn't cut it. For example, I have a website that plays HTM5 audio, and mobile browsers don't behave the same as they do on desktop browsers; such as iOS requiring user interaction before playing audio. These sorts of things can't be detected by media queries, nor by Modernizr. – Judah Gabriel Himango Mar 29 '14 at 05:53
  • 7
    @marksyzm You seem to be approaching this from a web design perspective, but in the realm of web applications, it's not uncommon at all to have to confine yourself to arbitrary business rules regarding how things display on mobile browsers regardless of screen size. – Alkanshel Jun 03 '14 at 20:32
  • 1
    I know, but that's still the problem. – marksyzm Jun 03 '14 at 21:32
  • The updated regex fails in iBooks on iPad. Returns false. The original response returns true. – rharriso Oct 10 '14 at 17:49
  • Hi @rharriso, I've just updated the script with the latest regex. Let me know if it works iBooks now. – Michael Zaporozhets Oct 12 '14 at 01:28
  • @MichaelZaporozhets, I just ran again through the inspector. Still the function above still returns false. Below is the useragent. `"Mozilla/5.0 (iPad; CPU OS 8_0_2 like Mac OS X) AppleWebKit/600.1.4 (KHTML, like Gecko) Version/8.0 Mobile/12A405 Safari/600.1.4"` – rharriso Oct 15 '14 at 15:50
  • @rharriso Ah sorry, I didn't notice that you were on an iPad in the first comment. Please read the 1st and 2nd comments on this comment thread. – Michael Zaporozhets Oct 16 '14 at 15:57
  • @MichaelZaporozhets. difference of opinion then. I'll stick with the original regex then. – rharriso Oct 16 '14 at 18:29
  • @rharriso I think i'll just write an alternate version that covers iPads too, given the demand. – Michael Zaporozhets Oct 18 '14 at 02:13
  • 1
    What does the "b" in function(a, b) stands for? you are clearly sending only one argument to the function – David Oliveros Mar 06 '15 at 07:53
  • why not find the size of screen instead from [here](http://stackoverflow.com/questions/7715124/jquery-do-something-if-screen-width-is-less-than-960-px) and [here](http://stackoverflow.com/a/14504257/2218697) or media queries in css or media queries in javascript – Shaiju T Mar 18 '15 at 09:13
  • 1
    This won't work on a nexus 7 tablet because the user agent doesn't include the "mobile" keyword after Android, while it does on an Android smartphone. The regex (android|bb\d+|meego).+mobile requires that android be followed by one or more of anything and then "mobile" which is not the case on tablet. Thus the comment from @GrasDouble to resolve the issue on various tablet types. However it might be more efficient to put android|ipad|playbook|silk| at the start of the 1st regexp instead of at the end. – surfbuds Mar 25 '15 at 15:08
  • @user2005009 I've added a function that will include tablets to the answer. – Michael Zaporozhets Apr 02 '15 at 04:36
  • I've read through all the comments. Would it not be better to detect its a mobile device by testing the default "click event". For example, query screen size is not good enough for me, because I need to serve a different experience based on whether the user is using their fingers or a mouse. Is this possible? Edit: It appears it could be http://stackoverflow.com/questions/4817029/whats-the-best-way-to-detect-a-touch-screen-device-using-javascript/4819886#4819886 – CarbonDry Dec 07 '15 at 11:57
  • how to check if the device are touchscreen ? – Syamsoul Azrien May 10 '16 at 09:42
  • 1
    @MichaelZaporozhets I realise you just copied it from detectmobilebrowsers.com, but I'm almost tempted to downvote this because of the unmaintainability of that code. It's not just the horific regexes, but why have it wrapped all in a self executing function and why not have a sensibly named variable? Why is it just 'a'? – stripybadger Jun 09 '16 at 14:45
  • @stripybadger Don't shoot the messenger! DMB does it this way (I presume they have an automated compilation script that pushes out the latest 'combination' or so which you have 'a' as the variable. One *could* of course change this, but maintaining any other updates apart from the return response each update from DMB simply doesn't seem worth my time. – Michael Zaporozhets Jun 09 '16 at 15:16
  • thanks for tablet, it's very usefull ! For me what to do "mobile" is not size, but touchscreen because a lot of css feature like "hover" on menu or tooltip have no sense without a mouse even if the screen is 4000px width – amdev Sep 29 '16 at 12:06
  • Nice Code! I agree that using Javascript to do this is can be painful and requires updating for new devices/browsers on the market, but at at this moment in time I would say use Javascript. Choosing CSS media queries can attempt to detect mobile/tablet but would still require updating for new devices. I would prefer using Javascript since I can keep the mobile/tablet detection code in one place and be able to do anything I need with Javascript code (including modifying the CSS). If you think you found better Javascript code, please share. Btw, is this code being kept up to date? – e-zero Jan 10 '17 at 07:04
  • hi is this function up to date? window.mobileAndTabletcheck = function() { – Furkan Gözükara Jan 18 '17 at 16:53
  • Can someone explains how this function works? How is `check` being updated? – noblerare Jun 17 '17 at 09:09
  • It uses the closure property for the check variable, and sets if if the if statement is true. There's probably better ways to write this. – Jim Pedid Jun 26 '17 at 20:46
  • That regex is some dangerous stuff you've got there. You could poke someone's eye out with that thing! – hewiefreeman Oct 29 '17 at 00:32
  • Not expecting this to change I opted to make it more static without a function call. It could be done where window.mobileCheck is a boolean that the comprehensive line makes true. – Master James Dec 20 '17 at 11:53
  • this method is such a mess, why not just have it return a boolean value?? – Vic Apr 20 '18 at 19:13
  • @MichaelZaporozhets im talking about the self executing function after `var check = false` – Vic Apr 21 '18 at 03:23
  • @Vic ah yeah- honestly, I'm pretty sure I left that in there to 'show working' from the source. That being said- no need for it stay that ugly now. feel free to suggest an edit. Probably time for an es6 version too tbh. – Michael Zaporozhets Apr 22 '18 at 22:59
  • 1
    Hello, from the future. Now even the 2K resolution is not unique on mobiles, so please refrain using that as a check. – Koshinae Jun 13 '18 at 08:41
  • I read `detectmob` as `detectmobster` and for a second I thought you were police – Bruno Francisco Sep 16 '18 at 19:16
  • +1 for checking dimensions. I realized the reason I wanted to detect mobile in the first place was to accommodate smaller screen widths. – ankh-morpork Sep 21 '18 at 02:15
  • To use `window.mobilecheck`, you need to use it as `window.mobilecheck()`. Why is it a function and not a boolean variable? – Maytha8 Oct 07 '18 at 06:11
  • @Mth see o.p: "I'm looking for a function..." – Michael Zaporozhets Oct 08 '18 at 06:52
  • I get it. The question says he wants a function that ***returns*** a boolean variable. Anyways, thanks for the `function`! – Maytha8 Oct 09 '18 at 11:45
  • I know you are just offering it as an alternative; but why not use `window.screen.width` and `window.screen.height` to capture the device screen size instead of `window.innerWidth` and `window.innerHeight`? This way the function won't detect a false screen size when the browser is not full screen. I tested this and it works reliably on Chrome 71, Safari 12, Firefox 64, Edge 18, IE11, Android (Chrome and Firefox), iPhone and iPad (Safari and Chrome for both). – Cory Kleiser Jan 11 '19 at 13:35
  • Detecting chrome in Mac as mobile device – Walker Leite Sep 30 '19 at 14:04
  • 1
    Do not rely on `window.innerWidth` for detecting mobile devices. It may give suprisingly large number if the site has elements larger than window width and mobile browser automatically scales the page. Instead use `document.body.offsetWidth` or `window.screen.width` – Zortext Nov 30 '19 at 12:40
  • Note that chrome is deprecating `navigator.userAgent` https://9to5google.com/2020/01/14/google-deprecate-chrome-user-agent-string-privacy/ – T.Woody Apr 17 '20 at 21:39
  • `window.mobileAndTabletCheck` function does not detect my iPad Pro – Below the Radar Nov 03 '20 at 18:13
  • 1
    @BelowtheRadar Unfortunately iPad Pro Safari does not identify itself as a tablet or mobile device, which disables this method of identification. If you're looking to target the ipad and similar devices, I'd probably look at browser api sniffing methods instead. See this answer for further information https://stackoverflow.com/questions/57776001/how-to-detect-ipad-pro-as-ipad-using-javascript – Michael Zaporozhets Nov 05 '20 at 06:00
  • "No mobile browser detected" for iPad Air 2 on detectmobilebrowsers.com – GajendraSinghParihar Dec 02 '20 at 11:00
  • better to use window.screen.width because if the window is not maximized you will get a "wrong" answer –  Jan 01 '21 at 19:33
  • Careful there is an extra `|` in `mobileAndTabletCheck` regex which makes the whole test wrong. Tried to edit but it's under 6 characters, so i can't. Any mod ? – Magoo Feb 28 '22 at 13:04
  • Agent strings will be spoofed. 2022 and long before, feature detection is far superior and reliable. Mandalorians would say, "userAgent is Not the way." – gdibble Apr 11 '22 at 21:06
  • what will be result of function detectMob if android laptop comes to market – user1844933 Aug 24 '22 at 13:51
368

How about:

if (typeof screen.orientation !== 'undefined') { ... }

...since smartphones usually support this property and desktop browsers don't. See in MDN.

EDIT 1: As @Gajus pointed out, window.orientation is now deprecated and shouldn't be used.

EDIT 2: You can use the experimental screen.orientation instead of the deprecated window.orientation. See in MDN.

EDIT 3: Changed from window.orientation to screen.orientation

Tiago Rangel
  • 1,159
  • 15
  • 29
yoav barnea
  • 5,836
  • 2
  • 22
  • 27
  • 19
    this is actually super unique and awesome, do you mind if I add it to my answer? – Michael Zaporozhets Jan 30 '13 at 00:34
  • thank you for the compliment. of course i don't mind. i didn't tested it though, so i would love to get some implementation feedbacks – yoav barnea Feb 07 '13 at 12:37
  • 86
    This is probably not going to work for long. 1) Tablets can have decent screen sizes, you want them to display full desktop website but they will have this property 2) Windows 8 is here and with it a bunch of laptops with touch screen and screens that rotate. – Dave Hilditch Feb 20 '13 at 17:33
  • 13
    as for your first point about Tablets with decent screen sizes- I think you could make the same arguments for all others solutions as well (a tablet with big screen that is been tracked as small screen). anyway the idea here is to search for property that is been shared by small devices instead of keep maintence long code and add regex with every new coming device/vesion/model. I think device detection is belong to the past and today we need to focus on feature detection. again I will be glad to here about more suitable property for that matter... – yoav barnea Mar 02 '13 at 20:01
  • Simple solution to a complex problem. I like it! – ChrisRich May 22 '13 at 03:34
  • 2
    Love it and works perfectly, thankyou. For my solution I was just after simple. – Bojangles Jun 18 '13 at 06:19
  • I'd take care with this approach. It seems not to be supported thoroughly, just by iOS and some Android devices. – Volker E. Jul 26 '13 at 16:03
  • I just tested this on an iPhone (iOS 7) and it works if the device is in landscape orientation, but not portrait. – siannopollo Oct 30 '13 at 15:42
  • this varient if(window.orientation !== undefined) {...} should be enough – MistereeDevlord Feb 03 '14 at 09:37
  • I prefer this, not for full fledged mobile detection. But as a helper work around to the limited orientation support on desktop. The accepted answer is also risky, if that list isn't up to date the function won't work across all browsers. And given its regex nature the chances of someone maintaining it are slim. This option is clear, short, succinct FTW – Lex May 29 '14 at 03:08
  • I tried different browsers on the same Android 4.4.4 device: Chrome - OK; Firefox - Not working; Dolphin - OK. – valir Jul 28 '14 at 20:05
  • I only need to detect a mobile device on my site to determine weither to use touchstart events or click events; the breakpoints are all irrelevant of window size and put in place to ensure the site is formatted nicely. so for a solution to detect weither or not I want touch events (any phone or tablet) or click events (a laptop / desktop) this is an awesome solution. thanks so much; the regex answers were complex and require constant maintenance. – Eolis Nov 04 '15 at 18:50
  • I like this solution because it answers the question of "is this mobile" as simply as possible. The question isn't "how do I detect small screen sizes", but rather "Detecting a mobile browser." – Ivan Jan 21 '16 at 04:52
  • 48
    `window.orientation` is a deprecated property (https://developer.mozilla.org/en-US/docs/Web/API/Window/orientation, https://compat.spec.whatwg.org/#dom-window-orientation) that some mobile browsers choose to support for unknown reasons. Same browsers implement `window.screen.orientation` (which is defined in desktop browsers too). I can only assume that `window.orientation` is left there for legacy reasons and should therefore not be used in new applications. – Gajus Feb 08 '16 at 10:07
  • True, window.orientation is deprecated but window.screen.orientation does not (yet) work on iOS 11.x (returns 'undefined'). – Jonny Apr 26 '19 at 10:21
  • 2
    Then simply use if(window.orientation || window.screen.orientation) {}. Problem solved – Ali Mert Çakar Jul 09 '20 at 06:30
  • 2
    @AliMertCakar I agree, but chrome (and may be others) defines window.screen.orientation in the desktop. Cheers. – Benj Sanders Jul 10 '20 at 23:42
  • 23
    screen.orientation is also supported on desktop https://developer.mozilla.org/en-US/docs/Web/API/Screen/orientation#browser_compatibility – Ictus May 12 '21 at 14:35
  • 3
    To go deeper on @lctus's comment, as of this writing, I don't think answer is usable any more, and should be updated to that effect. On the desktop versions of both Chrome and Firefox, `screen.orientation` is defined, so this solution will provide false positives for at least those desktop browsers. – Jeff Lee Dec 07 '21 at 23:23
  • 3
    Doesn't work any more – Krishna Karki May 06 '22 at 14:10
  • Well my Windows 10's Chrome 103 says that `screen.orientation` **is** defined ¯\_(ツ)_/¯ – RixTheTyrunt Jul 13 '22 at 12:09
  • It is not working solution anymore. Works also on PC. – Nijat Mursali Aug 01 '22 at 10:31
  • Problem with screen.orientation: you can just use this to check if screen is in portrait mode or not. This is obj value on mobile phones: Screen.orientation.type = 'portrait-primary', but as soon as your rotate your phone to landscape the value changes, so this makes it useless to detect if its mobile browser or not. – strix25 Jul 12 '23 at 07:58
  • At the moment the easiest way is still window.orientation. If you read properly it is actually not deprecated. They deprecated it only on desktop browsers. On mobile browsers it still has full support even in the newest browsers! – strix25 Jul 12 '23 at 08:04
  • @strix25 `window.orientation` is deprecated for all browsers. What you're not getting is that it was intentionally undefined on desktop browsers (and in case of mobile ones, it's deprecated). – Christian Jul 13 '23 at 07:40
  • @yoavbarnea On the other hand, `screen.orientation` will not work because on new browsers it will never be undefined. – Christian Jul 13 '23 at 07:40
  • @Christian you are wrong about deprecation on all browsers. Scroll to the bottom of the page https://developer.mozilla.org/en-US/docs/Web/API/Window/orientation Even Mobile Chrome Version 114.0.5735.199 has full support for it https://caniuse.com/?search=window.orientation – strix25 Jul 13 '23 at 07:53
  • @strix25 what you are seeing is the compatibility table saying if it works or not, **deprecation typically means it works, but it will not work anymore at some point in the future.** Both links you provided are saying the same thing. The table you see on MDN has a trash icon on the left (and a big warning at the start of the page) and caniuse specifically says: **This feature is deprecated/obsolete and should not be used.** – Christian Jul 13 '23 at 12:22
161
const isMobile = {
    Android: function() {
        return navigator.userAgent.match(/Android/i);
    },
    BlackBerry: function() {
        return navigator.userAgent.match(/BlackBerry/i);
    },
    iOS: function() {
        return navigator.userAgent.match(/iPhone|iPad|iPod/i);
    },
    Opera: function() {
        return navigator.userAgent.match(/Opera Mini/i);
    },
    Windows: function() {
        return navigator.userAgent.match(/IEMobile/i) || navigator.userAgent.match(/WPDesktop/i);
    },
    any: function() {
        return (isMobile.Android() || isMobile.BlackBerry() || isMobile.iOS() || isMobile.Opera() || isMobile.Windows());
    }
};

How to use

if( isMobile.any() ) alert('Mobile');

To check to see if the user is on a specific mobile device:

if( isMobile.iOS() ) alert('iOS');

Ref: http://www.abeautifulsite.net/blog/2011/11/detecting-mobile-devices-with-javascript

Enhanced version on github : https://github.com/smali-kazmi/detect-mobile-browser

zero_cool
  • 3,960
  • 5
  • 39
  • 54
Mudaser Ali
  • 3,989
  • 3
  • 25
  • 27
  • Why not make `any()` a for...in loop of ORed `isMobile` members? – SomeShinyObject Mar 01 '14 at 15:43
  • @ChristopherW i had created its plugin and modified code as you advised – Mudaser Ali Apr 30 '14 at 19:57
  • 2
    @Rob_vH i had put this code into github (https://github.com/smali-kazmi/detect-mobile-browser) with some advance features; you are open to send suggestions there as well – Mudaser Ali Mar 13 '15 at 19:45
  • This one gets my upvote for content, but I'm trying to figure out how to convert it to John Papa's styling and having some difficulty. Still quite new to AngularJS as a whole (about a month into knowledge of it) and the vm. notation angles the learning curve upward a bit. Any help? -C§ EDIT: I'm trying to unit test it with karma-jasmine is why I ask. – CSS Aug 11 '15 at 18:11
  • 3
    @AkarshSatija Does the performance drop from those 5 regex checks actually impact any of your applications? I would be very surprised if it did. Premature optimization can be a waste of time... – trusktr Sep 22 '19 at 03:53
  • @trusktr regex match is an expensive operation and handheld devices are always a little challenge at computing. There's no rationale around against Premature optimizations but they come back and bite very soon at your worsts. Also, why not go for optimization when better options are available? – Akarsh Satija Sep 22 '19 at 13:34
  • 3
    may i suggest `any: () => /Mobile/.test(navigator.userAgent)` – oriadam May 22 '20 at 12:28
  • I agree with @oriadam, because of the return type `match(): RegExpMatchArray`, `test(): boolean` . So when using TypeScript there will be an error. – Sergiy Ostrovsky Feb 03 '23 at 11:50
  • @oriadam this will always true: any: () => /Mobile/.test(navigator.userAgent)!! – Khalid Almannai Jul 23 '23 at 13:50
153

Here is a simple solution from the source of facebook's slingshot

const isMobile = /iPhone|iPad|iPod|Android/i.test(navigator.userAgent);
if (isMobile) {
  /* your code here */
}
zero_cool
  • 3,960
  • 5
  • 39
  • 54
Santhosh
  • 3,781
  • 2
  • 14
  • 11
58

Came here looking for a simple, clean way to detect "touch screens devices", which I class as mobile and tablets. Did not find a clean choice in the current answers but did work out the following which may also help someone.

var touchDevice = ('ontouchstart' in document.documentElement);

Edit: To support desktops with a touch screen and mobiles at the same time you can use the following:

var touchDevice = (navigator.maxTouchPoints || 'ontouchstart' in document.documentElement);
Tigger
  • 8,980
  • 5
  • 36
  • 40
  • 29
    What if desktop's monitor supports touch? – Anton Kuzmin Aug 01 '16 at 01:25
  • @HappyCoder I believe it is up to the OS to tell the browser when the touch screen on a desktop is active. So, yes this check should still be valid. – Tigger Aug 01 '16 at 09:09
  • (+1), however, my desktop I'm using now has a touchScreen, and it isn't always consistent for `touchstart|end|etc`. – Cody Dec 16 '16 at 21:18
  • 2
    Bootstrap datepicker uses the following: if ( window.navigator.msMaxTouchPoints || 'ontouchstart' in document) { this.input.blur(); } – J.T. Taylor Jul 15 '17 at 00:31
  • 2
    @J.T.Taylor It looks like Microsoft is [recommending](https://msdn.microsoft.com/en-us/library/hh772144.aspx) `navigator.maxTouchPoints` (no `ms` prefix). There is also an [MDN article](https://developer.mozilla.org/en-US/docs/Web/API/Navigator/maxTouchPoints) to check. – Tigger Jul 15 '17 at 00:43
  • what if use hammer.. for me return true... ('ontouchstart' in document.documentElement) – Enrikisimo Lopez Ramos Nov 24 '17 at 10:22
  • take care maxTouchPoints is broken, I have no touchscreen and in chrome it returns 256. This fixed the issue for me: navigator.maxTouchPoints & 0xFF https://stackoverflow.com/questions/55833326/wrong-maxtouchpoints-and-ontouchstart-in-document-in-chrome-mobile-emulati – strix25 Jul 12 '23 at 08:37
51

According to MDN's article on Browser detection using the user agent, it is encouraged to avoid this approach if possible and suggest other avenues such as feature detection.

However, if one must use the user agent as a means to detect if the device is mobile, they suggest:

In summary, we recommend looking for the string “Mobi” anywhere in the User Agent to detect a mobile device.

Therefore, this one-liner will suffice:

const isMobileDevice = window.navigator.userAgent.toLowerCase().includes("mobi");

[UPDATE]:

As @zenw0lf suggests in the comments, using a Regular Expression would be better:

const isMobileDevice = /Mobi/i.test(window.navigator.userAgent)

Chunky Chunk
  • 16,553
  • 15
  • 84
  • 162
42

As many have stated, relying on the moving target of the user agent data is problematic. The same can be said for counting on screen size.

My approach is borrowed from a CSS technique to determine if the interface is touch:

Using only javascript (support by all modern browsers), a media query match can easily infer whether the device is mobile.

function isMobile() {
    var match = window.matchMedia || window.msMatchMedia;
    if(match) {
        var mq = match("(pointer:coarse)");
        return mq.matches;
    }
    return false;
}
vsync
  • 118,978
  • 58
  • 307
  • 400
gsxrboy73
  • 1,382
  • 14
  • 19
  • 12
    What about laptops with touch enabled displays? – Maxim Oct 31 '18 at 21:32
  • 18
    I would check for !matchMedia("(any-pointer:fine)").matches myself. ("No mouse plugged in", rather than "has a touch screen". – Sora2455 Jan 30 '19 at 01:51
  • This works whereas my last script would get tricked by people using the browser's zoom feature (e.g. a guy I was talking with on a 13" screen with 4K who dropped to 1080p and still had to use zoom). Worked on my iPhone (Safari/Firefox) and Android devices (Waterfox/Chrome/"Browser"). Definitely *much* more reliable than all the higher up-voted answers. – John Sep 27 '19 at 18:50
  • does not detect FireFox fennec on an Android for which I supplemented with navigator.userAgent.toLowerCase().indexOf('fennec') > -1 (perhaps not the best supplement..) – StayCool Oct 29 '19 at 08:13
  • 4
    Additionnally you can test the hover property: for smartphones and touchscreens @media (hover: none) and (pointer: coarse) – Batailley Jan 31 '20 at 11:15
  • how widely "supported" is checking `any-pointer` and `hover` with MQs? i know MDN says theyre candidate recommendations, sooo – oldboy Nov 13 '20 at 07:11
  • According to this: https://caniuse.com/matchmedia, it's pretty widely support for all modern browsers. The only browsers to be concerned about are mobile browsers since that function will return false for all other browsers whether they support matchMedia or not. So based on caniuse.com, only *0.03%* of global users are *not supported*. – gsxrboy73 Nov 17 '20 at 15:46
  • Responses 'false' on a laptop with touchscreen. Hooray! – bulbigood Sep 07 '22 at 13:46
20

There's no perfect solution for detecting whether JS code is executed on a mobile browser, but the following two options should work in most cases.

Option 1 : browser sniffing

!function(a){var b=/iPhone/i,c=/iPod/i,d=/iPad/i,e=/(?=.*\bAndroid\b)(?=.*\bMobile\b)/i,f=/Android/i,g=/(?=.*\bAndroid\b)(?=.*\bSD4930UR\b)/i,h=/(?=.*\bAndroid\b)(?=.*\b(?:KFOT|KFTT|KFJWI|KFJWA|KFSOWI|KFTHWI|KFTHWA|KFAPWI|KFAPWA|KFARWI|KFASWI|KFSAWI|KFSAWA)\b)/i,i=/IEMobile/i,j=/(?=.*\bWindows\b)(?=.*\bARM\b)/i,k=/BlackBerry/i,l=/BB10/i,m=/Opera Mini/i,n=/(CriOS|Chrome)(?=.*\bMobile\b)/i,o=/(?=.*\bFirefox\b)(?=.*\bMobile\b)/i,p=new RegExp("(?:Nexus 7|BNTV250|Kindle Fire|Silk|GT-P1000)","i"),q=function(a,b){return a.test(b)},r=function(a){var r=a||navigator.userAgent,s=r.split("[FBAN");return"undefined"!=typeof s[1]&&(r=s[0]),s=r.split("Twitter"),"undefined"!=typeof s[1]&&(r=s[0]),this.apple={phone:q(b,r),ipod:q(c,r),tablet:!q(b,r)&&q(d,r),device:q(b,r)||q(c,r)||q(d,r)},this.amazon={phone:q(g,r),tablet:!q(g,r)&&q(h,r),device:q(g,r)||q(h,r)},this.android={phone:q(g,r)||q(e,r),tablet:!q(g,r)&&!q(e,r)&&(q(h,r)||q(f,r)),device:q(g,r)||q(h,r)||q(e,r)||q(f,r)},this.windows={phone:q(i,r),tablet:q(j,r),device:q(i,r)||q(j,r)},this.other={blackberry:q(k,r),blackberry10:q(l,r),opera:q(m,r),firefox:q(o,r),chrome:q(n,r),device:q(k,r)||q(l,r)||q(m,r)||q(o,r)||q(n,r)},this.seven_inch=q(p,r),this.any=this.apple.device||this.android.device||this.windows.device||this.other.device||this.seven_inch,this.phone=this.apple.phone||this.android.phone||this.windows.phone,this.tablet=this.apple.tablet||this.android.tablet||this.windows.tablet,"undefined"==typeof window?this:void 0},s=function(){var a=new r;return a.Class=r,a};"undefined"!=typeof module&&module.exports&&"undefined"==typeof window?module.exports=r:"undefined"!=typeof module&&module.exports&&"undefined"!=typeof window?module.exports=s():"function"==typeof define&&define.amd?define("isMobile",[],a.isMobile=s()):a.isMobile=s()}(this);

alert(isMobile.any ? 'Mobile' : 'Not mobile');

This particular browser sniffing code is that of a library called isMobile.


Option 2 : window.orientation

Test if window.orientation is defined :

var isMobile = window.orientation > -1;
alert(isMobile ? 'Mobile' : 'Not mobile');

Note

Not all touchscreen devices are mobile and vice versa. So, if you want to implement something specifically for touchscreen, you shouldn't test if your browser is run on a mobile device but rather whether the devices has touchscreen support :

var hasTouchscreen = 'ontouchstart' in window;
alert(hasTouchscreen ? 'has touchscreen' : 'doesn\'t have touchscreen');
Community
  • 1
  • 1
John Slegers
  • 45,213
  • 22
  • 199
  • 169
  • Orientation approach is really nice! )) – Maxim Oct 19 '17 at 11:57
  • 2
    I like your `window.orientation` solution, but the docs say it's deprecated! https://developer.mozilla.org/en-US/docs/Web/API/Window/orientation – skwidbreth Apr 10 '18 at 17:58
  • 4
    Orientation approach is NOT nice because Windows 8 and higher can change orientation. – Heitor Aug 04 '18 at 06:58
  • Windows 8 and newer are focused on adding support for mobiles but also hybrids (laptops that can convert to large pads) which is why orientation fails as a detection method even if moz wasn't referring to it as deprecated. – Jeff Clayton Jul 12 '19 at 15:12
  • It's from Win 7 with Graphical Software installed can change orientation but ask yourself a question, who can on Desktop / Laptop use a another screen orientation like Portrait instead of Landscape and use i for even more than 1 minute. No one !!! Changing orientation on Desktop means you'll start reading characters on your screen from bottom to top. – GirlCode Apr 17 '20 at 08:52
  • See [this other answer](/a/14301832/4642212). `.orientation` is no longer a solution to this problem. – Sebastian Simon Dec 09 '21 at 16:04
16

Here is a userAgent solution that is more efficent than match...

function _isMobile(){
    // if we want a more complete list use this: http://detectmobilebrowsers.com/
    // str.test() is more efficent than str.match()
    // remember str.test is case sensitive
    var isMobile = (/iphone|ipod|android|ie|blackberry|fennec/).test
         (navigator.userAgent.toLowerCase());
    return isMobile;
}
JeffJak
  • 2,008
  • 5
  • 28
  • 40
  • 10
    the test method is not case sensitive, but your regex is. you could just flag for case insensitive regex with an "i" at the end and do `/iphone|etc/i.test(navigator.userAgent)` – xec Feb 05 '13 at 17:01
13

Feature detection is much better than trying to figure out which device you are on and very hard to keep up with new devices coming out all the time, a library like Modernizr lets you know if a particular feature is available or not.

zadubz
  • 1,281
  • 2
  • 21
  • 36
  • 27
    You've answered another question than what was asked. Rather than "how can I detect mobile?", you've answered "how can I detect certain features?". Not all device detection is for feature detection. What if we were looking to get statistics about devices? Then no, "feature detection" is not "much better than [figuring out device]". – Jonathan Allard Jun 01 '16 at 19:10
  • 2
    This is not the answer, but it deserves more than just a comment. The question is: why do you want to detect a browser and then you will probably want to know it because of the (lack of) touch only. Responsive webdesign suffices in most if not all cases. – twicejr Aug 04 '17 at 14:24
  • What if the feature I want to detect is how powerful the device CPU is? I need to lower quality on mobile phones... – Mikepote Aug 17 '21 at 13:32
12

To add an extra layer of control I use the HTML5 storage to detect if it is using mobile storage or desktop storage. If the browser does not support storage I have an array of mobile browser names and I compare the user agent with the browsers in the array.

It is pretty simple. Here is the function:

// Used to detect whether the users browser is an mobile browser
function isMobile() {
    ///<summary>Detecting whether the browser is a mobile browser or desktop browser</summary>
    ///<returns>A boolean value indicating whether the browser is a mobile browser or not</returns>

    if (sessionStorage.desktop) // desktop storage 
        return false;
    else if (localStorage.mobile) // mobile storage
        return true;

    // alternative
    var mobile = ['iphone','ipad','android','blackberry','nokia','opera mini','windows mobile','windows phone','iemobile']; 
    for (var i in mobile) if (navigator.userAgent.toLowerCase().indexOf(mobile[i].toLowerCase()) > 0) return true;

    // nothing found.. assume desktop
    return false;
}
Rasmus Søborg
  • 3,597
  • 4
  • 29
  • 46
  • 3
    I haven't tested on mobile yet, but `sessionStorage.desktop` doesn't exist in either Safari, Chrome, or Firefox (all newest versions at time of post). You get an up-vote though, since your solution goes in a better direction than others. But don't forget to use `var mobile =` instead of `mobile =`. – shuckster Dec 28 '13 at 15:33
  • 3
    Also a good idea not to use indexOf with older browsers still being around which don't support that method, or to use a polyfill. It's not necessary to use toLowerCase on a list of lowercase values, nor is it necessary to do so if you're running /ipad|iphone|etc/i.test(navigator.userAgent) instead of the slow loop you have up there. – Jeffrey Gilbert Jun 02 '14 at 22:19
10

How about something like this?

if(
    (screen.width <= 640) || 
    (window.matchMedia && 
     window.matchMedia('only screen and (max-width: 640px)').matches
    )
  ){
   // Do the mobile thing
}
stujo
  • 2,089
  • 24
  • 29
  • Why not just use `screen.width` instead? It seems to me that's more reliable than `window.matchMedia`. – John Slegers Mar 12 '16 at 02:30
  • Good point John, I can't recall exactly what I was thinking at the time, it seems unlikely (looking at it now) that the second clause would return true if the first is false. There must have been some reason I added it though. – stujo Mar 23 '16 at 23:35
  • Most decent programmers feel ashamed when they see code they wrote themselves a year earlier. Those who don't just haven't grown as programmers ;-) – John Slegers Mar 24 '16 at 07:33
  • 6
    Window resolution has nothing to do with whether a browser is on a mobile device or not. For example, lots of desktop browsers run in non-full-screen windows. If you present a UI designed for handheld screens to those browsers, their users are going to have a frustrating experience. – ʇsәɹoɈ Apr 21 '16 at 02:16
10

A really good way of detecting mobile or tablet devices is by looking if the browser can create a touch event.

Plain JavaScript Code:

function isMobile() {
   try{ document.createEvent("TouchEvent"); return true; }
   catch(e){ return false; }
}

if (isMobile()) {
   # do whatever you wanna do!
}

This worked for me really well, but there may be a problem with laptop devices which include a touchscreen display.

I am not sure if a touchscreen Laptop will get detected as a mobile device because I haven't tested it yet.

Neo Morina
  • 391
  • 2
  • 13
  • 10
    Touch screen laptops will be detected as mobile device. As well as touch screen monitors for desktops. Believe it or not, you will also run into issue if you are using touchscreen device to RDP into another device that is does not have a touch screen. – blissfool Jun 04 '18 at 20:59
  • @blissfool i guess this will not be the right way for detecting mobile devices then. – Neo Morina Jun 12 '18 at 07:08
  • Unfortunately, no. But, it might still be a viable option for a very limited use case. – blissfool Jun 13 '18 at 14:51
  • never write code, that is based on an exception, that will be throwen for sure in any case... – Pablo Nov 15 '18 at 08:30
  • @Sivic it only gets thrown when a TouchEvent does not exists and the code above catches it and returns false. This is not the case on Mobile or Tablet or other Touch Screen devices. – Neo Morina Mar 15 '19 at 14:58
  • How about using this with a check on screen size? Considering Bootstrap switches to mobile view below 768px? – Ajay Gupta Jun 21 '19 at 14:37
10

Feature Detection

const isMobile = localStorage.mobile || window.navigator.maxTouchPoints > 1;

WORKS IN CHROME + SAFARI as of 2022-02-07 :: combining feature detections and trying everything in this thread and other sites. The localStorage.mobile works in Chrome mobile; the latter works in Safari mobile. Does not trigger desktop browsers with or w/o the dev-tools open and/or on a mobile simulator. As of writing this, it triggers a real mobile browser but not desktops.

Please consider

I've also tested this on a Lenovo X1 Yoga (keyboard or tablet-mode) on Win10

  1. localStorage.mobile is undefined no matter what
  2. When the laptop is in keyboard mode:
    window.navigator.maxTouchPoints is 1
    → isMobile is false
  3. When the keyboard is flipped back and the laptop is in tablet-mode:
    window.navigator.maxTouchPoints is 10
    → isMobile is true
gdibble
  • 1,341
  • 14
  • 16
  • 1
    maxTouchPoints - what if laptop has a touch screen? – sskular Mar 17 '22 at 14:40
  • 1
    @sskular that was a very good question---thanks. I tested it for us, as I have a Lenovo X1 Yoga available with Win10. 1) `localStorage.mobile` is `undefined` no matter what. 2) When the laptop is in keyboard mode, `window.navigator.maxTouchPoints` is `1`; so isMobile was `false`. 3) When the keyboard is flipped back and the laptop is in tablet mode, `window.navigator.maxTouchPoints` is `10`; so isMobile was `true`. Now the subjective question: Do we consider a tablet or laptop in tablet-mode as mobile? – gdibble Mar 21 '22 at 19:36
  • Great work, works on Firefox for Android too. – Hashim Aziz Jun 15 '22 at 19:02
  • localstorage.mobile is something you have to define, this answer code is incomplete. – Patricio Gabriel Maseda Aug 03 '22 at 14:06
8

don't use this method as window.orientation is now deprecated!!!

function isMobile() {
  return (typeof window.orientation !== "undefined") || (navigator.userAgent.indexOf('IEMobile') !== -1);
};
Rick Enciso
  • 3,145
  • 3
  • 14
  • 14
  • 2
    `window.orientation` is [deprecated](https://developer.mozilla.org/en-US/docs/Web/API/Window/orientation). This feature is no longer recommended. Though some browsers might still support it, it may have already been removed from the relevant web standards, may be in the process of being dropped, or may only be kept for compatibility purposes. Avoid using it, and update existing code if possible; see the compatibility table at the bottom of this page to guide your decision. Be aware that this feature may cease to work at any time. – karel Mar 09 '21 at 11:18
8

Depends on the use case. All mobile devices require a battery. If what you're after is compute power without draining the battery use the Battery Status API:

navigator.getBattery().then(battery => {
  battery.charging ? 'charging' : 'not charging';
});

If what you're looking for is presentational use matchMedia, which returns a Boolean value:

if (window.matchMedia("(min-width: 400px)").matches) {
  /* the viewport is at least 400 pixels wide */
} else {
  /* the viewport is less than 400 pixels wide */
}

Or combine them for an even better user experience on tablet devices.

vhs
  • 9,316
  • 3
  • 66
  • 70
7

Once the element gains focus, you immediately blur it. Bootstrap-datepicker, which is a very popular and well-maintained component with almost 10,000 stars in GitHub, uses this approach:

if (window.navigator.maxTouchPoints || 'ontouchstart' in document) {
    this.input.blur();
}

https://github.com/uxsolutions/bootstrap-datepicker

Thanks to Tigger for assistance.

Cody Gray - on strike
  • 239,200
  • 50
  • 490
  • 574
J.T. Taylor
  • 4,147
  • 1
  • 23
  • 23
6

Here is my re-thought solution for the problem. Still not perfect. The only true solution would be if the device manufacturers start to take seriously the "Mobile" and "Tablet" user-agent strings.

window.onload = userAgentDetect;
function userAgentDetect() {
  if(window.navigator.userAgent.match(/Mobile/i)
  || window.navigator.userAgent.match(/iPhone/i)
  || window.navigator.userAgent.match(/iPod/i)
  || window.navigator.userAgent.match(/IEMobile/i)
  || window.navigator.userAgent.match(/Windows Phone/i)
  || window.navigator.userAgent.match(/Android/i)
  || window.navigator.userAgent.match(/BlackBerry/i)
  || window.navigator.userAgent.match(/webOS/i)) {
    document.body.className += ' mobile';
    alert('True - Mobile - ' + navigator.userAgent);
  } else {
    alert('False - Mobile - ' + navigator.userAgent);
  }
  if(window.navigator.userAgent.match(/Tablet/i)
  || window.navigator.userAgent.match(/iPad/i)
  || window.navigator.userAgent.match(/Nexus 7/i)
  || window.navigator.userAgent.match(/Nexus 10/i)
  || window.navigator.userAgent.match(/KFAPWI/i)) {
    document.body.className -= ' mobile';
    document.body.className += ' tablet';
    alert('True - Tablet - ' + navigator.userAgent);
  } else {
    alert('False - Tablet - ' + navigator.userAgent);
  }
}

What happens when the Nexus 7 tablet only have the Android UA string? First, the Mobile become true, than later on the Tablet also become true, but Tablet will delete the Mobile UA string from the body tag.

CSS:

body.tablet { background-color: green; }
body.mobile { background-color: red; }

alert lines added for development. Chrome console can emulate many handheld devices. Test there.

EDIT:

Just don't use this, use feature detection instead. There are so many devices and brands out there that targeting a brand NEVER will be the right solution.

Lanti
  • 2,299
  • 2
  • 36
  • 69
  • *"Just don't use this"* ? You can always delete your answer. Also, all those `.match(` ... hm. RegExp and `.test()` is a simpler variant. – Roko C. Buljan Jan 10 '22 at 17:30
4

Here is a less obfuscated version of the answer by Michael Zaporozhets. It also uses a check to build the regular expressions only on the first call. See this answer for the technique used to build the string from an array of regular expressions.

var gRE = null;
var gRE4 = null;

function PlatformIsMobile()
{
    var e;
    
    if ( gRE == null )
    {
        e =
            [
                /(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(4|6)0|symbian|treo|up\.(browser|link)|vodafone/,
                /wap|windows ce|xda|xiino|android|ipad|playbook|silk/
            ];
        
        gRE = new RegExp(
            e.map( function( r ) { return r.source } ).join( "|" ), "i"
        );
    }
    
    if ( gRE4 == null )
    {
        e =
            [
                /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\-/
            ];
        
        gRE4 = new RegExp(
            e.map( function( r ) { return r.source } ).join( "|" ), "i"
        );
    }
    
    var key = navigator.userAgent || navigator.vendor || window.opera;
    
    return gRE.test( key ) ||
           gRE4.test( key.substr( 0, 4 ) );
}
M Katz
  • 5,098
  • 3
  • 44
  • 66
3

I advise you check out http://wurfl.io/

In a nutshell, if you import a tiny JS file:

<script type='text/javascript' src="//wurfl.io/wurfl.js"></script>

you will be left with a JSON object that looks like:

{
 "complete_device_name":"Google Nexus 7",
 "is_mobile":true,
 "form_factor":"Tablet"
}

(that's assuming you are using a Nexus 7, of course) and you will be able to do things like:

if(WURFL.form_factor == "Tablet"){
    //dostuff();
}

This is what you are looking for.

Disclaimer: I work for the company that offers this free service. Thanks.

Luca P.
  • 1,021
  • 8
  • 20
  • 1
    And howcome this does not recognize safari on iphone ? – Amyth Sep 06 '16 at 02:05
  • Can you expand on what browser you are using (exact UA string would be perfect), what data you are getting and what you are expecting? – Luca P. Sep 07 '16 at 13:11
  • I too tried wurfl, I am on a iPhone 5C running IOS 11.2. Its not recognising Safari as a mobile browser. I'm expecting to use "is_mobile" : true and then "form_factor": Smartphone and its not returning either. – Mike Wells Nov 17 '17 at 16:51
  • I had to turn to the Mobile Data gurus in the company and they tell me that OS 11.2 doesn't run on the 5C. Lowest device is the 5S. So something isn't right in what you wrote. Feel free to contact ScientiaMobile offline to verify where the disconnect might be. Thanks – Luca P. Nov 20 '17 at 02:01
3

This is just an es6 port of the accepted answer that I'm using in my project. Note that this also includes tablets.

export const isMobile = () => {
  const vendor = 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(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino|android|ipad|playbook|silk/i.test(
      vendor
    ) ||
    /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(
      vendor.substr(0, 4)
    )
  );
};
Andi
  • 3,249
  • 1
  • 20
  • 12
3

I have faced some scenarios where above answers dint work for me. So i came up with this. Might be helpful to someone.

if(/iPhone|iPad|iPod|Android|webOS|BlackBerry|Windows Phone/i.test(navigator.userAgent)
 || screen.availWidth < 480){
//code for mobile
}

It depends on your use case. If you focus on screen use screen.availWidth, or you can use document.body.clientWidth if you want to render based on document.

Thyagarajan C
  • 7,915
  • 1
  • 21
  • 25
3

This is what I use. I know userAgent sniffing is frowned upon, but my need happens to be one of the exclusions!

<script>
var brow = navigator.userAgent;
    if (/mobi/i.test(brow)) {
        alert('Mobile Browser');
        // Do something for mobile
    } else {
        alert('Not on Mobile');
        // Do something for non mobile
    }
</script>
Born2Discover
  • 133
  • 13
3

UserAgent is not 100% reliable.

window.navigator.maxTouchPoints > 1;

This is just enough! It excludes phone emulators in browser dev console. That was important for me.

f v
  • 350
  • 3
  • 5
2

The best must be :

var isMobile = (/Mobile/i.test(navigator.userAgent));

But like like Yoav Barnea says...

// Seem legit
var isMobile = ('DeviceOrientationEvent' in window || 'orientation' in window);
// But with my Chrome on windows, DeviceOrientationEvent == fct()
if (/Windows NT|Macintosh|Mac OS X|Linux/i.test(navigator.userAgent)) isMobile = false;
// My android have "linux" too
if (/Mobile/i.test(navigator.userAgent)) isMobile = true;

After this 3 tests, i hope var isMobile is... ok

molokoloco
  • 4,504
  • 2
  • 33
  • 27
2

Here is he full function

function isMobile(){
    return (/(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|android|ipad|playbook|silk/i.test(navigator.userAgent||navigator.vendor||window.opera)||/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((navigator.userAgent||navigator.vendor||window.opera).substr(0,4)))
}

jQuery.noConflict();
jQuery(document).ready(function(){
    if(isMobile()) alert("Mobile"); else alert("Not Mobile");
});
Fred Wuerges
  • 1,965
  • 2
  • 21
  • 42
David Latty
  • 87
  • 1
  • 6
  • .substr(0,4) returns first 4 letters. How does it detect "android.+mobile"? – raacer Aug 24 '15 at 21:31
  • 1
    @raacer there are actually two regexes in the answer (both on the same line) - the first one checks against the entire UA string, and looks for android, mobile etc, while the second one only checks against the first 4 characters of the UA. – JackW Aug 27 '15 at 13:45
  • It worked! thanks so much. – Freddy Daniel Sep 22 '21 at 21:46
2

Here's an ECMAScript 6 solution (TypeScript ready)

public isMobile(): boolean {
  let check = false;
  ((a => {
      if (/(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(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|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(a.substr(0, 4))) check = true;
      }))(navigator.userAgent || navigator.vendor);
  return check;
 }
0x1ad2
  • 8,014
  • 9
  • 35
  • 48
  • 1
    why not just return the `if` condition instead of having this whole `check` variable? – Vic Apr 20 '18 at 19:15
2

Note that Most newer-gen mobile devices now have resolutions greater than 600x400. ie, an iPhone 6....

Proof of test: ran the most upvoted and most recent posts here, with an optional check once run like so:

(function(a){
    window.isMobile = (/(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(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|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(a.substr(0,4)))
})(navigator.userAgent||navigator.vendor||window.opera);

alert("This browser was found to be a % browser.", window.isMobile ? 'mobile' : 'desktop');

Somehow, the following results were returned on the following Browser Apps. Specs: iPhone 6S, iOS 10.3.1.

Safari (latest): Detected it as a mobile.

Chrome (latest): Did not detect it as a mobile.

SO, i then tested the suggestion from Lanti (https://stackoverflow.com/a/31864119/7183483), and it did return the proper results (mobile for all iOS devices, and desktop for my Mac). Therefore, i proceeded to edit it a little since it would fire twice (for both mobile and Tablet). I then noticed when testing on an iPad, that it also returned as a mobile, which makes sense, since the Parameters that Lanti uses check the OS more than anything. Therefore, i simply moved the tablet IF statement inside the mobile check, which would return mobile is the Tablet check was negative, and tablet otherwise. I then added the else clause for the mobile check to return as desktop/laptop, since both qualify, but then noticed that the browser detects CPU and OS brand. So i added what is returned in there as part of else if statement instead. To cap it, I added a cautionary else statement in case nothing was detected. See bellow, will update with a test on a Windows 10 PC soon.

Oh, and i also added a 'debugMode' variable, to easily switch between debug and normal compiling.

Dislaimer: Full credit to Lanti, also that this was not tested on Windows Tablets... which might return desktop/laptop, since the OS is pure Windows. Will check once I find a friend who uses one.

function userAgentDetect() {
    let debugMode = true;
    if(window.navigator.userAgent.match(/Mobile/i)
        || window.navigator.userAgent.match(/iPhone/i)
        || window.navigator.userAgent.match(/iPod/i)
        || window.navigator.userAgent.match(/IEMobile/i)
        || window.navigator.userAgent.match(/Windows Phone/i)
        || window.navigator.userAgent.match(/Android/i)
        || window.navigator.userAgent.match(/BlackBerry/i)
        || window.navigator.userAgent.match(/webOS/i)) {
        if (window.navigator.userAgent.match(/Tablet/i)
            || window.navigator.userAgent.match(/iPad/i)
            || window.navigator.userAgent.match(/Nexus 7/i)
            || window.navigator.userAgent.match(/Nexus 10/i)
            || window.navigator.userAgent.match(/KFAPWI/i)) {
            window.deviceTypeVar = 'tablet';
            if (debugMode === true) {
                alert('Device is a tablet - ' + navigator.userAgent);
            }
        } else {
            if (debugMode === true) {
                alert('Device is a smartphone - ' + navigator.userAgent);
            };
            window.deviceTypeVar = 'smartphone';
        }
    } else if (window.navigator.userAgent.match(/Intel Mac/i)) {
        if (debugMode === true) {
            alert('Device is a desktop or laptop- ' + navigator.userAgent);
        }
        window.deviceTypeVar = 'desktop_or_laptop';
    } else if (window.navigator.userAgent.match(/Nexus 7/i)
        || window.navigator.userAgent.match(/Nexus 10/i)
        || window.navigator.userAgent.match(/KFAPWI/i)) {
        window.deviceTypeVar = 'tablet';
        if (debugMode === true) {
            alert('Device is a tablet - ' + navigator.userAgent);
        }
    } else {
        if (debugMode === true) {
            alert('Device is unknown- ' + navigator.userAgent);
        }
        window.deviceTypeVar = 'Unknown';
    }
}
Community
  • 1
  • 1
jlmurph
  • 1,050
  • 8
  • 17
2

Using Regex (from detectmobilebrowsers.com):

/* eslint-disable */
export const IS_MOBILE = (function (a) {
  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(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|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(
        a.substr(0,4)
      )
  )
  // @ts-ignore
})(navigator.userAgent || navigator.vendor || window.opera)
/* eslint-enable */
  • if a user is using Chrome in Desktop mode, it fill fail. Combined with media query would work alright – Aleks Aug 16 '20 at 21:27
2

Ah yes, the age old question...

It really depends on what you want to do in response to the knowledge.

1. Do you want to change UI so it fits nicely on different screen sizes?

Use media queries.

2. Do you want to show/hide things or change functionality based on mouse vs touch?

This answer above will do however there could be cases where a user has both and switches around. In that scenario you can toggle some JS variable and/or add a class to the document body when you detect mouse or touch events

  window.addEventListener("mousemove", function () {
    isTouch = false;
    document.body.classList.add("canHover");
  });
  window.addEventListener("touchstart", function () {
    isTouch = true;
    document.body.classList.remove("canHover");
  });
body.canHover #aButtonOrSomething:hover {
  //css attributes
}
  document
    .getElementById("aButtonOrSomething")
    .addEventListener("mouseover", showTooltip);
  document
    .getElementById("aButtonOrSomething")
    .addEventListener("click", function () {
      if (isTouch) showTooltip();
    });

3. Do you want to do something specific knowing exactly what device they have?

Use the accepted answer.

1

what about using "window.screen.width" ?

if (window.screen.width < 800) {
// do something
}

or

if($(window).width() < 800) {
//do something
}

I guess this is the best way because there is a new mobile device every day !

(although I think it's not that supported in old browsers, but give it a try :) )

Ahmad Yousef
  • 621
  • 9
  • 20
1

return 'ontouchstart' in window && window.screen.availWidth < 768

How about this, it expands on answer above but also checks the screen size

Dave Keane
  • 729
  • 8
  • 19
1

This is how you can find out, which device is user using.

if (/ipad|tablet/i.test(navigator.userAgent)) {
    console.log("it's a Ipad"); // your code here
}
else if (/mobile/i.test(navigator.userAgent)) {
     console.log("it's a Mobile");
} else {
     console.log("it's a Desktop");
}
aadilraza339
  • 103
  • 3
  • 1
    So, checking for other keywords (iPhone, Android, ...) is no longer necessary as suggested in https://stackoverflow.com/a/44663015 to detect mobile devices? – Simon Ferndriger Jul 26 '22 at 04:45
1
  function isMobile() {
    if ('maxTouchPoints' in navigator) return navigator.maxTouchPoints > 0;

    const mQ = matchMedia?.('(pointer:coarse)');
    if (mQ?.media === '(pointer:coarse)') return !!mQ.matches;
    
    if ('orientation' in window) return true;
    
    return /\b(BlackBerry|webOS|iPhone|IEMobile)\b/i.test(navigator.userAgent) ||
      /\b(Android|Windows Phone|iPad|iPod)\b/i.test(navigator.userAgent);
  }

navigator.userAgent sniffing is not recommended since it's not reliable and heavily varies. As you can see here: https://developers.whatismybrowser.com/useragents/explore/ the navigator.userAgent strings can vary greatly between versions of the same browser.

This MDN article can back this statement: https://developer.mozilla.org/en-US/docs/Web/HTTP/Browser_detection_using_the_user_agent#avoiding_user_agent_detection.

The answer above is a refactor of the suggested solution for mobile detection from the noted MDN article. It relies on feature checks first and then fallbacks as a last resort to navigator.userAgent sniffing.

Happy coding! <3

stamat
  • 1,832
  • 21
  • 26
  • Is not working for me, how do you use it? – Sanxofon Feb 23 '23 at 05:49
  • @Sanxofon hey I think I forgt to add `function` in front of the the function name Anyway just call the function `isMobile();` and it should return `true` if mobile device detected or `false` if not. – stamat Feb 25 '23 at 10:33
1

I think this is the real protecting soltution.

Testet on Chrome & Firefox, Mobile and on Desktop.

var ___isMobileDevice;
const isMobileDeviceCheck = () => {
    const mobileOsRegExp = "(Android|webOS|iPhone|iPod)";
    if(screen.width < 500 || navigator.userAgent.match('/'+mobileOsRegExp+'/i')) {
        ___isMobileDevice = true;
    }
    if (___isMobileDevice) {
        if (typeof window.orientation === "undefined") {
            ___isMobileDevice = false; 
        }
    }
    if (typeof navigator.userAgentData != "undefined" && !navigator.userAgentData.mobile) {
        ___isMobileDevice = false; 
    }
    if ( typeof window.orientation !== "undefined" && ___isMobileDevice ) {
        if (window.navigator.maxTouchPoints > 1 && (navigator.userAgentData.mobile || localStorage.mobile || 'ontouchstart' in document)) {
            // mobile device found
            console.log('Is mobile device!'); 
        }
    }
}
window.onresize = () => {
    isMobileDeviceCheck();
}
isMobileDeviceCheck();

PS: A Useragent switcher as a browser extension cannot fool you with this code.

MaZzIMo24
  • 139
  • 1
  • 6
1

By mutually-exclusive feature-detection

const hasCoarsePointer = () => window.matchMedia("(pointer: coarse)").matches
const hasMobileWidth = (maxWidth = 639) =>
  window.matchMedia(`(max-width: ${maxWidth}px)`).matches
const hasMultipleTouchPoints = () => navigator.maxTouchPoints > 1
const hasTouchEvents = () => "ontouchstart" in document.documentElement

export const isMobile = ({ maxWidth } = {}) => {
  return (
    hasCoarsePointer() &&
    hasMultipleTouchPoints() &&
    hasMobileWidth() &&
    hasTouchEvents()
  )
}

joined

export const isMobile = ({ maxWidth = 639 } = {}) => {
  return (
    window.matchMedia("(pointer: coarse)").matches &&
    navigator.maxTouchPoints > 1 &&
    window.matchMedia(`(max-width: ${maxWidth}px)`).matches &&
    "ontouchstart" in document.documentElement
  )
}

*May 5, 2023: window.matchMedia is currently a W3C Working Draft, maxTouchPoints and ontouchstart are in a W3C Editor's Draft. Use with caution.

Leo Dutra
  • 162
  • 3
  • 11
0

This could also be a solution.

var isMobile = false; //initiate as false

  // device detection
  if(/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|ipad|iris|kindle|Android|Silk|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(navigator.userAgent) 
  || /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(navigator.userAgent.substr(0,4))) isMobile = true;

  console.log('Mobile device:'+isMobile);

  var doc_h = $(document).height(); // returns height of HTML document
  var doc_w = $(document).width(); // returns width of HTML document
  console.log('Height: '+doc_h);
  console.log('width: '+doc_w);

  var iPadVertical = window.matchMedia("(width: 768px) and (height: 1024px) and (orientation: portrait)");
  var iPadHoricontal = window.matchMedia("(width: 1024px) and (height: 767px) and (orientation: landscape)");

  console.log('Height: '+doc_h);
  console.log('width: '+doc_w);

  if (iPadVertical.matches) {
      console.log('Ipad vertical detected');
  }else if (iPadHoricontal.matches){
      console.log('Ipad horicontal detected');
  }else {
      console.log('No Ipad');
  }

If you use both methods, you will get a perfect way to detect different devices.

Friis1978
  • 1,179
  • 9
  • 16
0
//true / false
function isMobile()
{
   return (/Android|webOS|iPhone|iPad|iPod|BlackBerry/i.test(navigator.userAgent) ); 
}

also you can follow this tutorial to detect a specific mobile. Click here.

gtzinos
  • 1,205
  • 15
  • 27
0

In any case, checking for type of device must be called just ONE TIME: your phone can't surprisingly stay a desktop in a moment :)

So, code for checking by userAgent, suggested here sometime ago, have to be look like that:

(function(a){window.isMobile = (/(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(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|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(a.substr(0,4)))})(navigator.userAgent||navigator.vendor||window.opera);

console.info('This is %s device', window.isMoblie ? 'mobile' : 'desktop');
SynCap
  • 6,244
  • 2
  • 18
  • 27
0

There is simple trick to detect whether it is a mobile device or not. Just check if the ontouchstart event exist:

function isMobile()
{
    return "ontouchstart" in window;
}
Martin Wantke
  • 4,287
  • 33
  • 21
  • 6
    Won't work with laptops and dekstops with touchscreen monitors. Also will be an issue with hybrid pc's like Surface. Less of an issue with desktops but there are more touchscreen laptops being sold these days. – blissfool Jun 04 '18 at 21:01
0

// Function returns true if current device is phone
function isMobile() {

    // regex from http://detectmobilebrowsers.com/mobile
    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(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test(navigator.userAgent) || /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(navigator.userAgent)
}

console.log({
    isMobile: isMobile()
});

0

I haven't seen anyone suggested:

window.navigator.connection.type

this only exists on mobile, but not on desktop browsers. It is simpler to just check the existence of that property, i.e. if(window && window.navigator && window.navigator.connection && window.navigator.connection.type) => then it is mobile

NOTE: this is experimental

EDIT (07.2022): The feature is being deemed as a potential tracking exploit, so it is being removed from latest versions. In other words, don't use this!

theCuriousOne
  • 1,022
  • 10
  • 22
0

I searched Replit's code ( because it had errors all over the website ) , until I saw:

(function (isTouchDevice) {
      if (!isTouchDevice) return;
      var isTouchClass = 'is-touch-device';
      var docElement = document.documentElement;
      docElement.className = docElement.className ? [docElement.className, isTouchClass].join(' ') : isTouchClass;
    })(('ontouchstart' in window) || window.DocumentTouch && document instanceof DocumentTouch);

so I modified it into something like this:

function isTouchDevice() {
    if (!(("ontouchstart" in window) || (window.DocumentTouch && document instanceof DocumentTouch))) {
        return false
    }
    return true
}

Values from different user agents:

  • Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36: false
  • Mozilla/5.0 (Linux; Android 10; Mi A2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Mobile Safari/537.36: true
RixTheTyrunt
  • 185
  • 3
  • 11
-1

The touchscreen and orientation solutions won't work on some PCs.

Some laptops have a touchscreen and hopefully more in the future. Also while I can't test it myself, some graphical tablets that work as a screen are a touchscreen capable.

Detecting orientation wouldn't work either. Some PCs like the Microsoft Surface Books have a detachable screen making it work like a tablet, including orientation support. Yet it is still a real PC.

If you have to detect and differentiate between PC and mobile, just read the user agent.
I don't like it either but it remains the best way.

Wiz
  • 11
  • 4
-1

This is the best way ive found nto work in all cases.

const deviceMotionAvailable = Array.isArray(navigator.userAgent.match(/Android/i) || navigator.userAgent.match(/iPhone/i))

Joel
  • 1,309
  • 2
  • 10
  • 20
  • 1
    That's dreadful and will have many false positives (especially for non-phone-sized Android devices) as well as false negatives (while Apple and Android are almost ubiquitous in the mobile market, they aren't completely ubiquitous). – Quentin Nov 11 '22 at 22:34
  • lol. you're correct didnt work on Android. How about this approach? /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent) – Joel Nov 14 '22 at 22:05
-5

I usually find that the simpler approach of checking the visibility of a particular element (say burger icon) that is only visible on mobile views works well and is far safer than relying on a very complicated regex. That would be difficult to test works 100%.

function isHidden(el) {
   return (el.offsetParent === null);
}
user432350
  • 161
  • 9