User Agent Detection — Parse Browser and Device from User-Agent String
User agent strings identify the browser, OS, and device making an HTTP request. Here's how to parse user agents reliably, detect mobile vs desktop, and use structured data...
User agent detection extracts structured browser, OS, and device information from the User-Agent HTTP header. The raw string is human-readable but inconsistently formatted — libraries parse it into reliable structured data. Here’s how to parse user agents correctly and avoid the pitfalls of manual string matching.
Use the User Agent Parser to parse any user agent string online.
What the User-Agent header contains
A modern browser user agent string:
Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36
Breaking it down:
Mozilla/5.0— legacy token, present in almost every UA for compatibility(Windows NT 10.0; Win64; x64)— OS informationAppleWebKit/537.36— rendering engine(KHTML, like Gecko)— WebKit compatibility tokenChrome/122.0.0.0— browser name and versionSafari/537.36— WebKit compatibility token
The format evolved historically and is full of legacy tokens — “Mozilla” in Chrome’s UA is meaningless, as is “Safari” at the end.
User agent examples by platform
# Chrome on Windows:
Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36
# Firefox on macOS:
Mozilla/5.0 (Macintosh; Intel Mac OS X 14.3; rv:123.0) Gecko/20100101 Firefox/123.0
# Safari on iPhone:
Mozilla/5.0 (iPhone; CPU iPhone OS 17_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.3 Mobile/15E148 Safari/604.1
# Chrome on Android:
Mozilla/5.0 (Linux; Android 14; Pixel 8) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.6261.105 Mobile Safari/537.36
# Googlebot:
Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)
# curl:
curl/8.4.0
# Python requests:
python-requests/2.31.0
Parsing with libraries (recommended)
JavaScript (ua-parser-js)
npm install ua-parser-js
import UAParser from 'ua-parser-js';
const ua = 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.3 Mobile/15E148 Safari/604.1';
const parser = new UAParser(ua);
const result = parser.getResult();
console.log(result);
/*
{
ua: "Mozilla/5.0 ...",
browser: { name: "Mobile Safari", version: "17.3", major: "17" },
engine: { name: "WebKit", version: "605.1.15" },
os: { name: "iOS", version: "17.3" },
device: { vendor: "Apple", model: "iPhone", type: "mobile" },
cpu: { architecture: undefined }
}
*/
// Check device type:
const isMobile = result.device.type === 'mobile';
const isTablet = result.device.type === 'tablet';
const isDesktop = !result.device.type;
// Check specific browser:
const isChrome = result.browser.name === 'Chrome';
const isSafari = result.browser.name === 'Safari';
const isFirefox = result.browser.name === 'Firefox';
// Get browser version number:
const chromeVersion = parseInt(result.browser.major);
Node.js (Express middleware)
import express from 'express';
import UAParser from 'ua-parser-js';
const app = express();
// Middleware to parse user agent for all requests:
app.use((req, res, next) => {
const ua = new UAParser(req.headers['user-agent']);
req.userAgent = ua.getResult();
next();
});
app.get('/api/data', (req, res) => {
const { device, browser, os } = req.userAgent;
// Log device type for analytics:
console.log(`Request from: ${device.type || 'desktop'} | ${browser.name} ${browser.version} | ${os.name}`);
// Return different response for mobile:
if (device.type === 'mobile') {
return res.json({ data: 'mobile optimized response' });
}
res.json({ data: 'full response' });
});
Python (user-agents library)
pip install user-agents
from user_agents import parse
ua_string = 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.3 Mobile/15E148 Safari/604.1'
ua = parse(ua_string)
print(ua.browser.family) # "Mobile Safari"
print(ua.browser.version) # (17, 3, 0)
print(ua.os.family) # "iOS"
print(ua.os.version) # (17, 3, 0)
print(ua.device.family) # "iPhone"
print(ua.device.brand) # "Apple"
print(ua.device.model) # "iPhone"
# Boolean helpers:
print(ua.is_mobile) # True
print(ua.is_tablet) # False
print(ua.is_pc) # False
print(ua.is_bot) # False
# In Django view:
from django.http import HttpRequest
def my_view(request: HttpRequest):
ua = parse(request.META.get('HTTP_USER_AGENT', ''))
if ua.is_mobile:
return mobile_response()
return desktop_response()
Bot detection
Bots, crawlers, and automated tools have distinct user agents:
const botPatterns = [
/bot/i,
/crawl/i,
/spider/i,
/googlebot/i,
/bingbot/i,
/slurp/i,
/duckduckbot/i,
/facebookexternalhit/i,
/curl/i,
/wget/i,
/python-requests/i,
/axios/i,
];
function isBot(userAgent) {
return botPatterns.some(pattern => pattern.test(userAgent));
}
// Better: use ua-parser-js (has bot database):
const result = new UAParser(userAgentString).getResult();
const isBot = result.browser.name === undefined; // Bots often have no recognized browser
Client hints: the modern alternative
The traditional User-Agent header is being replaced by Client Hints (privacy-preserving, structured):
// Request additional client hints in HTTP response header:
// Accept-CH: Sec-CH-UA, Sec-CH-UA-Mobile, Sec-CH-UA-Platform
// In JavaScript, read client hints:
// await navigator.userAgentData.getHighEntropyValues(['platform', 'platformVersion', 'architecture'])
const uaData = navigator.userAgentData;
console.log(uaData.brands); // [{ brand: 'Google Chrome', version: '122' }, ...]
console.log(uaData.mobile); // true/false
console.log(uaData.platform); // "Windows"
// Server-side via headers:
// Sec-CH-UA: "Chromium";v="122", "Not(A:Brand";v="24"
// Sec-CH-UA-Mobile: ?0
// Sec-CH-UA-Platform: "Windows"
Client hints reduce the privacy concerns of full UA strings (which can be used for fingerprinting) while providing the structure that developers need.
What NOT to do: manual string matching
// FRAGILE: breaks with new browsers, versions, or UA string changes
function isMobile(ua) {
return /Mobile|Android|iPhone|iPad/.test(ua);
}
// FRAGILE: version number position changes between browsers
function getChromeVersion(ua) {
const match = ua.match(/Chrome\/(\d+)/);
return match ? parseInt(match[1]) : null;
}
Manual string matching requires constant updates as new browsers and devices are released. Use a maintained library that has these patterns built in.
Related tools
- User Agent Parser — parse user agent strings online
- User Agent String Guide — understanding UA format
- User Agent Parser Guide — parser usage guide
Related posts
- Bot Detection Using User Agent Strings — Googlebot, Bingbot, and Crawlers — Identify search engine crawlers, social media bots, and malicious scrapers from …
- Browser Detection in JavaScript — Feature Detection vs User Agent Parsing — Detect browsers, OS, and device type in JavaScript using user agent strings, fea…
- User-Agent Client Hints — Modern Browser Detection Without UA Sniffing — User-Agent Client Hints replace UA string parsing with structured HTTP headers. …
- Email Extractor — Extract Email Addresses from Text — An email extractor finds and pulls all email addresses from a block of text usin…
- User Agent Parser — What Your Browser String Reveals — A user agent string tells servers your browser, version, OS, and device type. He…
Related tool
Parse any User-Agent string into browser, OS, device, and engine. Or detect your own. Built on the maintained ua-parser-js dataset.
Written by Mian Ali Khalid. Part of the Dev Productivity pillar.