react-native-nitro-device-info is built on Nitro,
a JSI/native technology. A browser has no native module, so the goal on web is
narrower than on native: the package must be import-safe and return honest
fallback values — not reproduce every device API.
This lets teams whose monorepo targets both native and web (react-native-web, Next.js SSR) depend on the package without their web build crashing.
The package ships a pure-JS web implementation (DeviceInfo.web.ts) that
satisfies the full DeviceInfo interface. Your bundler selects it
automatically — there is no separate package to install and no import path to
change.
Selection happens through two complementary mechanisms, so it works across the common web toolchains:
.web.ts platform
extension (index.web.ts is tried before index.ts) and also asserts the
browser export condition for the web platform.package.json exports map declares a
"browser" condition that points at the web build, which webpack honors for
target: 'web'.On the server during SSR, the native entry is also import-safe: the native HybridObject is created lazily (on first property access, not at module load), so merely importing the package never throws — and during server render no property is read, so the native binding is never touched.
The fallback returns a real value where a browser API can answer, and otherwise
the same neutral constants the native side uses for an unsupported platform
("unknown" / -1 / false / []). Values are never fabricated to look
real.
| Member | Source |
|---|---|
systemName |
parsed from navigator.userAgent ("Windows"/"macOS"/"iOS"/"Android"/"Linux", else "web") |
systemLanguage |
navigator.language |
brand, manufacturer |
navigator.vendor |
totalMemory |
navigator.deviceMemory × 1024³ (coarse, spec-bucketed; -1 if unsupported) |
getIsLandscape() |
screen.width > screen.height |
getUserAgent() |
navigator.userAgent |
getBatteryLevel(), getPowerState(), getIsBatteryCharging() |
Battery Status API (navigator.getBattery()), read once and cached; -1 / "unknown" if absent or denied |
getIsAirplaneMode() |
inferred from navigator.onLine (best effort) |
When the underlying global is missing (an older browser, or a server with no
navigator/screen), each of these degrades to the fallback constant rather
than throwing.
Build.* fields (androidId, serialNumber, fingerprint,
board, bootloader, apiLevel, securityPatch, …)isDeviceCompromised() returns falseversion, buildNumber, bundleId, applicationName, …)isMouseConnected, hostNames, …)Methods that return a Promise keep their signature and resolve the fallback
— they do not reject — so existing await call sites keep working:
The one exception is getDeviceToken(), which rejects on web. It is Apple
DeviceCheck, which has no web equivalent — this mirrors its documented behavior on
Android.
Every browser global is read through a typeof guard, and the native singleton
is lazy, so importing the package and reading any member on a server never
throws. Browser-derived values (battery, screen, navigator) naturally fall back
to constants on the server, then reflect real values once the app runs in the
browser.