Types
Type-only exports. Use import type so they're erased at runtime:
import type { Browser, OS, DetectOptions, ClientHints } from 'get-browser';
Browser
type Browser =
| 'android'
| 'chrome'
| 'edge'
| 'firefox'
| 'ie'
| 'opera'
| 'safari'
| 'unknown';
The full set of values detect() can return — and the canonical type for storing a detection result. Derived as:
type Browser = (typeof browsers)[keyof typeof browsers];
Using Browser instead of plain string gives you:
- Refactor safety. Renaming any value updates every type-checked use site.
- Exhaustiveness.
switchstatements without adefaultflag missing cases. - Autocomplete. Editors offer the eight literal options.
Tagging analytics
A classic use:
import { type Browser } from 'get-browser';
type Engine = 'chromium' | 'gecko' | 'webkit' | 'trident' | 'legacy-webkit' | 'unknown';
const engineOf = (b: Browser): Engine => {
switch (b) {
case 'chrome':
case 'edge':
case 'opera': return 'chromium';
case 'firefox': return 'gecko';
case 'safari': return 'webkit';
case 'ie': return 'trident';
case 'android': return 'legacy-webkit';
case 'unknown': return 'unknown';
}
};
If a future major adds 'samsung' to Browser, the engineOf switch breaks the build — exactly what you want.
OS
type OS =
| 'android'
| 'chromeos'
| 'ios'
| 'linux'
| 'macos'
| 'windows'
| 'unknown';
What getOS() returns. Derived from oses the same way Browser is derived from browsers.
'android' overlaps with Browser's 'android' (Android WebView) — but they're never produced by the same call. Use the source of the value, not its string, to know which dimension you're looking at.
DetectOptions
interface DetectOptions {
/** Full UA string to test against. Falls back to navigator.userAgent. */
readonly userAgent?: string;
/** navigator.vendor-equivalent string. Falls back to navigator.vendor. */
readonly vendor?: string;
/** Parsed User-Agent Client Hints. Consumed by getOS(); reserved for future use elsewhere. */
readonly clientHints?: ClientHints;
}
The optional shape every detector accepts. Pass it to make a detection deterministic — useful for:
- SSR — populate from request headers.
- Tests — pin a UA so the suite doesn't depend on the runner's identity.
- Multi-tenant SaaS — different policies based on the actual visitor, not the worker process.
When options.userAgent is provided, the detectors ignore globalThis.navigator entirely — even if it exists. That keeps the function pure with respect to its input.
import { isChrome } from 'get-browser';
// Forces a chrome UA regardless of where this runs.
isChrome({
userAgent: 'Mozilla/5.0 ... Chrome/140.0.0.0 ...',
vendor: 'Google Inc.',
});
ClientHints
interface ClientHints {
/**
* Value of Sec-CH-UA-Platform. Quoted or unquoted; case-insensitive.
* One of: "macOS", "Windows", "Linux", "iOS", "Android", "Chrome OS",
* "Chromium OS". Anything else falls back to UA matching.
*/
readonly platform?: string;
}
Parsed User-Agent Client Hints. Today only getOS() consumes this — it reads platform from the Sec-CH-UA-Platform request header. Other detectors will grow Client-Hint support over time without breaking changes.
The headline reason to prefer hints: Chrome's User-Agent Reduction is removing signal from the UA string. Hints are the long-term answer.