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.
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.
- They are new to market, they have to compete with Netscape
- 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
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
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 gives us some idea how to do it with the help of regular expressions.
But obviously we'll not reinventing the wheel. There is a beautiful library, UAParser.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
Top comments (3)
As a rule of thumb, you shouldn't try to detect browsers.
Instead, try detecting the features that you require for your software to be able to run (like Modernizr and family do).
In the history of the user agent (which I admit was a very interesting read), you outline how developers using the user agent string for feature toggles created that problem in the first place.
On top of that, I recall reading that Google is going to try and "deprecate" the user agent string by making it something generic, and not give away the users platform etc
yes, I agree, but still there are some use cases for browser specific features. Eg: You want to show a toast to your users if user uses browsers you don't support officially.
Mac OS 10.1 MUT