bowser, platform, and ua-parser-js are JavaScript utilities designed to parse User-Agent strings and environment data to identify browsers, operating systems, devices, and rendering engines. While they share the core goal of environment detection, they differ in API design, granularity of data, and broader platform support. bowser focuses on a modern, chainable API for browser specifics. platform provides a broad snapshot of the runtime environment, including Node.js and older browsers. ua-parser-js offers a highly detailed, synchronous parser that works across many JavaScript environments with a focus on accuracy and extensive device databases.
Parsing User-Agent strings is a common requirement for feature detection, analytics, and conditional rendering in web applications. While modern best practices often encourage feature detection over browser sniffing, there are still valid cases where knowing the client environment is necessary. bowser, platform, and ua-parser-js are the three most prominent tools for this task, but they approach the problem differently. Let's examine how they handle parsing, API design, and environment support.
The way you interact with these libraries varies significantly, impacting code readability and bundle integration.
bowser uses a functional, chainable API. You pass the User-Agent string to a parser instance and then call specific getters.
// bowser: Chainable parser
import bowser from 'bowser';
const parser = bowser.getParser(userAgent);
const browserName = parser.getBrowserName();
const isMobile = parser.isMobile();
platform exposes a static object that is populated immediately upon import. There is no need to instantiate a parser or pass a User-Agent string manually in browser contexts.
// platform: Static object
import platform from 'platform';
console.log(platform.name); // e.g., "Chrome"
console.log(platform.version); // e.g., "98.0.4758.102"
console.log(platform.os.family); // e.g., "Windows"
ua-parser-js relies on a class-based instance. You create a new parser, optionally passing a User-Agent string, and then retrieve a result object containing all data.
// ua-parser-js: Class instance
import UAParser from 'ua-parser-js';
const parser = new UAParser(userAgent);
const result = parser.getResult();
console.log(result.browser.name); // e.g., "Chrome"
console.log(result.device.model); // e.g., "iPhone"
Not all parsers dig equally deep. Some focus on the browser name, while others extract hardware and engine details.
bowser focuses primarily on the browser and OS. It excels at identifying browser families and versions but provides limited device hardware data.
// bowser: Browser and OS focus
const browser = parser.getBrowser();
// { name: 'Safari', version: '15.0' }
const os = parser.getOS();
// { name: 'macOS', version: '12.0' }
platform provides a balanced view of the environment, including layout engines and product names, but device model detection is less specific compared to dedicated parsers.
// platform: Environment snapshot
console.log(platform.layout); // e.g., "WebKit"
console.log(platform.product); // e.g., "Electron"
console.log(platform.description); // Full UA string description
ua-parser-js offers the most granular data, splitting results into browser, device, engine, CPU, and OS. It is particularly strong on mobile device models.
// ua-parser-js: Detailed breakdown
const device = result.device;
// { vendor: 'Apple', model: 'iPhone', type: 'mobile' }
const engine = result.engine;
// { name: 'WebKit', version: '605.1.15' }
Where these libraries run matters, especially for isomorphic applications.
bowser is designed primarily for browsers but works in Node.js if you pass the User-Agent string manually. It does not auto-detect the environment in Node.
// bowser: Manual UA in Node
import bowser from 'bowser';
const parser = bowser.getParser(process.env.USER_AGENT || '');
platform is built to detect the environment automatically. It works seamlessly in browsers, Node.js, and even older JavaScript engines without configuration.
// platform: Auto-detection
// Works out of the box in Node or Browser
if (platform.name === 'Node.js') {
// Handle server-side logic
}
ua-parser-js is universally compatible. It works in browsers, Node.js, and Web Workers. Like bowser, it requires manual UA string passing in non-browser environments.
// ua-parser-js: Universal compatibility
const parser = new UAParser(navigator.userAgent); // Browser
const serverParser = new UAParser(req.headers['user-agent']); // Node
Long-term support is critical for infrastructure libraries.
bowser is actively maintained with regular updates to handle new browser versions. It is lightweight and focuses on staying current with modern browser releases.
platform is stable but sees fewer updates. It is considered a mature library that prioritizes backward compatibility over cutting-edge device detection. It is often bundled with lodash.
ua-parser-js has a very high update frequency due to its reliance on community contributions for device patterns. It is the go-to choice when new devices must be recognized quickly.
| Feature | bowser | platform | ua-parser-js |
|---|---|---|---|
| API Style | Chainable functions | Static object | Class instance |
| Browser Data | โ Detailed | โ Basic | โ Very Detailed |
| Device Model | โ Limited | โ Limited | โ Extensive |
| Engine Info | โ Yes | โ Yes | โ Yes |
| Node.js Support | โ Manual UA | โ Auto-detect | โ Manual UA |
| Bundle Weight | ๐ข Lightweight | ๐ข Lightweight | ๐ก Moderate |
You need to apply a specific class for Safari users due to a known rendering bug.
bowser// bowser: Simple check
if (parser.getBrowserName() === 'Safari') {
document.body.classList.add('safari-fix');
}
You want to track user devices, including specific phone models and operating systems.
ua-parser-js// ua-parser-js: Analytics data
const { device, os } = parser.getResult();
analytics.track('page_view', {
device: `${device.vendor} ${device.model}`,
os: `${os.name} ${os.version}`
});
You are writing a utility library that runs in Node.js, browsers, and legacy environments.
platform// platform: Environment check
if (platform.os.family === 'Windows') {
// Handle Windows specific paths
}
Selecting the right parser depends on what you need to know about the client.
bowser. It is clean, modern, and easy to read in conditional logic.platform. It is excellent for detecting Node.js vs Browser without extra setup.ua-parser-js. It is the most powerful tool for analytics and precise device identification.Final Thought: While these tools are useful, remember that User-Agent strings can be spoofed. For critical feature detection, always prefer checking for the actual API or capability (feature detection) whenever possible. Use these libraries for analytics, logging, or non-critical UI adjustments.
Choose bowser if your primary need is clean, modern browser detection with a simple API. It is ideal for frontend applications where you need to quickly identify browser families (Chrome, Firefox, Safari) and versions without worrying about low-level engine details. Its chainable interface makes it easy to read and maintain in conditional logic.
Choose ua-parser-js if you require detailed parsing of device models, engine versions, and CPU architecture alongside browser data. It is the best fit for analytics, security fingerprinting, or complex feature detection where accuracy across a wide range of devices โ including mobile and smart TVs โ is critical.
Choose platform if you need to detect the broader runtime environment, not just the browser. It is suitable for libraries that must run in diverse contexts like Node.js, Rhino, or legacy browsers, and when you need quick access to properties like platform.name or platform.os without instantiating a parser object.
A small, fast and rich-API browser/platform/engine detector for both browser and node.
Don't hesitate to support the project on Github or OpenCollective if you like it โค๏ธ Also, contributors are always welcome!
The library is made to help to detect what browser your user has and gives you a convenient API to filter the users somehow depending on their browsers. Check it out on this page: https://bowser-js.github.io/bowser-online/.
Version 2.0 has drastically changed the API. All available methods are on the docs page.
For legacy code, check out the 1.x branch and install it through npm install bowser@1.9.4.
First of all, require the library. This is a UMD Module, so it will work for AMD, TypeScript, ES6, and CommonJS module systems.
const Bowser = require("bowser"); // CommonJS
import * as Bowser from "bowser"; // TypeScript
import Bowser from "bowser"; // ES6 (and TypeScript with --esModuleInterop enabled)
By default, the exported version is the ES5 transpiled version, which do not include any polyfills.
In case you don't use your own babel-polyfill you may need to have pre-built bundle with all needed polyfills.
So, for you it's suitable to require bowser like this: require('bowser/bundled').
As the result, you get a ES5 version of bowser with babel-polyfill bundled together.
You may need to use the source files, so they will be available in the package as well.
Often we need to pick users' browser properties such as the name, the version, the rendering engine and so on. Here is an example how to do it with Bowser:
const browser = Bowser.getParser(window.navigator.userAgent);
console.log(`The current browser name is "${browser.getBrowserName()}"`);
// The current browser name is "Internet Explorer"
Modern browsers support User-Agent Client Hints, which provide a more privacy-friendly and structured way to access browser information. Bowser can use Client Hints data to improve browser detection accuracy.
// Pass Client Hints as the second parameter
const browser = Bowser.getParser(
window.navigator.userAgent,
window.navigator.userAgentData
);
console.log(`The current browser name is "${browser.getBrowserName()}"`);
// More accurate detection using Client Hints
Bowser provides methods to access and query Client Hints data:
const browser = Bowser.getParser(
window.navigator.userAgent,
window.navigator.userAgentData
);
// Get the full Client Hints object
const hints = browser.getHints();
// Returns the ClientHints object or null if not provided
// Check if a specific brand exists
if (browser.hasBrand('Google Chrome')) {
console.log('This is Chrome!');
}
// Get the version of a specific brand
const chromeVersion = browser.getBrandVersion('Google Chrome');
console.log(`Chrome version: ${chromeVersion}`);
The Client Hints object structure:
{
brands: [
{ brand: 'Google Chrome', version: '131' },
{ brand: 'Chromium', version: '131' },
{ brand: 'Not_A Brand', version: '24' }
],
mobile: false,
platform: 'Windows',
platformVersion: '15.0.0',
architecture: 'x86',
model: '',
wow64: false
}
Note: Client Hints improve detection for browsers like DuckDuckGo and other Chromium-based browsers that may have similar User-Agent strings. When Client Hints are not provided, Bowser falls back to standard User-Agent string parsing.
or
const browser = Bowser.getParser(window.navigator.userAgent);
console.log(browser.getBrowser());
// outputs
{
name: "Internet Explorer"
version: "11.0"
}
or
console.log(Bowser.parse(window.navigator.userAgent));
// outputs
{
browser: {
name: "Internet Explorer"
version: "11.0"
},
os: {
name: "Windows"
version: "NT 6.3"
versionName: "8.1"
},
platform: {
type: "desktop"
},
engine: {
name: "Trident"
version: "7.0"
}
}
You can also use Bowser.parse() with Client Hints:
console.log(Bowser.parse(window.navigator.userAgent, window.navigator.userAgentData));
// Same output structure, but with enhanced detection from Client Hints
You could want to filter some particular browsers to provide any special support for them or make any workarounds. It could look like this:
const browser = Bowser.getParser(window.navigator.userAgent);
const isValidBrowser = browser.satisfies({
// declare browsers per OS
windows: {
"internet explorer": ">10",
},
macos: {
safari: ">10.1"
},
// per platform (mobile, desktop or tablet)
mobile: {
safari: '>=9',
'android browser': '>3.10'
},
// or in general
chrome: "~20.1.1432",
firefox: ">31",
opera: ">=22",
// also supports equality operator
chrome: "=20.1.1432", // will match particular build only
// and loose-equality operator
chrome: "~20", // will match any 20.* sub-version
chrome: "~20.1" // will match any 20.1.* sub-version (20.1.19 as well as 20.1.12.42-alpha.1)
});
Settings for any particular OS or platform has more priority and redefines settings of standalone browsers. Thus, you can define OS or platform specific rules and they will have more priority in the end.
More of API and possibilities you will find in the docs folder.
.satisfies()By default you are supposed to use the full browser name for .satisfies.
But, there's a short way to define a browser using short aliases. The full
list of aliases can be found in the file.
This project exists thanks to all the people who contribute. [Contribute].
Become a financial contributor and help us sustain our community. [Contribute]
Support this project with your organization. Your logo will show up here with a link to your website. [Contribute]
Licensed as MIT. All rights not explicitly granted in the MIT license are reserved. See the included LICENSE file for more details.