OS Detect
Lightweight OS, form-factor, and runtime detection for browsers, Node.js, and SSR — with React hooks and Vue composables. No dependencies.
Features
getOS()— returns a typed string identifier for the current OS; detection priority ensures ChromeOS is never misidentified as Linux- Boolean functions —
detectIsIOS(),detectIsMacOS(),detectIsAndroid(),detectIsWindows(),detectIsLinux(),detectIsChromeOS()— all synchronous and cached detectIsWindows11()— async; usesnavigator.userAgentData.getHighEntropyValues()in the browser andos.release()in Node.js- Device category —
isMobileDevice()andisDesktopDevice()for quick coarse checks getFormFactor()—'phone' | 'tablet' | 'desktop' | 'tv', driven by OS and physical screen size, not touch capability — a touchscreen Windows laptop is still'desktop'detectHasTouch()andgetPrimaryInput()— whether the device has a touchscreen at all, and which input type ('mouse'|'touch') is actually primary right now; the latter updates live on hybrid devices when a keyboard/mouse is attached or detachedgetPixelRatio()anddetectIsTV()— physical-to-logical pixel ratio, and best-effort smart TV detectiongetRuntime()—'node' | 'browser' | 'webworker', plus standalonedetectIsNode(),detectIsBrowser(),detectIsWebWorker(),detectIsElectron(), anddetectIsPWA()checks- React hooks —
useOS(),useIsWindows11(),useFormFactor(),useRuntime(), and the live-updatingusePrimaryInput()fromos-detect/react - Vue composables — the same five, from
os-detect/vue, as readonly refs - Node.js support — reads
process.platformin Node.js (including Node 21+, where the runtime exposes its own syntheticnavigatorglobal);detectIsWindows11()usesos.release()build number - iPadOS 13+ detection — correctly identifies iPads that send
Macintoshin their userAgent vianavigator.maxTouchPoints - Result cache — every function caches its result after the first call, except
getPrimaryInput()/getPixelRatio()(deliberately live — see API Reference) - Zero runtime dependencies — no external packages; React and Vue are optional peer deps
- Tree-shakeable ESM — import only what you use; UMD and CJS bundles also included
How It Works
Browser — checks navigator.userAgentData.platform first (Chrome 90+ / Edge 90+, not spoofable by userAgent overrides), then falls back to navigator.userAgent regex matching for browsers that don't implement it (Firefox, Safari, older Chrome).
Node.js — reads process.platform directly; no userAgent parsing happens server-side. detectIsWindows11() additionally dynamically imports the built-in os module and parses the build number from os.release().
All results are cached in module-level variables after the first call, so repeated calls in render functions or computed properties are effectively free — see resetDetectionCache() if you need to force a re-check.
Form factor and runtime context follow the same idea, with two deliberate exceptions. getFormFactor() and getRuntime() are composed from the same kind of cached, synchronous checks as getOS(). getPrimaryInput() and getPixelRatio() are not cached — a hybrid device's primary input, or a window's pixel ratio, can genuinely change mid-session, so both re-read the live signal on every call instead of freezing the first answer forever.