150

So I'm trying to move a "close" button to the left side when the user is on Mac and the right side when the user is on PC. Now I'm doing it by examining the user agent, but it can be too easily spoofed for reliable OS detection. Is there a surefire way to detect whether the OS on which the browser is running is Mac OS X or Windows? If not, what's better than user agent sniffing?

Louis
  • 146,715
  • 28
  • 274
  • 320
alt
  • 13,357
  • 19
  • 80
  • 120
  • 34
    If the user manipulates the useragent, isn't that his or her problem? I'd worry about it when it hurts *you* for them to have an invalid useragent (e.g. when it gives them access to something you don't want them to have), but for something like this, why are you stressing? Let them shoot themselves in the foot and have to deal with the consequences - no sweat off your back, mate. – Mahmoud Al-Qudsi May 10 '12 at 05:29
  • well, more like a tip than an answer. You can detect IE with conditional comments. this is +1 to the windows detection arsenal. but this would fail if IE were run in an emulator in another OS (like Wine on Linux). By the way, how about linux? – Joseph May 10 '12 at 05:30
  • @MahmoudAl-Qudsi Even without spoofing, mobile Firefox often pretends it's Safari, Opera often pretends it's firefox in some versions. Without spoofing the user agent is still VERY unreliable. – alt May 10 '12 at 05:33
  • Possible duplicate: http://stackoverflow.com/q/7044944/55209 – Artem Koshelev May 10 '12 at 05:34
  • But that question's answer is just "user agents". – alt May 10 '12 at 05:35
  • You worry someone could be spoofing the useragent and get the button on the wrong side? – FrancescoMM Jan 13 '20 at 17:27

8 Answers8

241

The window.navigator.platform property is not spoofed when the userAgent string is changed. I tested on my Mac if I change the userAgent to iPhone or Chrome Windows, navigator.platform remains MacIntel.

navigator.platform is not spoofed when the userAgent string is changed

The property is also read-only

navigator.platform is read-only


I could came up with the following table

Mac Computers

Mac68K Macintosh 68K system.
MacPPC Macintosh PowerPC system.
MacIntel Macintosh Intel system.
MacIntel Apple Silicon (ARM)

iOS Devices

iPhone iPhone.
iPod iPod Touch.
iPad iPad.


Modern macs returns navigator.platform == "MacIntel" but to give some "future proof" don't use exact matching, hopefully they will change to something like MacARM or MacQuantum in future.

var isMac = navigator.platform.toUpperCase().indexOf('MAC')>=0;

To include iOS that also use the "left side"

var isMacLike = /(Mac|iPhone|iPod|iPad)/i.test(navigator.platform);
var isIOS = /(iPhone|iPod|iPad)/i.test(navigator.platform);

var is_OSX = /(Mac|iPhone|iPod|iPad)/i.test(navigator.platform);
var is_iOS = /(iPhone|iPod|iPad)/i.test(navigator.platform);

var is_Mac = navigator.platform.toUpperCase().indexOf('MAC') >= 0;
var is_iPhone = navigator.platform == "iPhone";
var is_iPod = navigator.platform == "iPod";
var is_iPad = navigator.platform == "iPad";

/* Output */
var out = document.getElementById('out');
if (!is_OSX) out.innerHTML += "This NOT a Mac or an iOS Device!";
if (is_Mac) out.innerHTML += "This is a Mac Computer!\n";
if (is_iOS) out.innerHTML += "You're using an iOS Device!\n";
if (is_iPhone) out.innerHTML += "This is an iPhone!";
if (is_iPod) out.innerHTML += "This is an iPod Touch!";
if (is_iPad) out.innerHTML += "This is an iPad!";
out.innerHTML += "\nPlatform: " + navigator.platform;
<pre id="out"></pre>

Since most O.S. use the close button on the right, you can just move the close button to the left when the user is on a MacLike O.S., otherwise isn't a problem if you put it on the most common side, the right.

setTimeout(test, 1000); //delay for demonstration

function test() {

  var mac = /(Mac|iPhone|iPod|iPad)/i.test(navigator.platform);

  if (mac) {
    document.getElementById('close').classList.add("left");
  }
}
#window {
  position: absolute;
  margin: 1em;
  width: 300px;
  padding: 10px;
  border: 1px solid gray;
  background-color: #DDD;
  text-align: center;
  box-shadow: 0px 1px 3px #000;
}
#close {
  position: absolute;
  top: 0px;
  right: 0px;
  width: 22px;
  height: 22px;
  margin: -12px;
  box-shadow: 0px 1px 3px #000;
  background-color: #000;
  border: 2px solid #FFF;
  border-radius: 22px;
  color: #FFF;
  text-align: center;
  font: 14px"Comic Sans MS", Monaco;
}
#close.left{
  left: 0px;
}
<div id="window">
  <div id="close">x</div>
  <p>Hello!</p>
  <p>If the "close button" change to the left side</p>
  <p>you're on a Mac like system!</p>
</div>

http://www.nczonline.net/blog/2007/12/17/don-t-forget-navigator-platform/

Vitim.us
  • 20,746
  • 15
  • 92
  • 109
  • 1
    If anyone's interested in what the new M1 macs report, see here: https://stackoverflow.com/questions/64853342/whats-the-value-of-navigator-platform-on-arm-macs --- it looks like (at least for now) they still return `MacIntel` – Toastrackenigma Nov 29 '20 at 02:22
  • navigator.platform is deprecated. What now? – geoidesic May 28 '23 at 12:45
