react-native-device-info: the unglamorous module every React Native app ends up installing
Device Information for React Native iOS and Android
At a glance
- What is it?
- A native module that exposes device, battery, build and hardware facts to JavaScript, with a synchronous variant for most calls and a support matrix that spells out which platform gets what.
- Who is it for?
- This module earns its place by being boring in the right way. It wraps a large number of platform-specific native calls behind one JavaScript import, and its README is unusually honest about which platforms implement which function, including the ugly cases where a synchronous variant only exists on Android.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 4 days ago.
- What is it written in?
- Mainly TypeScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 11, 2026, and from our analysis. They are not legal advice.
Editorial analysis
Installing the module and what automatic linking changed
Install is one line, and the README gives both package managers:
npm install --save react-native-device-infoyarn add react-native-device-infoThe interesting part is what comes after. There is a Linking section that opens by naming linking as a frequent source of trouble for new React Native developers, citing errors such as RNDeviceInfo is null. The answer the project settled on is automatic linking, and it is supported on all platforms, including Windows on React Native 0.63 and later.
That is a reversal worth noticing. Earlier versions of the README carried manual linking instructions per platform, and the current text says previous versions need manual linking, that no support is offered for those, and points you at the upgrade-helper tool instead. So if you are working through a tutorial written before the automatic linking era, ignore its native step; the module resolves itself through the platform project files.
There is also a v6 to v7 upgrade note sitting near the top: the iOS Podfile minimum moves to iOS 10 and version 7 dropped iOS 9. That is old history, but it explains why an old fork or a pinned major version behaves differently on an old device.
The support matrix is the most useful table in the README
Most APIs in this module are platform-specific, and the README says so before listing anything. If a platform has no implementation, the defaults come back as the string unknown, the number minus one, or false, with arrays and objects empty.
Those defaults are the reason to read the matrix rather than the function names. The table has a column per platform: iOS, Android, Windows, Web, and visionOS. A row such as getAndroidId shows a check only under Android, meaning on iOS it resolves to unknown rather than throwing. getUserAgentSync is called out separately, because while the asynchronous getUserAgent works on both mobile platforms, the synchronous form is Android only.
The sync-versus-async split is a real design decision rather than a naming quirk. Most calls return a Promise, and most have a companion with Sync on the end that operates synchronously. The README's stated reason is app startup: you would rather call isCameraPresentSync during bootstrap than deal with async calls in the first frames of launch.
VisionOS having its own column is a newer signal. It tells you the module is being kept in step with new platform targets rather than frozen at the last mobile release, which is reassuring for a dependency you cannot easily replace once its return values are spread through your analytics and bug-reporting code.
Proguard rules that only apply to two specific features
The module asks for exactly two Proguard additions, and each is tied to a named feature rather than to the library as a whole. The first is for Install Referrer tracking:
-keep class com.android.installreferrer.api.** {
*;
}The second covers a specific symptom: if hasGms() misbehaves on a release build, add the rule for Google's common services:
-keep class com.google.android.gms.common.** {*;}Both are conditional. Install Referrer needs the rule only if you use the feature, and the GMS rule only if you call hasGms. That restraint matters, because the usual failure mode with a library like this is shipping a fat keep rule set that hides real problems.
There is an earlier section on AndroidX support that is worth reading with suspicion rather than trust. It tells you the module defaults to AndroidX, and it presents a Gradle ext block with version numbers such as compileSdkVersion set to 28, targetSdkVersion 28, firebaseIidVersion 19.0.1 and supportLibVersion 1.0.2, plus three alternatives for the deviceId dependency. Those defaults describe an older generation of Android builds than the one the current releases require, so treat the block as a template for where these knobs live rather than as values to copy. If you need non-AndroidX, the README points at the jetifier package in reverse mode.
Usage stays deliberately plain
There is no provider, no hook requirement, and no configuration step in the quick start. You import the module, either as a default or through destructuring:
import DeviceInfo from 'react-native-device-info';
// or ES6+ destructured imports
import { getUniqueId, getManufacturer } from 'react-native-device-info';What you get back depends on the call, and the API reference behind the anchors in the table documents each one. The functions span identifiers and hardware such as getAndroidId, getApiLevel, getBootloader and getManufacturer, build metadata such as getApplicationName, getBuildId, getBuildNumber and getBundleId, and device state such as getBatteryLevel and getCarrier.
Release 15 added one more of the identifier family: getAppSetId, described as a specific type of Android id, with a required compileSdk of 34 or later. A later patch, 15.0.2, added an optional Gradle dependency for it so the feature works when the host app does not already pull that dependency in. That is the pattern to expect from this module: a new native call arrives, and the surrounding build requirements move with it.
There is also a hooks and events section in the table of contents, so subscription-style APIs exist alongside the one-shot calls, for values such as battery level that change while the app is running.
Build requirements moved from 28 to 34 and that is the upgrade story
The single most consequential line for an adopter is in the release notes rather than the README. Version 15.0.0, published in November 2025, lists a breaking change for Android: it requires compileSdk 34 or later. The support matrix, the Proguard notes and the older ext block all still read like an earlier era, so the release notes are where the real floor is stated.
That is also why the older Gradle ext block and the current requirement disagree. The block with compileSdkVersion 28 predates the requirement; it is left in place because the version-variable knobs are still the right place to configure things, not because 28 is a supported value today. A reader who copies it verbatim into a modern app will hit build failures that have nothing to do with this module.
The build system itself is a Yarn workspace with a nested example app. The scripts show the shape of the development loop: an analyze target that runs both the TypeScript and Flow checks, a ts-check invoking tsc against tsconfig.build.json, a flow-check running flow-bin over a Flow declaration file, a clean target that resets the example project and removes iOS pods, and a dev-sync that copies the built output into the example app's node_modules.
Package metadata corroborates the versioning. The published version field is 15.0.2, matching the latest tag, and the files array ships the TypeScript source, the compiled output for both CommonJS and ES modules, the Android, iOS, web and Windows platform folders, and the podspec.
What the repository does not answer
The README is long and mostly a reference, and it is honest about its boundaries. The example app is pointed at repeatedly as the place to go when a function is unclear, and the README asks that any bug be reproduced there first, which is a reasonable stance for a module with a hundred platform-specific branches.
What you will not find on the README is a policy on identifiers. Several functions return values that on Android have been progressively restricted by the platform, and getUniqueId in particular changed behaviour across Android releases as Google tightened access to hardware identifiers. The README documents the return types; it does not promise stability of the underlying value. If your analytics depend on a stable per-device key, that is a decision to make on your own terms rather than something this documentation settles.
The typedoc configuration, the CODEOWNERS file and the MAINTAINERS file point to a project with real review structure rather than a single maintainer, and the open issue count is low for the download numbers this package sees. The last push was on 2026-09-12. Nothing is archived, and the project is clearly still in use, so the realistic risk here is not abandonment but the quiet churn of native APIs changing underneath a stable JavaScript surface.
Editorial conclusion
This module earns its place by being boring in the right way. It wraps a large number of platform-specific native calls behind one JavaScript import, and its README is unusually honest about which platforms implement which function, including the ugly cases where a synchronous variant only exists on Android. The parts to read before adopting it are the support matrix near the top of the README and the compileSdk floor, which release 15 raised to 34. Start by finding your actual call in the matrix, confirm the platform column says what you need, and pin the version in lockstep with your React Native upgrade rather than tracking the tip of master.
Frequently asked questions
How do I get my device ID?
The module exposes several identifiers, and they differ by platform. getAndroidId is listed as Android only, getAppSetId arrived in release 15 as an Android-specific type of device id that needs compileSdk 34 or later, and getUniqueId appears in the README's destructured import example as a general-purpose option. On a platform with no implementation the call resolves to the string unknown rather than failing.
How to get device info in React Native?
Install the react-native-device-info package and import it. Most calls return a Promise and have a companion with Sync on the end for use during app bootstrap, so you can avoid async work in the first frames of launch. Linking is automatic on all platforms, including Windows on React Native 0.63 and later.
What does the module return on an unsupported platform?
Default values rather than errors. The string unknown for string returns, minus one for numbers, false for booleans, and empty arrays or objects for the aggregate types. The support matrix in the README marks each function per platform so you can check before you call.
What compileSdk does the current version need?
Release 15.0.0 lists a breaking change requiring compileSdk 34 or later on Android, which is what its getAppSetId feature needs. Note that the AndroidX section of the README still shows an older ext block with compileSdkVersion 28, so treat that block as a template rather than as values to copy.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/react-native-device-info-react-native-device-info)