Safe, reliable Browser sniffing
Tags: javascript, browser, detection, desktop
Published: 2018-06-25 17:47:08

---
title: Safe, reliable Browser sniffing
published: true
description: Browser detection using top-level object in the BOM. No third party.
tags: javascript, browser, detection, desktop
cover_image: https://thepracticaldev.s3.amazonaws.com/i/rrudcplxhq4x2o3rfcci.png
---

We've recently built a WebExtension for our Web Application as Add-on and extra feature to sell 💰💸 (b/c why not). We decided to serve 4 different browser types:  **Chrome**, **Safari**, **Opera**, and **Firefox**. So we had to figure out which browser is rendering our page to display a browser-specific instructions to the users.

---

## You're lying to me. Aren't You?

**Browser detection using the user agent** is just sucks!! because it's trivial to spoof this **value**. For example the snippet below: 

```javascript
navigator.userAgent.indexOf('Chrome') !== -1 
```

returns `true` for both **Google Chrome** and **Opera** (*since Opera replaces its engine with Blink + V8 used by Chromium*) because its UA string looks like Chrome. Thats is not what am looking for. And if we're trying to detect a specific browser, the point of feature-checking is kind of lost.



> Check out [MDN web docs: Browser detection using the user agent](https://developer.mozilla.org/en-US/docs/Web/HTTP/Browser_detection_using_the_user_agent) for futher details.



## Top-level object FWT

`window` is the top-level object in the **Browser Object Model** (**BOM**) hierarchy. Every single browser has its own properties such as *ApplePayError* in Safari for instance, in addtion to the standard ones (e.g. `window.location`, `window.console`, ...etc).



## Solution

```javascript
/*
 * Browser detection
 * @return {String} 
 */
const browserDetection = () => {
  const browsers = {
    firefox: !!window.InstallTrigger,
    safari: !!window.ApplePaySession,
    opera: window.opr && !!window.opr.addons,
    chrome: window.chrome && !!window.chrome.webstore
  };
    
  return Object.keys(browsers).find(key => browsers[key] === true);
};

console.log(browserDetection()) // browser name expected
```



* **Firefox**: The `InstallTrigger` interface is an interesting outlier in the Apps API.
* **Safari**: `ApplePaySession` belongs to the Apple Pay JS API. A session object for managing the payment process on the web.
* **Opera**:  `opr`  self explanatory. `.opr.addons` represent interface in the Add-ons API
* **Chrome**:  ~~`chrome.webstore` API to initiate app and extension installations "inline" from web page~~. Notice: this will be [deprecated](https://dev.to/_elmahdim/safe-reliable-browser-sniffing-39bp#comment-node-118287), thanks to [Madison Dickson](https://dev.to/mix3d). Any recommendations are welcome!



## Tested in the following "Desktop Browsers":

✓ **Firefox Quantum**  Version ~60

✓ **Google Chrome**  Version ~67

✓ **Opera**  Version ~53

✓ **Safari**  Version ~11



**Please keep in mind**, that solution worked just perfectly in my case, and <u>might not fit yours</u>.

## [Demo on Codepen](https://codepen.io/elmahdim/full/bKjmbb/)

---

**Feedback are welcome**. If you have any suggestions or corrections to make, please do not hesitate to drop me a note/comment.