Tiny, typed, SSR-safe browser detection.
One call. One canonical answer. ~1.4 kB min+gzip. Zero dependencies.
📚 Docs site · 🧪 Playground · 🍳 Recipes · ↗️ v1 → v2
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
Switch on the browser
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; }
Booleans — tree-shakes to ~400 bytes per predicate
import { isMobile, isChrome, isSafari } from 'get-browser'; if (isMobile() && !isChrome()) showNonChromeMobileBanner(); if (isSafari() && isMobile()) applyMobileSafariFix();
Server-side — Next.js, Remix, Workers, Deno
// 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.
Cross-platform UI — shortcuts, downloads, deep links
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';
In-app browsers — Instagram, Facebook, TikTok, X, LinkedIn, …
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.
Rendering engine — correct on iOS, where everything is WebKit
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:3000
Contributing & license
PRs welcome — see CONTRIBUTING.md. For security issues, see SECURITY.md (please don't open public issues for vulnerabilities).
MIT © yankouskia and contributors.





























