javascriptbrowser-detection

Unable to detect underlying OS using JS


When I see the console of my browser, even if i am using windows, it returns Linux.

function detectOS() {
    const userAgent = navigator.userAgent.toLowerCase();

    if (userAgent.includes('win')) {
        return 'Windows';
    } else if (userAgent.includes('mac')) {
        return 'Mac';
    } else if (userAgent.includes('linux')) {
        return 'Linux';
    } else if (userAgent.includes('iphone') || userAgent.includes('ipad')) {
        return 'iOS';
    } else if (userAgent.includes('android')) {
        return 'Android';
    }
  
    return 'Unknown OS';
}
console.log(detectOS());

Any problem with the code or my console?

I tried to use other browser and PC, but not working!!!


Solution

  • Your code should work for most cases. However, there might be instances where some browsers or browser extensions modify the user agent string, leading to incorrect information being returned. So they might not be the foolproof methods.1 Additionally, if you are using a virtual machine, it could cause the user agent to report the host OS instead of the guest OS.

    Since you mentioned that navigator.platform works for you, but also it is deprecated, you can consider using another property, navigator.userAgentData.platform.2

    As pointed out by JaromandaX in a comment, you should check for Linux as the last condition, as Android is a Linux-based operating system so there might be some conflict.

    Reliably checking platform information is not a trivial task; therefore, if you are allowed to use a library, I'd recommend using one that can handle this for you. Platform.js is a comprehensive library that can help you achieve this.3

    function detectOS() {
      // if a browser has no support for navigator.userAgentData.platform use platform as fallback
      const userAgent = (navigator.userAgentData.platform ?? navigator.platform).toLowerCase();
    
      if (userAgent.includes('win')) {
        return 'Windows';
      } else if (userAgent.includes('android')) {
        return 'Android';
      } else if (userAgent.includes('mac')) {
        return 'Mac';
      } else if (userAgent.includes('iphone') || userAgent.includes('ipad')) {
        return 'iOS';
      } else if (userAgent.includes('linux')) {
        return 'Linux';
      }
      return 'Unknown OS';
    }
    
    console.log(detectOS());


    1Why neither navigator.userAgent nor navigator.platform are foolproof?

    Below is a small script using navigator.platform which modifies the platform property.

    const codeToInject = `
      Object.defineProperty(navigator, "platform", {
        get: () => "MacIntel",
        set: (a) => {}
      });
    `;
    const script = document.createElement('script');
    script.textContent = codeToInject;
    (document.head || document.documentElement).appendChild(script);
    script.remove();
    
    console.log(navigator.platform); // will always return MacIntel
    // For your case it will always print Mac which proves that it can be modified.

    2Checking browser support

    Since navigator.userAgentData is experimental it is important to check for its browser-support is crucial.

    3Using platform.js to detect OS:

    Below is the way to use platform.js for your requirement.

    function detectOS() {
      const os = platform.os.family;
    
      if (os === 'Windows') {
        return 'Windows';
      } else if (os === 'OS X' || os === 'macOS') {
        return 'Mac';
      } else if (os === 'iOS') {
        return 'iOS';
      } else if (os === 'Android') {
        return 'Android';
      } else if (os === 'Linux') {
        return 'Linux';
      }
    
      return 'Unknown OS';
    }
    
    console.log(detectOS());
    <script src="https://cdnjs.cloudflare.com/ajax/libs/platform/1.3.6/platform.min.js"></script>