get-browser
v2.3.0
Published
Lightweight, SSR-safe browser detection — strict TypeScript types, dual ESM + CJS, zero runtime dependencies.
Maintainers
Readme
import { detect, getEngine, getOS, isMobile, browsers, engines, oses } from 'get-browser';
if (detect() === browsers.SAFARI && isMobile()) {
applyMobileSafariFix();
}
if (getEngine() === engines.WEBKIT) applyWebkitScrollFix(); // also catches Chrome-iOS
const shortcut = getOS() === oses.MACOS ? '⌘ K' : 'Ctrl K';That's the whole pitch. Three canonical questions, three strict unions:
detect()→'chrome' | 'edge' | 'firefox' | 'safari' | 'opera' | 'ie' | 'android' | 'unknown'— who.getEngine()→'blink' | 'gecko' | 'webkit' | 'trident' | 'presto' | 'edgehtml' | 'unknown'— what renders it (correct on iOS).getOS()→'macos' | 'windows' | 'linux' | 'ios' | 'android' | 'chromeos' | 'unknown'— where it runs.
A handful of tree-shakeable predicates do the boolean versions.
Install
pnpm add get-browser # or npm / yarn / bunNo bundler? Drop in the UMD bundle:
<script src="https://unpkg.com/get-browser/dist/umd/get-browser.global.js"></script>
<script>
if (GetBrowser.isMobile()) document.body.classList.add('is-mobile');
</script>Why you'd use this
- 🪶 Tiny — ~1.4 kB min+gzip, zero dependencies, tree-shakeable.
- 🧠 Typed —
detect()returns theBrowserunion, neverstring. Exhaustive switches compile. - 🏗️ SSR-safe — every detector takes
{ userAgent }. Works in Node, Next.js, Remix, Astro, Workers, Deno. - 🎯 Honest — it answers who, not what. For capability checks use
@supports/matchMedia.
[!TIP] Want to see it in action without installing anything? Open the Playground — paste any user-agent and watch every predicate light up.
Usage
import { detect, browsers } from 'get-browser';
switch (detect()) {
case browsers.CHROME: loadChromeShim(); break;
case browsers.SAFARI: patchSafariScrollBug(); break;
case browsers.FIREFOX: enableFirefoxOnlyFeature(); break;
case browsers.UNKNOWN: /* bot or new browser */ break;
}import { isMobile, isChrome, isSafari } from 'get-browser';
if (isMobile() && !isChrome()) showNonChromeMobileBanner();
if (isSafari() && isMobile()) applyMobileSafariFix();// Next.js Edge route — runs on Cloudflare too
export const runtime = 'edge';
import { detect, getOS } from 'get-browser';
export function GET(req: Request) {
const userAgent = req.headers.get('user-agent') ?? '';
return Response.json({
browser: detect({ userAgent }),
// Prefer Sec-CH-UA-Platform — Chrome's UA Reduction is hollowing
// out the legacy UA string. Get-browser reads either.
os: getOS({
userAgent,
clientHints: { platform: req.headers.get('sec-ch-ua-platform') ?? undefined },
}),
});
}The library never touches window at import time. Pass an explicit UA and detection becomes a pure function — perfect for tests and SSR. Full framework cookbook in the SSR guide.
import { getOS, oses } from 'get-browser';
const os = getOS();
const shortcut = os === oses.MACOS ? '⌘ K' : 'Ctrl K';
const downloadUrl = os === oses.WINDOWS ? '/dl/app.exe'
: os === oses.MACOS ? '/dl/app.dmg'
: os === oses.LINUX ? '/dl/app.deb'
: '/dl/';
const storeUrl = os === oses.IOS ? 'https://apps.apple.com/…'
: os === oses.ANDROID ? 'https://play.google.com/…'
: '/install';import { isInAppBrowser } from 'get-browser';
// OAuth providers (Google, Apple, Microsoft) block sign-in inside
// most in-app browsers. Bounce to the system browser first.
if (isInAppBrowser()) {
showOpenInBrowserBanner({
message: 'Tap ⋯ → "Open in browser" to continue with Google sign-in.',
});
}Catches Facebook (FBAN/FBAV/FB_IAB), Instagram, X/Twitter, LinkedIn, TikTok, Snapchat, WeChat, Line, Telegram, Pinterest. Stable token-based matching — version-agnostic.
import { detect, getEngine, engines } from 'get-browser';
// One check covers Safari + Chrome-iOS + Firefox-iOS + Edge-iOS.
if (getEngine() === engines.WEBKIT) applyWebkitScrollFix();
// Honest analytics: "who" and "what renders it" are different questions.
analytics.track('page_view', { browser: detect(), engine: getEngine() });getEngine() reads the engine from the UA, so Chrome-on-iOS reports 'webkit' (what actually paints the page) — not 'blink'. A hand-rolled browser → engine lookup gets that wrong.
API
A small surface — every export pulls its weight.
| | |
| --- | --- |
| detect(opts?) | Returns one of the browsers values |
| getEngine(opts?) | Returns one of the engines values |
| getOS(opts?) | Returns one of the oses values |
| isChrome / isEdge / isFirefox / isSafari | (opts?) => boolean |
| isOpera / isIE / isAndroid / isMobile | (opts?) => boolean |
| isInAppBrowser | (opts?) => boolean — true inside Instagram, Facebook, TikTok, X, LinkedIn, … |
| browsers, oses, engines | Frozen enums: { CHROME: 'chrome', ... }, { MACOS: 'macos', ... }, { WEBKIT: 'webkit', ... } |
| Browser, OS, Engine, DetectOptions, ClientHints | Type-only exports |
opts is { userAgent?: string; vendor?: string; clientHints?: { platform?: string } } — pass userAgent for SSR or tests, pass clientHints.platform (the Sec-CH-UA-Platform header) for the most reliable OS read.
How it stacks up
| Bundle (min+gz) | get-browser | detect-browser | bowser | ua-parser-js | | --- | :-: | :-: | :-: | :-: | | | 🏆 ~1.4 kB | ~2 kB | ~7 kB | ~10 kB |
Pick ua-parser-js if you need version numbers or device info. Pick get-browser if you just need the single, lowercase, typed answer to which browser is this? — see the full comparison.
What it detects
Chrome, Edge (legacy & Chromium), Firefox, Safari (desktop, iOS, iPadOS), Opera (Presto & OPR), Internet Explorer 6-11, Android WebView — including iOS variants (CriOS, FxiOS, EdgiOS) and mobile / tablet user-agents. Coverage details: browser support.
Requirements
- Node ≥ 20 (active LTS — 20, 22, 24)
- TypeScript ≥ 5.0 if you use types
- Browsers — evergreen. UMD bundle is ES2018.
Documentation
The full docs are built with Docusaurus and deployed to GitHub Pages:
| 📚 Docs | 🔌 API | 🧪 Playground | 🍳 Recipes | 🏗️ SSR | 🔄 Migration | | :-: | :-: | :-: | :-: | :-: | :-: |
Run the docs locally:
pnpm install
pnpm run build # build the library first
pnpm run website:install
pnpm run website:dev # http://localhost:3000Contributing & license
PRs welcome — see CONTRIBUTING.md. For security issues, see SECURITY.md (please don't open public issues for vulnerabilities).
MIT © yankouskia and contributors.
