bowser, detect-browser, ua-parser-js, and useragent are JavaScript libraries designed to parse User-Agent strings and identify browser, OS, and device information. ua-parser-js is the industry standard for detailed parsing across environments. bowser focuses on browser-specific logic with a clean API. detect-browser offers a lightweight solution for quick checks in the browser. useragent is a legacy parser often used in older Node.js stacks but lacks modern maintenance compared to alternatives.
Parsing User-Agent strings is a fragile task — browsers change their strings frequently, and new devices appear constantly. The packages bowser, detect-browser, ua-parser-js, and useragent all attempt to solve this, but they differ in depth, maintenance, and API design. Let's compare how they handle real-world detection scenarios.
The way you start parsing varies significantly between these libraries. Some require manual UA string input, while others grab it automatically from the environment.
bowser requires you to pass the User-Agent string explicitly to a parser instance.
// bowser: Explicit parser creation
import bowser from 'bowser';
const parser = bowser.getParser(window.navigator.userAgent);
const browser = parser.getBrowser();
console.log(browser.name); // "Chrome"
detect-browser is designed for simplicity — it detects the current environment automatically without arguments.
// detect-browser: Zero-config detection
import { detect } from 'detect-browser';
const browser = detect();
console.log(browser.name); // "chrome"
ua-parser-js offers a class-based approach that works in both Node.js and browsers.
// ua-parser-js: Class-based instantiation
import UAParser from 'ua-parser-js';
const parser = new UAParser(window.navigator.userAgent);
const result = parser.getResult();
console.log(result.browser.name); // "Chrome"
useragent follows a older CommonJS-style function export pattern.
// useragent: Function-based parsing
const useragent = require('useragent');
const agent = useragent.parse(window.navigator.userAgent);
console.log(agent.family); // "Chrome"
Not all parsers return the same level of detail. Some focus only on the browser, while others dig into device hardware.
bowser provides structured data for browser, OS, and platform, but focuses heavily on browser versioning.
// bowser: Structured browser and OS data
const browser = parser.getBrowser();
const os = parser.getOS();
// { name: "Chrome", version: "91.0" }
// { name: "Windows", version: "10" }
detect-browser returns a flat object with basic details — enough for simple checks but not deep analytics.
// detect-browser: Flat object output
const browser = detect();
// { name: "chrome", version: "91.0.4472.124", os: "Windows" }
ua-parser-js provides the deepest breakdown, including device model and vendor.
// ua-parser-js: Detailed device and engine data
const result = parser.getResult();
// result.device.model: "iPhone"
// result.engine.name: "WebKit"
// result.os.name: "iOS"
useragent returns a specific structure focused on family and major/minor versions, often used in logging.
// useragent: Family-based versioning
const agent = useragent.parse(ua);
// agent.family: "Chrome"
// agent.major: "91"
// agent.minor: "0"
Your deployment target matters. Some libraries are built for the browser first, while others work seamlessly on the server.
bowser works in both environments but requires you to supply the UA string manually in Node.js.
// bowser: Manual UA in Node.js
const parser = bowser.getParser(req.headers['user-agent']);
const isSafari = parser.satisfies({ safari: ">14" });
detect-browser is primarily designed for the browser. Using it in Node.js requires passing a UA string explicitly.
// detect-browser: Browser-first design
import { detectFromUserAgent } from 'detect-browser';
// In Node.js you must use the specific function
const browser = detectFromUserAgent(req.headers['user-agent']);
ua-parser-js is environment-agnostic — it works identically in Node.js and browsers.
// ua-parser-js: Universal support
const parser = new UAParser(req.headers['user-agent']); // Node
const parser = new UAParser(); // Browser (auto-detect)
useragent is historically tied to Node.js and Express middleware patterns.
// useragent: Node.js focused
app.use(function(req, res, next){
req.useragent = useragent.parse(req.headers['user-agent']);
next();
});
User-Agent parsing is a cat-and-mouse game. Libraries need frequent updates to recognize new browsers.
bowser is actively maintained and updates regularly for new browser versions. It is a safe choice for modern frontends.
detect-browser receives updates but focuses on stability over exhaustive device lists. Good for common browsers.
ua-parser-js has the largest community and fastest response to new UA strings. It is the most reliable for critical logic.
useragent has slower update cycles compared to ua-parser-js. For new projects, evaluate alternatives due to potential gaps in recognizing very recent devices.
| Feature | bowser | detect-browser | ua-parser-js | useragent |
|---|---|---|---|---|
| Primary Focus | Browser logic | Quick checks | Deep parsing | Legacy/Node |
| API Style | Chainable | Functional | Class-based | Function |
| Device Data | Basic | Basic | Detailed | Basic |
| Node Support | ✅ (Manual UA) | ✅ (Specific func) | ✅ (Auto/Manual) | ✅ (Native) |
| Maintenance | Active | Active | Very Active | Slow |
ua-parser-js is the top choice for most professional projects — it offers the best balance of detail, reliability, and cross-environment support. Use it when you need to trust the data.
bowser is excellent for frontend feature flags — its API is clean and purpose-built for browser checks without the overhead of device analytics.
detect-browser fits small scripts or widgets — where bundle size is critical and you only need to know "Chrome vs Safari".
useragent should be reserved for legacy maintenance — if you are starting fresh, the slower update cycle poses a risk for new device support.
Final Thought: Remember that User-Agent sniffing is inherently fragile — prefer feature detection whenever possible. Use these tools only when you have no other option.
Choose bowser if you need a clean, chainable API specifically for browser detection logic in client-side applications. It is well-suited for feature flags based on browser identity rather than deep device analytics.
Choose detect-browser if you want a zero-config, lightweight solution for quick browser checks in the browser environment. It is ideal for simple conditional rendering where bundle size matters.
Choose ua-parser-js if you require robust, detailed parsing of browser, OS, and device data across both Node.js and browser environments. It is the safest choice for production systems needing reliable UA data.
Choose useragent only if you are maintaining legacy systems that already depend on it. For new projects, evaluate alternatives like ua-parser-js due to slower update cycles and less active maintenance.
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.