undevice
v0.1.3
Published
Runtime-agnostic user-agent device detector
Downloads
358
Maintainers
Readme
undevice
Runtime-agnostic device detection from User-Agent and CDN headers.
Works on Node.js, browsers, and edge runtimes.
Not affiliated with the UnJS organization.
Install
# npm
npm install undevice
# pnpm
pnpm install undevice
# yarn
yarn add undevice
# bun
bun install undeviceAPI
detectDevice
declare function detectDevice(input?: DetectDeviceInput): DeviceFlagsPure function: does not read globals or mutate input. Default input is {}.
Types
type DeviceHeaders = Readonly<Record<string, string | undefined>>
type DetectDeviceInput = Readonly<{
userAgent?: string
headers?: DeviceHeaders
}>
// Boolean flags only (see Flags); does not include userAgent
type DeviceFlags = DeviceKindFlags & OsFlags & BrowserFlags & {
isCrawler: boolean
}DeviceHeaderskeys are matched case-insensitively.DeviceFlagsdoes not echo the inputuserAgent.
Invariants
Exactly one device kind flag is true:
isMobile|isTablet|isDesktop|isUnknown
isMobileOrTablet and isDesktopOrTablet are derived from that kind.
Empty userAgent without a recognized CDN device hint yields isUnknown: true. Choosing a UI fallback is the caller's responsibility.
User-Agent matching is heuristic, not a security boundary.
Signal precedence
- CloudFront viewer headers — only when
userAgentisAmazon CloudFront - Cloudflare
cf-device-type - User-Agent string
Exports
| Kind | Name |
| --------- | ------------------------------------------------------------------------------------------------------------------ |
| Function | detectDevice |
| Types | DetectDeviceInput, DeviceHeaders, DeviceFlags, DeviceKindFlags |
| Constants | DeviceKind, BrowserName, CloudflareHeader, CloudflareDeviceType, CloudFrontHeader, CloudFrontUserAgent |
Usage
import { detectDevice } from "undevice";
const device = detectDevice({
userAgent: "Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X)",
});
device.isMobile; // true
device.isIos; // true
device.isSafari; // trueconst device = detectDevice({
userAgent: request.headers.get("user-agent") || undefined,
headers: Object.fromEntries(request.headers),
});For SSR, pass the same input on server and client.
Flags
Device kind:
isMobileisTabletisDesktopisUnknown
Derived:
isMobileOrTabletisDesktopOrTablet
OS:
isIos/isAndroid/isWindows/isMacOS/isLinux/isApple
Browser:
isChrome/isFirefox/isSafari/isEdge/isSamsung
Other:
isCrawler
CDN Headers
import { CloudflareHeader, CloudflareDeviceType, detectDevice } from "undevice";
detectDevice({
userAgent: "Mozilla/5.0 ...",
headers: {
[CloudflareHeader.DeviceType]: CloudflareDeviceType.Mobile,
},
});import { CloudFrontHeader, CloudFrontUserAgent, detectDevice } from "undevice";
detectDevice({
userAgent: CloudFrontUserAgent.AmazonCloudFront,
headers: {
[CloudFrontHeader.IsMobileViewer]: "true",
[CloudFrontHeader.IsIosViewer]: "true",
},
});Constants
import {
DeviceKind,
BrowserName,
CloudflareHeader,
CloudflareDeviceType,
CloudFrontHeader,
CloudFrontUserAgent,
} from "undevice";
DeviceKind.Mobile; // "mobile"
CloudflareHeader.DeviceType; // "cf-device-type"Feature set inspired by @nuxtjs/device.
