24

I can detect iOS 13 on iPhone but in iPad OS 13 navigator.platform comes as MacIntel. So it is not possible to get iPad identified using below code, but it works perfectly on iPhone.

    if (/iP(hone|od|ad)/.test(navigator.platform)) {
            var v = (navigator.appVersion).match(/OS (\d+)_(\d+)_?(\d+)?/);
            var version = [parseInt(v[1], 10), parseInt(v[2], 10), parseInt(v[3] || 0, 10)];
            return version;
    }

When we request for mobile website using the browser on iPad navigator.platform returns as iPad and works perfectly.

Can anyone suggest a way to identify iPad running on iOS 13 and up using Javascript?

MaDu_LK
  • 2,700
  • 5
  • 24
  • 39
  • 1
    Possible duplicate of [Tell iPadOS from macOS on the web](https://stackoverflow.com/questions/56578799/tell-ipados-from-macos-on-the-web) – Eugene Berdnikov Sep 03 '19 at 06:49

6 Answers6

28

I was able to get iPad detection working by checking for navigator.maxTouchPoints as well as navigator.platform. It's not perfect (as discussed in the comments below) but it's the best solution I've come across so far so I wanted to share.

const iPad = (userAgent.match(/(iPad)/) /* iOS pre 13 */ || 
  (navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1) /* iPad OS 13 */);
Stenerson
  • 862
  • 7
  • 16
  • Wouldn't this return true if the user has a touch screen monitor? – Kris Sep 17 '19 at 20:31
  • @Kris My intention was to only return true if it's a touch screen monitor that also was running Safari (i.e. only iOS devices), however... I didn't take in account that Chrome (and probably others) have "Safari" in their user agent string. I still think I'm on the right track though... just need some more iterations – Stenerson Sep 18 '19 at 18:26
  • 1
    @Kris I've updated this to use `navigator.platform` which I think will work at least for my app's purposes. There are no touch screen macs (yet ) so any touch screen MacIntel platform should be iPadOS 13+? I guess they could have a third-party touchscreen monitor but I'm not sure how MacOS would respond to that?? I'd be **happy** to use another method but this is the only one that I've seen to work so far. – Stenerson Sep 18 '19 at 18:37
  • Adding window.devicePixelRatio detection could help to differentiate between iPad and iPhone. On newer iPhones window.devicePixelRatio == 3, iPads all window.devicePixelRatio == 2. https://51degrees.com/blog/device-detection-for-apple-iphone-and-ipad – Justin Putney Nov 06 '19 at 18:26
  • @JustinPutney Thats not a good solution since iPhone 2-7 returns `2`, too. – Mick Dec 03 '19 at 14:20
  • @Mick you have to have a different detect for iPhone 2-7. In that case, you can simply check the userAgent. E.g, var isIOS = (navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1 && !window.MSStream), isIPad = uAgent.indexOf("ipad") > -1 || (isIOS && window.devicePixelRatio < 3), isIPhone = uAgent.indexOf("iphone") > -1 || (isIOS && window.devicePixelRatio > 2); – Justin Putney Dec 04 '19 at 15:20
  • 1
    Phaser solution https://github.com/azerion/phaser/commit/554eeca5935f6311227c9be1c1331ffcd94abdc2#diff-de672b8173a52c4541cf4d3841682351R1228 – Florent Jan 28 '20 at 10:03
  • The Phaser solution works like a charme! Thanks all for your time. – Mauro Casula Sep 24 '20 at 17:05
5

TL;DR

const iPad = !!(navigator.userAgent.match(/(iPad)/)
  || (navigator.platform === "MacIntel" && typeof navigator.standalone !== "undefined"))

We can use the navigator.standalone param. It's non-standard and used only on iOS Safari at present:

Navigator.standalone

Returns a boolean indicating whether the browser is running in standalone mode. Available on Apple's iOS Safari only.

When combined with navigator.platform === "MacIntel" iPad's are the only devices that define this property, therefore typeof navigator.standalone !== "undefined" filters out Macs running Safari (touchscreen or not).

I set up a CodeSandbox and manually tested on Browserstack, seems to work as expected: https://bc89h.csb.app/

Version Detection (iOS only)

I haven't tested this too extensively but should give anyone else looking a good place to start:

const version = navigator.userAgent.match(/Version\/(\d+)\.(\d+)\.?(\d+)?/);
const major = version && version[1] ? version[1] : "";
const minor = version && version[2] ? version[2] : "";
const patch = version && version[3] ? version[3] : "";

The above takes the version and breaks it down into major, minor and patch elements. This seems to work for iOS 12 & 13 which I ran a quick test against. The above SandBox link shows the output.

GuyC
  • 5,694
  • 23
  • 36
3

You can use WURFL.js, which is free if you just want to know what device is in use: https://web.wurfl.io/#wurfl-js

Full disclosure, I'm the COO of the company behind WURFL and ImageEngine, but I'm also an open-source developer :)