77

It's as simple as that:

function isMacintosh() {
  return navigator.platform.indexOf('Mac') > -1
}

function isWindows() {
  return navigator.platform.indexOf('Win') > -1
}
benhatsor
  • 1,863
  • 6
  • 20
Benny Code
  • 51,456
  • 28
  • 233
  • 198
  • 9
    Note that `navigator.platform` is no longer part of the web standard, so this probably needs an edit to explain that while this worked back in 2015, it's no longer the right solution. – Mike 'Pomax' Kamermans Sep 06 '21 at 16:18
8

You can test this:

function getOS() {
  let userAgent = window.navigator.userAgent.toLowerCase(),
    macosPlatforms = /(macintosh|macintel|macppc|mac68k|macos)/i,
    windowsPlatforms = /(win32|win64|windows|wince)/i,
    iosPlatforms = /(iphone|ipad|ipod)/i,
    os = null;

  if (macosPlatforms.test(userAgent)) {
    os = "macos";
  } else if (iosPlatforms.test(userAgent)) {
    os = "ios";
  } else if (windowsPlatforms.test(userAgent)) {
    os = "windows";
  } else if (/android/.test(userAgent)) {
    os = "android";
  } else if (!os && /linux/.test(userAgent)) {
    os = "linux";
  }

  return os;
}

document.getElementById('your-os').textContent = getOS();
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
        <h1 id="your-os"></h1>
  </body>
</html>
Tomerikoo
  • 18,379
  • 16
  • 47
  • 61
7

As mentioned in previous answers, navigator.platform is deprecated. We should use navigator.userAgentData but it still lack of support (firefox, safari does not support it in 2022).

Note that the navigator.userAgentData will only work for compatible browser through https.

Here is a script that will use UserAgentData with a fall back to the old way of doing it.

function get_platform() {
    // 2022 way of detecting. Note : this userAgentData feature is available only in secure contexts (HTTPS)
    if (typeof navigator.userAgentData !== 'undefined' && navigator.userAgentData != null) {
        return navigator.userAgentData.platform;
    }
    // Deprecated but still works for most of the browser
    if (typeof navigator.platform !== 'undefined') {
        if (typeof navigator.userAgent !== 'undefined' && /android/.test(navigator.userAgent.toLowerCase())) {
            // android device’s navigator.platform is often set as 'linux', so let’s use userAgent for them
            return 'android';
        }
        return navigator.platform;
    }
    return 'unknown';
}

let platform = get_platform().toLowerCase();

let isOSX = /mac/.test(platform); // Mac desktop
let isIOS = ['iphone', 'ipad', 'ipod'].indexOf(platform); // Mac iOs
let isApple = isOSX || isIOS; // Apple device (desktop or iOS)
let isWindows = /win/.test(platform); // Windows
let isAndroid = /android/.test(platform); // Android
let isLinux = /linux/.test(platform); // Linux
Erwan
  • 2,512
  • 1
  • 24
  • 17
6

For completion: Some browsers support navigator.userAgentData.platform, which is a read-only property.

console.log(navigator.userAgentData.platform);
// macOs

Please be aware that Navigator.platform is deprecated.

Niekes
  • 400
  • 1
  • 4
  • 11
  • where did you find that `navigator.platform` is deprecated? The link you've shared doesn't show that, and it's still in the HTML specs. – Chris Jul 22 '22 at 07:50
  • 1
    Looks like the content of the site changed. Here is another deprecation notice https://docs.w3cub.com/dom/navigator/platform – Niekes Jul 22 '22 at 16:49
5

Is this what you are looking for? Otherwise, let me know and I will remove this post.

Try this jQuery plugin: http://archive.plugins.jquery.com/project/client-detect

Demo: http://www.stoimen.com/jquery.client.plugin/

This is based on quirksmode BrowserDetect a wrap for jQuery browser/os detection plugin.

For keen readers:
http://www.stoimen.com/blog/2009/07/16/jquery-browser-and-os-detection-plugin/
http://www.quirksmode.org/js/support.html

And more code around the plugin resides here: http://www.stoimen.com/jquery.client.plugin/jquery.client.js

Tot Zam
  • 8,406
  • 10
  • 51
  • 76
Tats_innit
  • 33,991
  • 10
  • 71
  • 77
  • 1
    Link only answers are discouraged since links expire and break, like the first link in this answer. Instead, include the main points from the links in the actual answer, in addition to the links. – Tot Zam Aug 21 '17 at 04:46
2

Let me know if this works. Way to detect an Apple device (Mac computers, iPhones, etc.) with help from StackOverflow.com:
What is the list of possible values for navigator.platform as of today?

var deviceDetect = navigator.platform;
var appleDevicesArr = ['MacIntel', 'MacPPC', 'Mac68K', 'Macintosh', 'iPhone', 
'iPod', 'iPad', 'iPhone Simulator', 'iPod Simulator', 'iPad Simulator', 'Pike 
v7.6 release 92', 'Pike v7.8 release 517'];

// If on Apple device
if(appleDevicesArr.includes(deviceDetect)) {
    // Execute code
}
// If NOT on Apple device
else {
    // Execute code
}
0

I think all Chrome or Chromium-based browser will return MacIntel on the macOS platform regardless of the hardware architecture.

Check the Chromium Source code for further details.

Subhajit
  • 390
  • 3
  • 18