express-useragent, react-device-detect, and ua-parser-js are tools used to identify client devices and browsers, but they serve different layers of the stack. ua-parser-js is a lightweight, framework-independent library that parses user-agent strings into structured data about the browser, engine, OS, and device. express-useragent is an Express.js middleware wrapper that attaches parsed user-agent data directly to the request object for backend logic. react-device-detect is a React-specific library that provides components and hooks to conditionally render UI based on the device type, handling both server-side and client-side rendering concerns.
Identifying the client device and browser is a common requirement in web development, whether for analytics, conditional rendering, or security checks. The packages express-useragent, react-device-detect, and ua-parser-js approach this problem from different angles — backend middleware, frontend UI components, and core parsing logic. Let's compare how they handle real-world engineering tasks.
express-useragent acts as an Express middleware.
User-Agent header and attaches the result to req.useragent.// express-useragent: Middleware setup
const express = require('express');
const useragent = require('express-useragent');
const app = express();
app.use(useragent.express());
app.get('/', (req, res) => {
// Data attached to request object
res.json({ isMobile: req.useragent.isMobile });
});
react-device-detect provides React components and hooks.
// react-device-detect: Component usage
import { BrowserView, MobileView, useDeviceDetect } from 'react-device-detect';
function App() {
const { isMobile } = useDeviceDetect();
return (
<div>
<BrowserView>This shows on desktop</BrowserView>
<MobileView>This shows on mobile</MobileView>
</div>
);
}
ua-parser-js is a pure JavaScript parser.
// ua-parser-js: Direct parsing
import UAParser from 'ua-parser-js';
const parser = new UAParser();
const result = parser.getResult();
console.log(result.browser.name); // "Chrome"
console.log(result.os.version); // "10"
Handling user-agent detection during Server-Side Rendering is tricky because the server sees the initial request, but the browser might differ or hydrate differently.
express-useragent runs on the server only.
// express-useragent: Passing data to client
app.get('/', (req, res) => {
const isMobile = req.useragent.isMobile;
// Render React app with initial props
res.render('index', { initialData: { isMobile } });
});
react-device-detect handles SSR internally.
// react-device-detect: SSR safe rendering
// Works automatically in Next.js getServerSideProps or loaders
function Page() {
// No manual prop passing needed for basic views
return <MobileView><p>Mobile Only</p></MobileView>;
}
ua-parser-js requires manual SSR implementation.
// ua-parser-js: Manual SSR setup
export async function getServerSideProps({ req }) {
const parser = new UAParser(req.headers['user-agent']);
return { props: { deviceData: parser.getResult() } };
}
Different tasks require different levels of detail. Sometimes you just need "is mobile," and other times you need "Chrome version 114 on Windows 11."
express-useragent focuses on high-level flags.
isMobile, isTablet, isDesktop.// express-useragent: High-level flags
if (req.useragent.isMobile) {
// Redirect to mobile site
res.redirect('/m');
}
react-device-detect focuses on UI categories.
// react-device-detect: Category based
<MobileView>
<DownloadAppButton /> {/* Show only on mobile devices */}
</MobileView>
ua-parser-js provides deep technical details.
// ua-parser-js: Deep details
const { browser, os, device } = parser.getResult();
if (browser.name === 'Chrome' && browser.major < 90) {
// Show upgrade warning
}
Adding dependencies affects load times and server processing. The cost varies between a middleware, a UI library, and a utility function.
express-useragent adds cost to every server request.
// express-useragent: Overhead on every route
app.use((req, res, next) => {
// Parsing happens here automatically for all routes
next();
});
react-device-detect adds weight to the client bundle.
// react-device-detect: Bundle import
// Imports the whole detection logic into client JS
import { MobileView } from 'react-device-detect';
ua-parser-js is lightweight and on-demand.
// ua-parser-js: On-demand usage
// Only loads when you need specific data
const parser = new UAParser(navigator.userAgent);
User-agent strings are increasingly unreliable due to privacy features like User-Agent Reduction and Client Hints.
express-useragent relies on raw headers.
// express-useragent: Risk of spoofing
// Do not use for authentication or access control
if (req.useragent.isBot) {
// A malicious bot can fake this header
}
react-device-detect inherits UA limitations.
// react-device-detect: UI safety
// Safe for layout changes, not for access rules
return isMobile ? <MobileNav /> : <DesktopNav />;
ua-parser-js offers Client Hints support.
// ua-parser-js: Client Hints
// Requires server to accept CH headers
parser.setHeaders({ 'sec-ch-ua': '...', 'sec-ch-ua-mobile': '?' });
While they target different layers, all three packages share the goal of identifying the client environment.
User-Agent HTTP header or navigator.userAgent.// Common input source
const uaString = navigator.userAgent; // or req.headers['user-agent']
// Installation pattern
// npm install express-useragent
// npm install react-device-detect
// npm install ua-parser-js
// All run synchronously
const result = parser.parse(uaString); // No 'await' needed
| Feature | express-useragent | react-device-detect | ua-parser-js |
|---|---|---|---|
| Primary Use | Express Middleware | React UI Components | General Parser Library |
| Environment | Node.js / Server | Browser / SSR | Any JS Runtime |
| Data Output | Boolean Flags (isMobile) | Component Visibility | Detailed Object (OS, Version) |
| SSR Handling | Manual Prop Passing | Built-in Hydration Safety | Manual Implementation |
| Maintenance | Legacy / Stable | Active | Active / Standard |
express-useragent is a legacy tool 🕰️ — useful for quick Express apps but showing its age. It simplifies server-side checks but couples you to Express and lacks deep data. Use it for internal tools or quick prototypes where you already use Express.
react-device-detect is a UI helper 🎨 — perfect for React teams who need to adapt layouts without writing media queries. It saves time on hydration issues but adds bundle weight. Use it for consumer-facing React apps where device-specific UI is critical.
ua-parser-js is the engine ⚙️ — the most flexible and future-proof option. It gives you raw data and works everywhere. Use it for analytics, security logging, or when you need precise browser versioning across any framework.
Final Thought: For new architectures, prefer ua-parser-js for data logic and react-device-detect for UI logic. Avoid relying solely on express-useragent unless maintaining older systems, as modern privacy standards are making raw User-Agent parsing less reliable over time.
Choose express-useragent if you are maintaining a legacy Express.js backend and need quick access to user-agent data within your route handlers without manual parsing. It is best suited for server-side logging, basic analytics, or simple content negotiation where you already rely on the Express middleware ecosystem. However, for new projects, consider using a standalone parser instead to avoid coupling your logic to Express-specific middleware.
Choose react-device-detect if you are building a React application that needs to show or hide components based on the device type (e.g., mobile vs. desktop). It is ideal for frontend teams that want to avoid writing custom media queries or user-agent checks in multiple components. This package handles the complexity of SSR hydration mismatches, making it safer for Next.js or Remix applications than rolling your own solution.
Choose ua-parser-js if you need a reliable, framework-agnostic parser to extract detailed browser and OS information in any JavaScript environment. It is the best choice for backend services, Node.js scripts, or frontend code where you need raw data rather than UI components. Use this when you require precise version numbers or engine details that higher-level abstractions might hide.
Fast user-agent parser with first-class Express middleware and TypeScript typings. Works server-side in Node.js and in the browser via a lightweight IIFE bundle.
Requires Node.js 18 or newer.
npm install express-useragent
import http from 'node:http';
import { UserAgent } from 'express-useragent';
const server = http.createServer((req, res) => {
const source = req.headers['user-agent'] ?? 'unknown';
const parser = new UserAgent().hydrate(source);
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify(parser.Agent));
});
server.listen(3000);
ESM usage (Node 18+):
import express from 'express';
import { express as useragent } from 'express-useragent';
const app = express();
app.use(useragent());
app.get('/', (req, res) => {
res.json({
browser: req.useragent?.browser,
os: req.useragent?.os,
});
});
app.listen(3000);
Alternatively, you can import the whole namespace:
import express from 'express';
import * as useragent from 'express-useragent';
const app = express();
app.use(useragent.express());
app.get('/', (req, res) => {
res.json({
browser: req.useragent?.browser,
os: req.useragent?.os,
});
});
app.listen(3000);
CommonJS (require) still supports the default export pattern used in older examples:
const express = require('express');
const useragent = require('express-useragent');
const app = express();
app.use(useragent.express());
app.get('/', (req, res) => {
res.json({
browser: req.useragent?.browser,
os: req.useragent?.os,
});
});
app.listen(3000);
import { express as useragent } from 'express-useragent';
app.use(useragent());
import * as useragent from 'express-useragent';
app.use(useragent.express());
const useragent = require('express-useragent');
app.use(useragent.express());
import useragent from 'express-useragent' returned an object with an .express() method used as middleware.express (and alias useragentMiddleware). Use one of:
import { express as useragent } from 'express-useragent' → app.use(useragent())import * as useragent from 'express-useragent' → app.use(useragent.express())require('express-useragent').express() continues to work unchanged.See more end-to-end demos under examples/:
examples/server.ts — Express middleware demoexamples/http.ts — raw Node HTTP samplenew UserAgent() — build a fresh parser instance.useragent.parse(source) — quick parse returning the agent snapshot.useragent.express() — Express-compatible middleware that hydrates req.useragent and res.locals.useragent.parser.Agent — normalized fingerprint with convenience booleans (isMobile, isBot, etc.).Sample payload:
{
"isMobile": false,
"isDesktop": true,
"isBot": false,
"browser": "Chrome",
"version": "118.0.0",
"os": "macOS Sonoma",
"platform": "Apple Mac",
"source": "Mozilla/5.0 (Macintosh; Intel Mac OS X 14_0)..."
}
The build exports drop-in browser bundles under dist/browser/:
express-useragent.global.js — readable IIFE that exposes window.UserAgent and window.useragent.express-useragent.global.min.js — minified version of the same API.<script src="/vendor/express-useragent.global.min.js"></script>
<script>
const agent = new UserAgent().parse(navigator.userAgent);
console.log(agent.browser, agent.version);
</script>
Prefer consuming the ESM/CJS entry from your bundler when possible:
import { UserAgent } from 'express-useragent';
const agent = new UserAgent().parse(navigator.userAgent);
npm install # install dependencies
npm run lint # lint the TypeScript sources, tests, and examples
npm run typecheck # run the TypeScript compiler in noEmit mode
npm test # execute Vitest (includes adapted legacy suites)
npm run build # emit dist/ (CJS, ESM, d.ts, browser bundles)
Examples for manual testing:
npm run http # raw Node HTTP sample
npm run express # Express middleware demo
npm run simple # CLI parsing helper
Bug reports and PRs are welcome. When submitting changes, please include:
tests/ covering new parsing behaviour.npm test and npm run lint output or reproduction steps.See CONTRIBUTING.md for detailed guidelines, including how to update the bot list.
MIT © Aleksejs Gordejevs and contributors.