Determine if user navigated from mobile Safari

JavascriptIphoneMobile SafariWeb Clips

Javascript Problem Overview


I have an app, and I'd like to redirect the users to different pages based on where they are navigating from.

If navigating from web clip, do not redirect. If navigating from mobile Safari, redirect to safari.aspx. If navigating from anywhere else, redirect to unavailable.aspx

I was able to use https://stackoverflow.com/questions/2738766/iphone-webapps-is-there-a-way-to-detect-how-it-was-loaded-home-screen-vs-safari to determine if the user was navigating from a web clip, but I'm having trouble determining if the user navigated from mobile Safari on an iPhone or iPod.

Here's what I have:

if (window.navigator.standalone) {
    // user navigated from web clip, don't redirect
}
else if (/*logic for mobile Safari*/) {
    //user navigated from mobile Safari, redirect to safari page
    window.location = "safari.aspx";
}
else {
    //user navigated from some other browser, redirect to unavailable page
    window.location = "unavailable.aspx";
}

Javascript Solutions


Solution 1 - Javascript

See https://developer.chrome.com/multidevice/user-agent#chrome_for_ios_user_agent - the user agent strings for Safari on iOS and for Chrome on iOS are inconveniently similar:

Chrome

Mozilla/5.0 (iPhone; U; CPU iPhone OS 5_1_1 like Mac OS X; en) AppleWebKit/534.46.0 (KHTML, like Gecko) CriOS/19.0.1084.60 Mobile/9B206 Safari/7534.48.3

Safari

Mozilla/5.0 (iPhone; U; CPU like Mac OS X; en) AppleWebKit/420+ (KHTML, like Gecko) Version/3.0 Mobile/1A543 Safari/419.3

Looks like the best approach here is to first of all check for iOS as other answers have suggested and then filter on the stuff that makes the Safari UA unique, which I would suggest is best accomplished with "is AppleWebKit and is not CriOS":

var ua = window.navigator.userAgent;
var iOS = !!ua.match(/iPad/i) || !!ua.match(/iPhone/i);
var webkit = !!ua.match(/WebKit/i);
var iOSSafari = iOS && webkit && !ua.match(/CriOS/i);

Solution 2 - Javascript

UPDATE: This is a very old answer and I cannot delete it because the answer is accepted. Check unwitting's answer below for a better solution.


You should be able to check for the "iPad" or "iPhone" substring in the user agent string:

var userAgent = window.navigator.userAgent;

if (userAgent.match(/iPad/i) || userAgent.match(/iPhone/i)) {
   // iPad or iPhone
}
else {
   // Anything else
}

Solution 3 - Javascript

best practice is:

function isMobileSafari() {
	return navigator.userAgent.match(/(iPod|iPhone|iPad)/) && navigator.userAgent.match(/AppleWebKit/)
}

Solution 4 - Javascript

Merged all the answers and comments. This is the result.

function iOSSafari(userAgent) {
    return /iP(ad|od|hone)/i.test(userAgent) &&
      /WebKit/i.test(userAgent) &&
      !(/(CriOS|FxiOS|OPiOS|mercury)/i.test(userAgent));
}


// Usage:
// if iOSSafari(window.navigator.userAgent) { /* iOS Safari code here */ }

// Testing:
var iPhoneSafari = [
  "Mozilla/5.0 (iPhone; CPU iPhone OS 14_4_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0.3 Mobile/15E148 Safari/604.1",
  "Mozilla/5.0 (Apple-iPhone7C2/1202.466; U; CPU like Mac OS X; en) AppleWebKit/420+ (KHTML, like Gecko) Version/3.0 Mobile/1A543 Safari/419.3",
  "Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.34 (KHTML, like Gecko) Version/11.0 Mobile/15A5341f Safari/604.1",
  "Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1",
  "Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A5370a Safari/604.1",
  "Mozilla/5.0 (iPhone; CPU iPhone OS 12_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.0 Mobile/15E148 Safari/604.1",
  "Mozilla/5.0 (iPhone9,3; U; CPU iPhone OS 10_0_1 like Mac OS X) AppleWebKit/602.1.50 (KHTML, like Gecko) Version/10.0 Mobile/14A403 Safari/602.1",
  "Mozilla/5.0 (iPhone9,4; U; CPU iPhone OS 10_0_1 like Mac OS X) AppleWebKit/602.1.50 (KHTML, like Gecko) Version/10.0 Mobile/14A403 Safari/602.1",
];
console.log("All true:", iPhoneSafari.map(iOSSafari));

var iPhoneNotSafari = [
  "Mozilla/5.0 (iPhone; CPU iPhone OS 12_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/69.0.3497.105 Mobile/15E148 Safari/605.1",
  "Mozilla/5.0 (iPhone; CPU iPhone OS 12_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) FxiOS/13.2b11866 Mobile/16A366 Safari/605.1.15",
];
console.log("All false:", iPhoneNotSafari.map(iOSSafari));

