Skip to content

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; uses navigator.userAgentData.getHighEntropyValues() in the browser and os.release() in Node.js
  • Device category — isMobileDevice() and isDesktopDevice() 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() and getPrimaryInput() — 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 detached
  • getPixelRatio() and detectIsTV() — physical-to-logical pixel ratio, and best-effort smart TV detection
  • getRuntime() — 'node' | 'browser' | 'webworker', plus standalone detectIsNode(), detectIsBrowser(), detectIsWebWorker(), detectIsElectron(), and detectIsPWA() checks
  • React hooks — useOS(), useIsWindows11(), useFormFactor(), useRuntime(), and the live-updating usePrimaryInput() from os-detect/react
  • Vue composables — the same five, from os-detect/vue, as readonly refs
  • Node.js support — reads process.platform in Node.js (including Node 21+, where the runtime exposes its own synthetic navigator global); detectIsWindows11() uses os.release() build number
  • iPadOS 13+ detection — correctly identifies iPads that send Macintosh in their userAgent via navigator.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.