A compact, dependency-free, MIT-licensed user agent parser for JavaScript. Detects browser, engine, OS, CPU, and device — plus first-class classification of bots, AI training crawlers, and in-app browsers, and support for User-Agent Client Hints.
No build step. src/ua-lite.js is the distributable — drop it straight
into a <script> tag, require() it in Node, or import it.
npm install ua-liteOr drop the file directly into a page:
<script src="ua-lite.js"></script>
<script>
const result = UALite.parse(navigator.userAgent);
</script>const { parse } = require('ua-lite');
const result = parse('Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36');
console.log(result.browser.name); // 'Chrome'parse('Mozilla/5.0 (Linux; Android 14; Pixel 8) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.6367.82 Mobile Safari/537.36');parse() never throws and never returns undefined fields — every key is
present, with null where nothing was detected.
Synchronously parses a UA string. ua is trimmed to 500 characters. Pass an
optional hints object (see Client hints) to merge Client
Hints data into the result in one call.
Returns a Promise<UAResult>. In a browser, automatically collects
navigator.userAgentData (including high-entropy values like
platformVersion, architecture, and model) and merges them into the
result. Falls back to a plain parse() when the Client Hints API isn't
available. ua defaults to navigator.userAgent.
Merges a Client Hints header object into an existing UAResult, returning
a new object — the input result is never mutated.
Browser-only. Reads navigator.userAgentData synchronously and returns a
hints object (low-entropy only — brands, mobile flag, platform). Returns
null if the API isn't available.
const { parse, collectHints } = require('ua-lite');
const result = parse(navigator.userAgent, collectHints());Or use parseAsync() to also pick up high-entropy values
(platformVersion, architecture, model, full version list):
const { parseAsync } = require('ua-lite');
const result = await parseAsync();Pass the raw Sec-CH-UA-* request headers straight through:
const { parse } = require('ua-lite');
app.get('/', (req, res) => {
const result = parse(req.headers['user-agent'], req.headers);
res.json(result);
});Recognized header keys (case-insensitive):
| Header | Effect |
|---|---|
sec-ch-ua |
Overrides browser.name from the brand list (skips Chromium/Not-A.Brand noise entries) |
sec-ch-ua-full-version-list |
Overrides browser.name and browser.version with the full version |
sec-ch-ua-platform |
Overrides os.name |
sec-ch-ua-platform-version |
Overrides os.version |
sec-ch-ua-mobile |
?1 sets device.type to mobile, ?0 sets it to desktop |
sec-ch-ua-arch |
Overrides cpu.architecture |
sec-ch-ua-model |
Overrides device.model (only when non-empty) |
agent.type classifies what kind of client is making the request —
independent of, and detected before, browser parsing:
| Type | Covers | Examples |
|---|---|---|
ai |
Crawlers that train or answer from AI models | GPTBot, ClaudeBot, Google-Extended, PerplexityBot, CCBot, Bytespider |
crawler |
Traditional search/indexing/SEO crawlers | Googlebot, Bingbot, AhrefsBot, Twitterbot |
bot |
Generic scripts and HTTP clients | curl, wget, python-requests, axios, Go-http-client |
app |
In-app / wrapper browsers | Instagram, Facebook, TikTok, Twitter, WhatsApp, Electron |
browser |
Everything else — a regular end-user browser | Chrome, Firefox, Safari, Edge |
When agent.type is browser, agent.name mirrors browser.name.
device.type is forced to 'bot' whenever agent.type is anything other
than browser or app.
All detection rules live in flat, ordered tables inside
src/ua-lite.js — no build step, so edits take effect immediately.
To add a new agent pattern (e.g. a new AI crawler), find the AGENT_RULES
array and add a [regex], [['type', 'ai'], ['name', 'YourBotName']], pair
in the appropriate tier. Order matters — rules are tried top to bottom
and the first match wins, so put more specific patterns before generic
ones.
The same pattern applies to BROWSER_RULES, OS_RULES(), CPU_RULES, and
DEVICE_RULES_PASS1.
ua-lite's domain knowledge (regex ordering, the Windows NT version map, the rgxMapper pattern) was studied from ua-parser-js — see src/ua-lite.js for the disclosure. No code was copied; all patterns here are written fresh. We benchmarked ua-lite against that library (both major versions) plus four other widely used UA-parsing libraries on npm: bowser, platform.js, express-useragent, and mobile-detect.
All figures below are real measurements: each package was installed fresh from npm, required directly (no bundler), and run through the same 12-UA mix (desktop/mobile/tablet/bot) on Node 22.
ua-parser-js v1 and v2 are shown separately because their license terms differ sharply — that difference is the main reason ua-lite exists.
| ua-lite | ua-parser-js v1 | ua-parser-js v2 | |
|---|---|---|---|
| License | MIT | MIT (unmaintained) | AGPL-3.0 (commercial tiers available) |
| Bot/AI agent detection | ✅ built-in, free | ❌ | ✅, but gated behind AGPL copyleft or a paid commercial license |
| Client Hints | ✅ built-in | ➖ separate package | ✅ |
| Build step | None | None | Requires build |
| Bundle | Single file | Single file | Multi-file, plus a large bundled icon set |
Bundle size (gzip, the actual file require() resolves to):
| ua-lite | bowser | platform.js | express-useragent | mobile-detect | ua-parser-js v1 | ua-parser-js v2 | |
|---|---|---|---|---|---|---|---|
| gzip size | 6.0 KB | 7.6 KB | 11.9 KB | 8.4 KB | 22.5 KB | 8.7 KB | 13.6 KB |
Parse throughput (50,000 parses, warm, parses/sec):
| ua-lite | bowser | platform.js | express-useragent | mobile-detect | ua-parser-js v1 | ua-parser-js v2 | |
|---|---|---|---|---|---|---|---|
| parses/sec | 292,000 | 256,000 | 22,000 | 380,000 | 119,000 | 88,600 | 21,500 |
express-useragent edges out ua-lite on raw throughput — it returns a flatter, simpler object (mostly boolean flags) with less string-shaping per parse. platform.js is by far the slowest of the group, at roughly 1/17th of express-useragent's throughput.
Feature coverage — this is where the field narrows fast:
| ua-lite | bowser | platform.js | express-useragent | mobile-detect | |
|---|---|---|---|---|---|
| License | MIT | MIT | MIT | MIT | MIT |
| Browser name/version | ✅ | ✅ | ✅ | ✅ | ❌ |
| Engine (Blink/Gecko/WebKit) | ✅ | ✅ | ✅ (as "layout") | ❌ | ❌ |
| OS name/version | ✅ | ✅ (empty for bot UAs, correctly — no OS token to find) | ✅ | ✅ | ✅ (OS family only) |
| CPU architecture | ✅ (arch family: amd64/arm64/arm/...) | ❌ | ➖ (bit-width only — 32/64, misses arch family entirely, even for aarch64) |
❌ | ❌ |
| Device type (mobile/tablet/desktop/tv/console) | ✅ | ➖ (type: "bot" only) | ❌ | ➖ (boolean flags, no unified type) | ➖ (mobile/tablet booleans only) |
| Traditional crawler detection (Googlebot, Bingbot) | ✅ | ✅ (with vendor) | ❌ | ✅ | ❌ |
| AI-crawler detection (GPTBot, ClaudeBot, PerplexityBot) | ✅ | ✅ (with vendor) | ❌ | ❌ | ❌ |
| Generic script detection (curl, python-requests) | ✅ | ❌ | ❌ | ✅ | ❌ |
| In-app browser detection (Instagram, Facebook, TikTok) | ✅ | ➖ (device only, no wrapper flag) | ❌ | ➖ (Facebook flag only) | ❌ |
Client Hints (sec-ch-ua-*) parsing |
✅ | ❌ | ❌ | ➖ (field exists, must be fed manually) | ❌ |
Takeaways from actually running these side by side:
- bowser is the strongest of the four alternatives on bot detection —
it tags many known AI crawlers with a vendor field (
"Anthropic","OpenAI") and returns proper OS name/version for regular browsers — but it has no CPU architecture at all, and no generic-script detection (curl,python-requestscome back with an empty browser name, not flagged as bots). - platform.js is a legacy general-purpose detector: solid browser/OS
fields, a CPU field that only reports 32/64-bit (never resolves
aarch64to an actual arm64 family), no bot detection of any kind, and it's ~13–17x slower than the others in this table — it does noticeably more string work per parse than the others. - express-useragent is the fastest here and has real crawler/script
detection (
isBot,botName,isCurl), but it predates the AI-crawler wave — it correctly flags Googlebot and curl, but returns nothing for GPTBot or ClaudeBot. It also has aclientHintsfield in its output shape, but nothing parsessec-ch-ua-*headers into it automatically. - mobile-detect is a mobile-detection specialist, not a general UA parser — no browser name, no engine, no bot detection at all. It answers one question well ("is this a phone/tablet?") and nothing else.
- ua-parser-js v1 returns full browser/engine/OS/CPU/device fields under a permissive MIT license, but is unmaintained and has no bot or AI-agent classification at all — the gap ua-lite was built to fill.
- ua-parser-js v2 does have AI-crawler pattern lists as rich as ua-lite's, but the whole package (including that submodule) ships under AGPL-3.0. Using it in a closed-source service means either open-sourcing that service or buying a commercial license — a legal cost, not a runtime one. It's also the heaviest and slowest option in this whole comparison.
ua-lite is the only one of the six that combines full field coverage (browser/engine/OS/CPU/device), tiered bot/AI/app classification, and native Client Hints resolution in a single MIT-licensed file with no copyleft strings attached — the closest alternative on features (bowser) still needs OS/CPU data filled in from elsewhere, the fastest alternative (express-useragent) needs AI-crawler patterns added by hand, and the only other option with comparable AI-crawler coverage (ua-parser-js v2) requires either open-sourcing your own product or paying for a license.
MIT
{ "ua": "Mozilla/5.0 (Linux; Android 14; Pixel 8) AppleWebKit/537.36 ...", "browser": { "name": "Chrome", "version": "124.0.6367.82" }, "engine": { "name": "Blink", "version": "124.0.6367.82" }, "os": { "name": "Android", "version": "14" }, "cpu": { "architecture": null }, "device": { "type": "mobile", "vendor": "Google", "model": "Pixel 8" }, "agent": { "type": "browser", "name": "Chrome" } }