Solution 5 - Javascript

Falling code only find mobile safari and nothing else (except dolphin and other small browsers)

  (/(iPad|iPhone|iPod)/gi).test(userAgent) &&
  !(/CriOS/).test(userAgent) &&
  !(/FxiOS/).test(userAgent) &&
  !(/OPiOS/).test(userAgent) &&
  !(/mercury/).test(userAgent)

Solution 6 - Javascript

Seeing all the answers, here are some tips about the proposed RegExes:

  • AppleWebKit matches Desktop Safari too (not only mobile)
  • no need to call .match more than once for such simple regexes, and prefer the lighter .test method.
  • the g (global) regex flag is useless while the i (case insensitive) can be useful
  • no need for capture (parenthesis), we are just testing the string

I'm just using this since getting true for mobile Chrome is OK for me (same behavior):

/iPhone|iPad|iPod/i.test(navigator.userAgent)

(I just want to detect if the device is a target for an iOS app)

Solution 7 - Javascript

This regex works for me, clean and simple:

const isIOSSafari = !!window.navigator.userAgent.match(/Version\/[\d\.]+.*Safari/);

Solution 8 - Javascript

Actually, there isn't a silver bullet of detecting mobile safari. There are quite a few browsers may use the keywords of the user agent of mobile safari. Maybe you can try feature detection and keep updating the rule.

Solution 9 - Javascript

I upvoted @unwitting 's answer, as it inevitably got me going. However, when rendering my SPA in an iOS Webview, I needed to tweak it a bit.

function is_iOS () {
    /*
        Returns (true/false) whether device agent is iOS Safari
    */
    var ua = navigator.userAgent;
    var iOS = !!ua.match(/iPad/i) || !!ua.match(/iPhone/i);
    var webkitUa = !!ua.match(/WebKit/i);
            
    return typeof webkitUa !== 'undefined' && iOS && webkitUa && !ua.match(/CriOS/i);
};

The main difference being, the renaming of webkit to webkitUa, so as to prevent clashing with the root webkit object used as a message handler between the SPA & UIView.

Solution 10 - Javascript

I know this is an old thread, but I'd like to share my solution with you guys.

I needed to detect when an user navigates from Desktop Safari (Because we're in middle 2017, and Apple hasn't give any support for input[type="date"] YET...

So, I made a fallback custom datepicker for it) . But only applies to safari in desktop because that input type works fine in mobile Safari. So, I made this Regex to only detect desktop Safari. I already tested it and it doesn't match with Opera, Chrome, Firefox or Safari Mobile.

Hope it may help some of you guys.

if(userAgent.match(/^(?!.*chrome).(?!.*mobile).(?!.*firefox).(?!.*iPad).(?!.*iPhone).*safari.*$/i)){
  $('input[type="date"]').each(function(){
    $(this).BitmallDatePicker();
  })
}

Solution 11 - Javascript

I was looking for this answer and I remembered I came across this before.

The most reliable way to detect Safari on iOS in JavaScript is

if (window.outerWidth === 0) {
    // Code for Safari on iOS
} 

or 

if (window.outerHeight === 0) {
    // Code for Safari on iOS
} 

For some reason Safari on iOS returns 0 for window.outerHeight property and window.outerWidth property.

This is for all iPads and iPhones on all versions of iOS. Every other browser and device this property works normally.

Not sure if they intend to change this but for now it works well.

Solution 12 - Javascript

function isIOS {
  var ua = window.navigator.userAgent;
  return /(iPad|iPhone|iPod).*WebKit/.test(ua) && !/(CriOS|OPiOS)/.test(ua);
}

Solution 13 - Javascript

var isApple = false;    
if(/iPhone|iPad|iPod/i.test(navigator.userAgent)) {      
  isApple = true;
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionStevenView Question on Stackoverflow
Solution 1 - JavascriptunwittingView Answer on Stackoverflow
Solution 2 - JavascriptDaniel VassalloView Answer on Stackoverflow
Solution 3 - JavascriptappsthatmatterView Answer on Stackoverflow
Solution 4 - JavascriptКонстантин ВанView Answer on Stackoverflow
Solution 5 - JavascriptaWebDeveloperView Answer on Stackoverflow
Solution 6 - Javascriptantoine129View Answer on Stackoverflow
Solution 7 - JavascriptcyianiteView Answer on Stackoverflow
Solution 8 - JavascriptLightView Answer on Stackoverflow
Solution 9 - JavascriptpimView Answer on Stackoverflow
Solution 10 - Javascriptedd2110View Answer on Stackoverflow
Solution 11 - JavascriptnaeluhView Answer on Stackoverflow
Solution 12 - JavascriptKugutsumenView Answer on Stackoverflow
Solution 13 - JavascriptDiogo SouzaView Answer on Stackoverflow