WURFL.js can tell you what OS is in use and if it's an iPhone or iPad.

To use it, just add this to the head of your page:

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

Then you can use the device information in javascript:

console.log(WURFL.complete_device_name);

Note: With the paid version you can get more accurate results (ex: Apple iPhone XS Max, Apple iPad Pro 11) as well as a many other device characteristics.

If you don't need the device information for the initial paint, you can also run this asynchronously so it doesn't block rendering. Stick it at the end of the body and use async or defer:

<script type="text/javascript">
window.addEventListener('WurflJSDetectionComplete', () => {
   console.log(`Device: ${WURFL.complete_device_name}`);
});
</script>
<script type="text/javascript" src="//wurfl.io/wurfl.js" async></script>

While you're at it, you might as well use this improved device information to enhance Google Analytics: https://www.scientiamobile.com/wurfljs-google-analytics-iphone/

Note that unlike the other answers, this one requires no ongoing maintenance on the part of the developer.

SteveK
  • 976
  • 1
  • 8
  • 10
  • On iPad, it only says tablet if I uncheck the request desktop site in safari settings, which all users will not do probably. By default it says Desktop. – Rudy Nov 17 '20 at 17:18
  • Yes indeed, thanks for the clarification. Apple introduced this within the last year and unfortunately there is no known way around it, especially with so much emphasis on preventing fingerprinting. – SteveK Nov 21 '20 at 00:33
2

It's simple - you can't. You can only use hacks like this one

let isIOS = /iPad|iPhone|iPod/.test(navigator.platform)
|| (navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1)

The first condition for "mobile", second for iPad mimicking Macintosh Safari. It works reliably for me, but who knows what will change in the future. If there are to be macs with touch screen, this will detect not only iPads in Desktop mode, but also regular Macs.

The other way is feature detection - you can, but probably shouldn't rely on browser features support. For example, Safari on Mac doesn't support date picker, but the mobile one does.

Anyway, I suggest you try not to rely on platform detection (which will be broken in future anyway) and use feature detection (but not to distinct platforms) as Modernizr instead - if you want to use Date picker, you can check if it is available and if it's not, use an HTML solution instead. Don't lock out users just because they use some other browser. You may notify them but give them the option to hide the notification and use your site anyway.

As a user, I hate it when someone tells me to go and use another browser

Just remember - platform detection indicates a bad code smell since all these are hacks.

NebulaFox
  • 6,239
  • 7
  • 40
  • 60
kikiwora
  • 1,514
  • 8
  • 7
1

I did expand the implementation a little to make use of some more default browser features on iPad OS vs Mac OS Catalina. According to my tests on diverse iPads and all late iOS Devices this works well.

var isIPadOs = window.AuthenticatorAssertionResponse === undefined
        && window.AuthenticatorAttestationResponse === undefined
        && window.AuthenticatorResponse === undefined
        && window.Credential === undefined
        && window.CredentialsContainer === undefined
        && window.DeviceMotionEvent !== undefined
        && window.DeviceOrientationEvent !== undefined
        && navigator.maxTouchPoints === 5
        && navigator.plugins.length === 0
        && navigator.platform !== "iPhone";

Gist: https://gist.github.com/braandl/f7965f62a5fecc379476d2c055838e36

Simon B.
  • 2,013
  • 18
  • 28
braandl
  • 66
  • 4
  • Thanks for your effort! But couldnt this change with the next iPadOS or iPad device? – Mick Dec 03 '19 at 14:19
  • Yes, absolutly. All these "fingerprinting" methods need to be updated eventually... Though due to my experiance with Apples Browser update policy this should be fine for a while... – braandl Dec 05 '19 at 16:14
  • @braandl thanks for this! There's a typo in `window.CredentialsContainer` though! – Patrick Hübl-Neschkudla Apr 14 '20 at 07:51
0

It's a bit hackish and surely not very future safe but for now we are using the following and it seems to do the trick.

The first block is just sniffing the user agent for older iPads and the the second block after 'OR' is checking if the platform is Macintosh and has touch points. At the time of writing this, there's no official touch screen for Mac yet, so it should be pretty safe for a while.

if ((/\b(iPad)\b/.test(navigator.userAgent)
    && /WebKit/.test(navigator.userAgent)
    && !window.MSStream)
    || (navigator.platform === 'MacIntel'
    && navigator.maxTouchPoints
    && navigator.maxTouchPoints === 5)
  ) {
        return true;
    }
A.G.
  • 128
  • 1
  • 8