12

While previously we were able to use navigator.platform in order to check which OS a browser was running in (which is still necessary for things like key event translation, e.g. Home vs. metaKey+ArrowLeft, or placing virtual modal "close" icons in a way that follows OS conventions) that option no longer exists. (That is to say, right now it technically still does but it's no longer a solution that is guaranteed to work by the time you deploy your code).

I can't seem to find any official documentation on what the replacement is supposed to be if OS knowledge is required: what is the new and improved way to determine which OS/platform a web page is running on?

(The currently most popular SO question around this, "Best way to detect Mac OS X or Windows computers with JavaScript or jQuery", does not have any answers that have been edited since the decision to deprecate navigator.platform was made, so unfortunately is not useful at the moment)

Mike 'Pomax' Kamermans
  • 49,297
  • 16
  • 112
  • 153

2 Answers2

2

One option would be using navigator.userAgentData along with the .getHighEntropyValues() method. Then we can utilize the User-Agent Client Hints API and get high entropy values from userAgentData by requesting a number of hints. Providing a means to detect OS from User-Agent information since navigator.platform is no longer.

Or instead just access navigator.userAgent which has full support and provides a user-agent string for the current browser where the OS could be extracted from.

function checkOS(n) {
  if (n.userAgentData) {
    const hints = ["architecture", "model", "platform", "platformVersion", "uaFullVersion"];
    n.userAgentData.getHighEntropyValues(hints)
      .then(ua => {
        console.log(ua);
      });
  } else {
    console.log(n.userAgent);
    return "navigator.userAgentData is not supported!";
  }
}

checkOS(navigator);

This is about the only documentation I've found in the DevTools "issues" tab aside from information on update on user agent string reduction.

A page or script is accessing at least one of navigator.userAgent, navigator.appVersion, and navigator.platform. In a future version of Chrome, the amount of information available in the User Agent string will be reduced. - To fix this issue, replace the usage of navigator.userAgent, navigator.appVersion, and navigator.platform with feature detection, progressive enhancement, or migrate to navigator.userAgentData.

I tried logging navigator.userAgentData to the console on a Windows and macOS machine using Chrome to see what kind of data it contained, and the object does have some useful information like the getHighEntropyValues() method in particular.

// NavigatorUAData {brands: Array(3), mobile: true}
{
  "brands": [
    {
      "brand": "Chromium",
      "version": "92"
    },
    {
      "brand": " Not A;Brand",
      "version": "99"
    },
    {
      "brand": "Google Chrome",
      "version": "92"
    }
  ],
  "mobile": false,
  "getHighEntropyValues": function getHighEntropyValues() { [native code] }
}

The browser support for navigator.userAgentData is not great (only supported in Chrome, Edge, Opera), but this could be a step in the right direction for detecting OS from userAgentData since navigator.platform is no longer. CodePen demo

Tanner Dolby
  • 4,253
  • 3
  • 10
  • 21
1

It turns out that the only realistic option for now is to look at the User Agent string and make decisions based on that (either by handrolling code, or using a user agent parsing library that does that for you).

This is not ideal, but as the goal is OS detection, and explicitly not browser detection, it's also not too hacky or liable to break in the future.

Mike 'Pomax' Kamermans
  • 49,297
  • 16
  • 112
  • 153
  • I'm writing integration tests so there are no HTTP requests. What can I do now? – canbax Feb 20 '23 at 07:46
  • I'm a little confused how you can write integration tests (i.e. tests with a browser that load your pages and then interact with them, performing tests based on the system as a whole, as opposed to unit tests) without having anything request pages to run their test actions on? – Mike 'Pomax' Kamermans Feb 20 '23 at 17:27
  • actually there are HTTP requests but we just return mock responses to them. So there is no backend – canbax Feb 21 '23 at 08:04
  • Still a bit confused then: what's preventing the browser from checking its own user agent? – Mike 'Pomax' Kamermans Feb 21 '23 at 16:39
  • hm I don't know maybe it is doable. Can make an HTTP call and give a mock response and then check userAgent? I just used `process.platform` instead – canbax Feb 22 '23 at 12:02
  • There is no `process` in the browser, so you're not running browser based integration tests at all (e.g selenium, playwright, etc). You're doing _something_, and you're doing that in Node, but that's all we know at the moment. You could ask Node which OS it's currently running on using `process.platform`, but if you're not even using a browser then just mock the user agent for whatever OS your test is pretending to run for? – Mike 'Pomax' Kamermans Feb 22 '23 at 16:04