All You Need to Know About Browser's User Agent String
Tags: browser, javascript, npm, webdev
Published: 2020-05-08 04:45:31

At Cefalo, I needed to develop a feature which required me to detect browser first. I thought it was easy - I would get it from the user agent string. But from my current browser, Chrome, what I found was 

```
Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_1) 
AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36
```

Wait wait wait. What the hell? I was expecting only `Chrome` but why these extra confusing words with chrome?

**Mozilla:** Immediately comes *Mozilla Firefox* on our mind. Mozilla is a software community that was founded by the members of Netscape, they now maintain *Mozilla Firefox* which is one of most popular browsers. But why it's here?

**WebKit:** The rendering engine which is used by Safari. Though Chrome started with Webkit, but they now uses Blink (which was built based on Webkit though), Where is `Blink` in this string?

**KHTML:** It was the rendering engine for *Konqueror* browser. Webkit was based on KHTML. Why it is even here?

**Gecko:** The rendering engine for Firefox. But why they have to write `like Gecko`? is it a joke?

**Chrome:** I can understand.

**Safari:** Again, what the hell?

To understand what's going on, lets start from what is browser's user agent?

It's a string to identify which browser is being used by client, which OS it is, which version etc. Generally this string passed by HTTP headers. Many websites customize their experience based on that. *Eg: When you are going to download a software, based on your OS it gives you the correct software automatically.* 

Generally, it has a format like this.

```jsx
Mozilla/[version] ([system and browser information]) [platform] ([platform details]) [extensions]
```

But at the early days, it was very simple, `Mosaic/0.9`, it is the user agent string for Mosaic, which is the first web browser. After some time, Netscape Navigator came into the field, they designed their user agent like `Mozilla/2.02 [en] (WinNT; N)` which means, Mozilla( interestingly the named it as "Mosaic Killer"!) version 2.02, having English language and Windows NT as a platform with No encryption.

But things started getting dirty after Internet Explorer entered in the community. When IE came to the market, Netscape was the dominant browser. At that time, many servers checked whether it's `Netscape` or not, before serving their contents. Most probably, they thought it would add some extra layer of security. But this created problem for Internet Explorer.

1. They are new to market, they have to compete with Netscape
2. If they can't give support for some websites (who checks whether it is `Netscape` or not first), then their adoption rate will be slower. Some people won't use it.

So they decided to trick the server. They designed their user agent like this

```jsx
 Mozilla/2.0 (compatible; MSIE Version; Operating System)
//Example
 Mozilla/2.0 (compatible; MSIE 3.03; Windows 95
```

 Above example indicates, Mozilla 2.0 compatible Microsoft Internet Explorer of version 3.03 in windows 95 platform.

So the websites that checked for Netscape (eg: Checking whether `Mozilla` is included in User Agent string, will also serve contents to Internet Explorer now.  That's how keyword `Mozilla` is now present most of the browsers' user agent string. 

And as new browsers came in the market, this dirty trick continued. That's why some user string has `like Gecko` to substring in it. Just to bypass the filter some popular website was using to serve their content to Gecko engines. Google Chrome just uses all the string for apple's safari + extra string for chrome version. So the servers serve content to Safari, will also serve content to Chrome. 

Now how can we get the browser's user agent programmatically?

In angular, you can get user agent by 

```jsx
const userAgent = window.navigator.userAgent;
console.log(userAgent);
// Prints Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36
```

Now how to detect browser from this user agent? There is no clean way to do this. The bellow table collected from [here](https://developer.mozilla.org/en-US/docs/Web/HTTP/Browser_detection_using_the_user_agent) gives us some idea how to do it with the help of regular expressions.
![Pattern Detection for UA Strings](https://dev-to-uploads.s3.amazonaws.com/i/5z2mfmmtkvu9fv1sy61i.png)

But obviously we'll not reinventing the wheel. There is a beautiful library, [UAParser.js](https://github.com/faisalman/ua-parser-js), that does this tedious work for us. 

Just type `npm i ua-parser-js` and you will get the browser by `getBrowser()` method, as simple as that.

*Does this post cover "all" about user agent string?* Obviously no. **I lied, just like Chrome lies to the servers.**

**References**

1. [https://en.wikipedia.org/wiki/Mozilla](https://en.wikipedia.org/wiki/Mozilla)
2. [https://humanwhocodes.com/blog/2010/01/12/history-of-the-user-agent-string/](https://humanwhocodes.com/blog/2010/01/12/history-of-the-user-agent-string/)
3. [https://www.whatsmyua.info/](https://www.whatsmyua.info/)
4. [https://en.wikipedia.org/wiki/Netscape#Mozilla-based_releases](https://en.wikipedia.org/wiki/Netscape#Mozilla-based_releases)