179

How to detect Safari browser using JavaScript? I have tried code below and it detects not only Safari but also Chrome browser.

function IsSafari() {

  var is_safari = navigator.userAgent.toLowerCase().indexOf('safari/') > -1;
  return is_safari;

}
Kara
  • 5,650
  • 15
  • 48
  • 55
Tomas
  • 15,501
  • 38
  • 136
  • 233
  • 1
    Some of JS code related to file submitting works deferentially for Safari, for Chrome works fine. – Tomas Oct 30 '11 at 10:49
  • 1
    You should almost certainly be testing for whatever differences in the APIs there are. There are other WebKit based browsers beyond Safari and Chrome. – Quentin Oct 30 '11 at 12:48
  • 13
    There are many reasons one might wish to detect the browser. For example, as of this writing certain aspects of the SVG engine such as filters are broken in Safari, but working in Chrome. – Paul Legato Jun 01 '12 at 06:21
  • Sometimes you just can't fix bug because you can't reproduce it(I don't have access to Mac). I fixed problem on Midori(some BlobBuilder/Blob issue for sendAsBinary shim), but client says there is still an issue with file upload, so the best thing i can think of is just to remove Safari support and use iframes for it(as for old IE) – llamerr May 24 '13 at 12:56
  • 1
    possible duplicate of [How to detect chrome and safari browser (webkit)](http://stackoverflow.com/questions/12625876/how-to-detect-chrome-and-safari-browser-webkit) – anik4e Nov 24 '14 at 09:58

21 Answers21

191

Note: always try to detect the specific behavior you're trying to fix, instead of targeting it with isSafari?

As a last resort, detect Safari with this regex:

var isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent);

It uses negative look-arounds and it excludes Chrome, Edge, and all Android browsers that include the Safari name in their user agent.

Community
  • 1
  • 1
fregante
  • 23,010
  • 11
  • 97
  • 127
  • 2
    This doesn't work. I'm still getting true if I'm using Chrome Browser on an iPhone. – ayjay Feb 23 '15 at 23:09
  • 39
    That's because all browsers on iOS are just wrappers for Safari (with the exception of Opera Mini in _Mini_ mode), including Chrome. This doesn't necessarily mean that they'll _all_ match this test since the userAgent string is up to the wrapper. You might want to [detect Chrome on iOS](http://stackoverflow.com/a/13808053/288906) separately. – fregante Feb 24 '15 at 07:25
  • Dude this worked for me!!! Thanks a ton.. navigator.userAgent was returning values like "5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.99 Safari/537.36" for both Chrome in Windows and Safari in mac. – KaustubhSV Apr 30 '15 at 14:06
  • Very elegant, thanks for this! Using it in my JavaScript copy-to-clipboard library: https://github.com/ryanpcmcquen/simpleJsCopy – ryanpcmcquen Oct 11 '15 at 23:39
  • Not working. This says true for stock android browser. – Pascal Raszyk Oct 29 '15 at 09:49
  • 2
    Fixed now. You're definitely right, the problem with a lot of browsers is that they include other names to try not to be left out. Like Edge includes both Chrome and Safari in its UA. User agent checks are bad for this reason: browsers change and the checks need to be updated. Unfortunately there's no perfect way to detect a browser, it's always a guess. – fregante Oct 29 '15 at 12:32
  • true. We should stick with feature detection for this kind of stuff. Modernizr covers most of the edge cases (for example Image Orientation which only works for mobile Safari). I ended up using Modernizr rather than using the User Agent. – Pascal Raszyk Nov 10 '15 at 21:15
  • 1
    Definitely a good idea to use feature detection, but some behaviors are just hard or nearly impossible to test, for example whether videos on mobile go automatically fullscreen, something that only happens on the iPhone and iPod. To test it, you need to load a video and have the user play it. – fregante Nov 11 '15 at 06:27
  • This was exactly what I needed. I like to use SVG images for logos where possible, but Safari just kept butchering their proportions, so I needed something to detect just Safari so I could run a small script to swap out all the SVG's for PNG's. Thanks for this! – Tessa Oct 26 '16 at 17:38
  • @Tessa are you sure that's necessary? You probably just needed `preserveAspectRatio` – fregante Dec 24 '16 at 04:24
  • @bfred.it I didn't know about that! I'm relatively new to using SVG's in my work so I'll definitely try it out instead! – Tessa Dec 29 '16 at 14:21
  • For what it's worth, I've found that safari's background-color property silently fails with partial transparency colour values. That is, it "does" "render" the color, it just renders it as `transparent`. Anything that overrides that will also override the intended color in other browsers. Point being, feature detection is just sometimes not the way. – Mattias Martens Mar 30 '21 at 17:25
122

You can easily use index of Chrome to filter out Chrome:

var ua = navigator.userAgent.toLowerCase(); 
if (ua.indexOf('safari') != -1) { 
  if (ua.indexOf('chrome') > -1) {
    alert("1") // Chrome
  } else {
    alert("2") // Safari
  }
}
jcubic
  • 51,975
  • 42
  • 183
  • 323
david
  • 3,958
  • 3
  • 20
  • 25
107

As other people have already noted, feature detection is preferred over checking for a specific browser. One reason is that the user agent string can be altered. Another reason is that the string may change and break your code in newer versions.

If you still want to do it and test for any Safari version, I'd suggest using this

var isSafari = navigator.vendor && navigator.vendor.indexOf('Apple') > -1 &&
               navigator.userAgent &&
               navigator.userAgent.indexOf('CriOS') == -1 &&
               navigator.userAgent.indexOf('FxiOS') == -1;

This will work with any version of Safari across all devices: Mac, iPhone, iPod, iPad.

Edit

To test in your current browser: https://jsfiddle.net/j5hgcbm2/

Edit 2

Updated according to Chrome docs to detect Chrome on iOS correctly

It's worth noting that all Browsers on iOS are just wrappers for Safari and use the same engine. See bfred.it's comment on his own answer in this thread.

Edit 3

Updated according to Firefox docs to detect Firefox on iOS correctly

qingu
  • 1,823
  • 1
  • 13
  • 19
  • Thanks for the comment - Updated to detect Chrome on iOS correctly – qingu Nov 07 '15 at 19:46
  • @qingu - I don't understand this javascript, how would I do something like - if(safaribrowser) { do this } else { do that } using the same code what value is 'var isSafari' thanks – GAV Feb 09 '16 at 16:01
  • @GAV: `isSafari` will be `true` in a Safari browser, `false` otherwise. You can simply use the above snippet and then use yours almost as you posted it. `if (isSafari) { do_this(); } else { do_that(); }`. – qingu Feb 09 '16 at 19:05
  • 2
    Unfortunately there's more more reasons to try to figure out the browser than just feature detection. A browser can support a feature, but be buggy (ex: canvas bug in IE10, but the same feature works in IE9). Also Firefox behaves differently than webkit based browsers, such as how it responds to mouse movement. Apple's Safari has reflow bugs that don't exist in Chrome. Some browsers are also performant when doing certain computationally intensive tasks than others. – DemiImp Oct 12 '16 at 04:15
  • Chrome on iOS is kinda Safari as it uses a Safari Webkit engine, it's not really Chrome. – AMilassin Mar 03 '17 at 10:20
  • Works correctly with Safari/Chrome, but thinks Firefox isSafari on mobile on my iPhone. – M3RS Feb 08 '18 at 08:46
  • 2
    @Andras For Firefox you can add `&& !navigator.userAgent.match('FxiOS')` similar to the Chrome check - ref (https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/User-Agent/Firefox) – Petri Pellinen Jul 06 '18 at 07:38
  • Thanks @Andras for reporting the issue with Firefox on iOS and Petri Pellinen for providing a fix. – qingu Jul 13 '18 at 00:24
88

Just use:

var isSafari = window.safari !== undefined;
if (isSafari) console.log("Safari, yeah!");
lukyer
  • 6,141
  • 1
  • 31
  • 28
22

This code is used to detect only safari browser

if (navigator.userAgent.search("Safari") >= 0 && navigator.userAgent.search("Chrome") < 0) 
{
   alert("Browser is Safari");          
}
wahid
  • 1,051
  • 1
  • 8
  • 16
  • 5
    this code only detects wether a webkit browser is not chrome. Many other browsers have the bad idea of including "safari" in their user agent string. For example, Opera: `Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2062.94 Safari/537.36 OPR/24.0.1558.51 (Edition Next)`, or Stock Android browser: `Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.34 Safari/534.24` – rupps Jan 17 '15 at 00:14
  • tossing platform detection can perhaps filter out specific compatibility cases. – ljgww May 11 '15 at 08:49
  • I just checked a half dozen third party iOS browsers, they all spoof the very exact Safari User-Agent. – Mitch Match Nov 07 '15 at 08:49
  • So this will only detect Chrome. And yet, I just found out Chrome 44 no longer has Chrome in the UA, but 'CriOS' instead :( – Mitch Match Nov 07 '15 at 09:02
  • We should always try to do feature detection, and use browser detection as a last resort, since the latter is much more likely to break and to block legitimate users. Any answer which doesn't mention feature detection at all is getting a downvote from me. – Flimm Nov 17 '17 at 09:24
17

Because userAgent for chrome and safari are nearly the same it can be easier to look at the vendor of the browser

Safari

navigator.vendor ==  "Apple Computer, Inc."

Chrome

navigator.vendor ==  "Google Inc."

FireFox (why is it empty?)

navigator.vendor ==  ""

IE (why is it undefined?)

navigator.vendor ==  undefined
tylerlindell
  • 1,451
  • 2
  • 16
  • 18
10

I don't know why the OP wanted to detect Safari, but in the rare case you need browser sniffing nowadays it's problably more important to detect the render engine than the name of the browser. For example on iOS all browsers use the Safari/Webkit engine, so it's pointless to get "chrome" or "firefox" as browser name if the underlying renderer is in fact Safari/Webkit. I haven't tested this code with old browsers but it works with everything fairly recent on Android, iOS, OS X, Windows and Linux.

<script>
    let browserName = "";

    if(navigator.vendor.match(/google/i)) {
        browserName = 'chrome/blink';
    }
    else if(navigator.vendor.match(/apple/i)) {
        browserName = 'safari/webkit';
    }
    else if(navigator.userAgent.match(/firefox\//i)) {
        browserName = 'firefox/gecko';
    }
    else if(navigator.userAgent.match(/edge\//i)) {
        browserName = 'edge/edgehtml';
    }
    else if(navigator.userAgent.match(/trident\//i)) {
        browserName = 'ie/trident';
    }
    else
    {
        browserName = navigator.userAgent + "\n" + navigator.vendor;
    }
    alert(browserName);
</script>

To clarify:

  • All browsers under iOS will be reported as "safari/webkit"
  • All browsers under Android but Firefox will be reported as "chrome/blink"
  • Chrome, Opera, Blisk, Vivaldi etc. will all be reported as "chrome/blink" under Windows, OS X or Linux
  • Old versions of IE have the string MSIE not Trident. Sometimes edge is missing the final e in the word edge. You have to search for edg – PHP Guru Oct 31 '20 at 16:10
  • This should be the new accepted answer, thank you Christopher. – Myndex Nov 01 '20 at 23:33
8

In my case I needed to target Safari on both iOS and macOS. This worked for me:

if (/apple/i.test(navigator.vendor)) {
  // It's Safari
}
Simone
  • 17,439
  • 10
  • 67
  • 96
  • Thanks! This also can detect WKWebView which does not contain Safari string: `Mozilla/5.0 (iPhone; CPU iPhone OS 14_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148` – mikep Feb 22 '21 at 02:51
  • Any reason to use regex for this instead of just doing `navigator.vendor === "Apple Computer, Inc."`? – Newbyte Mar 04 '21 at 21:23
  • Honestly I don't know what `navigator.vendor` might possibly contain, but in my specific case I needed to target any Apple browser in general, so the regex worked for me – Simone Mar 05 '21 at 09:37
7

Only Safari whitout Chrome:

After trying others codes I didn't find any that works with new and old versions of Safari.

Finally, I did this code that's working very well for me:

var ua = navigator.userAgent.toLowerCase(); 
var isSafari = false;
try {
  isSafari = /constructor/i.test(window.HTMLElement) || (function (p) { return p.toString() === "[object SafariRemoteNotification]"; })(!window['safari'] || safari.pushNotification);
}
catch(err) {}
isSafari = (isSafari || ((ua.indexOf('safari') != -1)&& (!(ua.indexOf('chrome')!= -1) && (ua.indexOf('version/')!= -1))));

//test
if (isSafari)
{
  //Code for Safari Browser (Desktop and Mobile)
  document.getElementById('idbody').innerHTML = "This is Safari!";
}
else
{
  document.getElementById('idbody').innerHTML = "Not is Safari!";
}
<body id="idbody">
</body>
alessandrio
  • 3,901
  • 2
  • 27
  • 36
leoledmag
  • 138
  • 1
  • 6
6

I observed that only one word distinguishes Safari - "Version". So this regex will work perfect:

/.*Version.*Safari.*/.test(navigator.userAgent)
Piotr Kowalski
  • 328
  • 3
  • 14
5

I use this

function getBrowserName() {
    var name = "Unknown";
    if(navigator.userAgent.indexOf("MSIE")!=-1){
        name = "MSIE";
    }
    else if(navigator.userAgent.indexOf("Firefox")!=-1){
        name = "Firefox";
    }
    else if(navigator.userAgent.indexOf("Opera")!=-1){
        name = "Opera";
    }
    else if(navigator.userAgent.indexOf("Chrome") != -1){
        name = "Chrome";
    }
    else if(navigator.userAgent.indexOf("Safari")!=-1){
        name = "Safari";
    }
    return name;   
}

if( getBrowserName() == "Safari" ){
    alert("You are using Safari");
}else{
    alert("You are surfing on " + getBrowserName(name));
}
lovepong
  • 565
  • 1
  • 7
  • 17
4

Simplest answer:

function isSafari() {
 if (navigator.vendor.match(/[Aa]+pple/g).length > 0 ) 
   return true; 
 return false;
}
SudarP
  • 708
  • 8
  • 9
4

Read many answers and posts and determined the most accurate solution. Tested in Safari, Chrome, Firefox (desktop and iOS versions). First we need to detect Apple vendor and then exclude Chrome and Firefox (for iOS).

let isSafari = navigator.vendor.match(/apple/i) &&
             !navigator.userAgent.match(/crios/i) &&
             !navigator.userAgent.match(/fxios/i);

if (isSafari) {
  //
} else {
  //
}
3

For the records, the safest way I've found is to implement the Safari part of the browser-detection code from this answer:

const isSafari = window['safari'] && safari.pushNotification &&
    safari.pushNotification.toString() === '[object SafariRemoteNotification]';

Of course, the best way of dealing with browser-specific issues is always to do feature-detection, if at all possible. Using a piece of code like the above one is, though, still better than agent string detection.

Marcos Sandrini
  • 226
  • 2
  • 6
  • 1
    This doesn't work with safari Version/13.1 Mobile/15E148 Safari/604.1 on iPhone OS 13_4_1. – mindo Apr 24 '20 at 10:32
2

Modified regex for answer above

var isSafari = /^((?!chrome|android|crios|fxios).)*safari/i.test(navigator.userAgent);
  • crios - Chrome
  • fxios - Firefox
Community
  • 1
  • 1
2

I know this question is old, but I thought of posting the answer anyway as it may help someone. The above solutions were failing in some edge cases, so we had to implement it in a way that handles iOS, Desktop, and other platforms separately.

function isSafari() {
    var ua = window.navigator.userAgent;
    var iOS = !!ua.match(/iP(ad|od|hone)/i);
    var hasSafariInUa = !!ua.match(/Safari/i);
    var noOtherBrowsersInUa = !ua.match(/Chrome|CriOS|OPiOS|mercury|FxiOS|Firefox/i)
    var result = false;
    if(iOS) { //detecting Safari in IOS mobile browsers
        var webkit = !!ua.match(/WebKit/i);
        result = webkit && hasSafariInUa && noOtherBrowsersInUa
    } else if(window.safari !== undefined){ //detecting Safari in Desktop Browsers
        result = true;
    } else { // detecting Safari in other platforms
        result = hasSafariInUa && noOtherBrowsersInUa
    }
    return result;
}
H H
  • 346
  • 1
  • 5
1

This unique "issue" is 100% sign that browser is Safari (believe it or not).

if (Object.getOwnPropertyDescriptor(Document.prototype, 'cookie').descriptor === false) {
   console.log('Hello Safari!');
}

This means that cookie object descriptor is set to false on Safari while on the all other is true, which is actually giving me a headache on the other project. Happy coding!

maxxx
  • 497
  • 3
  • 5
  • Seems no longer true. Also crashes on Firefox "Object.getOwnPropertyDescriptor(...) is undefined" – Offirmo Mar 20 '19 at 05:05
0

Maybe this works :

Object.prototype.toString.call(window.HTMLElement).indexOf('Constructor')

EDIT: NO LONGER WORKING

0

I tested the code posted by #Christopher Martin, and it reported my browser as Chrome, because it tests for that before testing for Edge, which would otherwise answer true to the test that is intended to identify Chrome. I amended his answer to correct that deficiency and two others, namely:

  1. The abbreviated user agent substring for Edge
  2. The very old string for MSIE

Converting the code into a function yields the following function and test script that reports via the debug console.

    <script type="text/javascript">
    function BasicBrowserSniffer ( )
    {
        if ( navigator.userAgent.match ( /edge\//i ) ) {
            return 'edge/edgehtml';
        }
        if ( navigator.userAgent.match ( /edg\//i ) ) {
            return 'edge/edgehtml';
        }
        else if ( navigator.vendor.match ( /google/i ) ) {
            return 'chrome/blink';
        }
        else if ( navigator.vendor.match ( /apple/i ) ) {
            return 'safari/webkit';
        }
        else if ( navigator.userAgent.match ( /firefox\//i ) ) {
            return 'firefox/gecko';
        }
        else if ( navigator.userAgent.match ( /trident\//i ) ) {
            return 'ie/trident';
        }
        else if ( navigator.userAgent.match ( /msie\//i ) ) {
            return 'ie/trident';
        }
        else
        {
            return navigator.userAgent + "\n" + navigator.vendor;
        }
    };  // BasicBrowserSniffer function

    console.info ( 'Entering function anonymous DocumentReady function' );
    console.info ( 'User Agent String   = ' + navigator.userAgent.toLowerCase ( ));
    console.info ( 'User Agent Vendor   = ' + var uav = navigator.vendor.toLowerCase ( );
    console.info ( 'BasicBrowserSniffer = ' + BasicBrowserSniffer ( ) );
    console.info ( 'Leaving function anonymous DocumentReady function' );
</script>
David A. Gray
  • 864
  • 10
  • 18
-1

I create a function that return boolean type:

export const isSafari = () => navigator.userAgent.toLowerCase().indexOf('safari') !== -1
Idan
  • 1,696
  • 15
  • 26
-3

User agent sniffing is really tricky and unreliable. We were trying to detect Safari on iOS with something like @qingu's answer above, it did work pretty well for Safari, Chrome and Firefox. But it falsely detected Opera and Edge as Safari.

So we went with feature detection, as it looks like as of today, serviceWorker is only supported in Safari and not in any other browser on iOS. As stated in https://jakearchibald.github.io/isserviceworkerready/

Support does not include iOS versions of third-party browsers on that platform (see Safari support).

So we did something like

if ('serviceWorker' in navigator) {
    return 'Safari';
}
else {
    return 'Other Browser';
}

Note: Not tested on Safari on MacOS.

A.G.
  • 128
  • 1
  • 8