Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Detecting Apple Silicon mac in JavaScript

Is there a way to detect Apple Silicon Mac in JavaScript?
Properties in navigator don't seem to be very helpful, for example, navigator.platform is set to MacIntel and the user agent is exactly the same.

The why part: I have two versions of my software available, for Intel and for Apple Silicon. Asking users "Is your Mac Apple Silicon or Intel?" is not great.

like image 286
Antelle Avatar asked Dec 04 '20 15:12

Antelle


2 Answers

I have a solution, but it feels pretty fragile.

Check the OS, since Apple Silicon only exists with 10_15 or higher:

navigator.userAgent.match(/OS X 10_([789]|1[01234])/)

Check the GPU using webgl:

var w = document.createElement("canvas").getContext("webgl");
var d = w.getExtension('WEBGL_debug_renderer_info');
var g = d && w.getParameter(d.UNMASKED_RENDERER_WEBGL) || "";
if (g.match(/Apple/) && !g.match(/Apple GPU/)) {
   ...definitely arm...
}

If you see Apple GPU, then it's Safari which hides the GPU to prevent fingerprinting. Dig into capabilities:

if (w.getSupportedExtensions().indexOf("WEBGL_compressed_texture_s3tc_srgb") == -1) {
  ...probably arm...
}

(I compared the capabilities of my MacBook Pro to a new M1 Air, and that one is missing on the Air. All others were identical.)

The approach I'm taking is to give the user a choice, but use this test to choose the default.

If anyone has another idea of something that might be peculiar to help narrow down if it's an M1, I'm happy to experiment...

Update: As Romain points out in the comments, Apple added support for the missing extension in Big Sur, so this isn't working now (in Safari; it still works in Chrome & Firefox).

like image 200
Joshua Smith Avatar answered Oct 16 '22 19:10

Joshua Smith


There's a library you can use that gives you information about the operating system that's in Node.js - os (const os = require('os')). It has a method returning the cpu cores - os.cpus(), you can just take the first element and check if it's the exact model you want or if it simply contains "Apple M1" as a string in its model - let isM1 = cpuCore[0].model.includes("Apple M1").

You might also check the os.arch() method as it:

Returns the operating system CPU architecture for which the Node.js binary was compiled.

I would however advice high levels of caution when using the arch method because I have had several occurrences in which an M1 Mac returned x64 from os.arch() instead of arm64 which is the expected result.

EDIT: Might be better to replace cpuCore[0].model.includes("Apple M1") with either a regular expression or cpuCore[0].model.includes("Apple") since the earliest versions of M1 macs return 'Apple processor' under model.

like image 33
InsertKnowledge Avatar answered Oct 16 '22 18:10

InsertKnowledge