Safeguard
Open Source

Is react-native-device-info Safe? A Security Guide

react-native-device-info is one of the most-used device fingerprinting libraries in React Native. Here is how to use it without leaking data or tripping privacy reviews.

Priya Mehta
DevSecOps Engineer
6 min read

react-native-device-info is a well-maintained, low-dependency native module, so the real risk is not the package itself but what you do with the device data it exposes. The library surfaces more than 150 device properties, and several of them are the kind of identifiers that turn a routine analytics call into a privacy incident if you log or transmit them carelessly.

The package pulls roughly 1.1 million weekly downloads on npm and ships with zero direct runtime dependencies, which keeps its transitive attack surface small. That is the good news. The rest of this guide is about the parts that a dependency scanner will not catch: the data-handling decisions you make on top of it.

What react-native-device-info actually exposes

When people search for react-native-device-info npm they usually want a quick way to read a build number or check whether the app is running on a tablet. The library does that, but it also exposes a long tail of hardware and account identifiers:

  • getUniqueId() — a per-install identifier (Android uses a generated ID stored in the keystore; iOS returns identifierForVendor).
  • getMacAddress(), getIpAddress() — network identifiers, gated behind permissions.
  • getAndroidId() — the Android Settings.Secure ANDROID_ID.
  • getSerialNumber(), getInstanceId(), phone-model and carrier fields.

The problem is that many of these read like harmless telemetry but are treated as personal data under GDPR, CCPA, and Apple's App Store rules. A device serial or a stable unique ID is a persistent identifier. If you ship it to a third-party analytics endpoint without disclosure, you have a compliance gap regardless of how clean the npm package is.

The permission trap on Android

Several getters silently require Android permissions or return placeholder values when the permission is missing. getIpAddress() and getMacAddress() historically depended on ACCESS_WIFI_STATE and, on newer Android versions, return anonymized or constant values (02:00:00:00:00:00 for MAC) because the platform locked them down.

The security anti-pattern is requesting a broad permission just to satisfy a getter that no longer returns useful data. Audit which methods your code actually calls and strip the permissions you added speculatively. Over-requested permissions are one of the most common reasons an Android build gets flagged in a Play Store privacy review.

import DeviceInfo from 'react-native-device-info';

// Prefer async getters and handle the "not available" path.
const id = await DeviceInfo.getUniqueId();
// Do NOT do this:
// analytics.track('open', { deviceId: id, mac: await DeviceInfo.getMacAddress() });

Treat the unique ID as sensitive, not as a session key

A recurring mistake with react native device info is using getUniqueId() as an authentication or session token. It is stable, but it is not a secret — anyone with local access or a rooted device can read it, and on iOS the vendor identifier resets when all of a vendor's apps are uninstalled. Use it for coarse analytics or fraud signals, never as the thing that grants access to an account.

If you need a stable identifier for licensing or abuse prevention, hash it with a server-side salt so the raw device value never leaves the device in a form you can correlate across tenants.

Supply chain posture of the package itself

On the dependency side, the picture is reassuring. The package has no known open advisories at the time of writing, a healthy release cadence, and no direct runtime dependencies, which limits how much transitive code you inherit. Still, treat it like any other native module in your pipeline:

  • Pin the version in package-lock.json and review the diff on every bump. Native modules can introduce new Gradle or CocoaPods behavior between minor releases.
  • Run continuous SCA against your lockfile so a future advisory against the package or its build tooling surfaces before release. An SCA tool such as Safeguard can flag a newly disclosed issue transitively without you re-auditing by hand. Our software composition analysis product is built for exactly this lockfile-diff workflow.
  • Watch the native build dependencies (Gradle plugins, autolinking scripts) as carefully as the JS, since those run with your build machine's privileges.

Data minimization: collect the least you need

The cleanest way to de-risk this library is to wrap it in a small module that only exposes the two or three fields your product actually needs, and route everything else through a review gate.

// deviceContext.js — the only place allowed to import DeviceInfo directly
import DeviceInfo from 'react-native-device-info';

export async function safeDeviceContext() {
  return {
    appVersion: DeviceInfo.getVersion(),
    buildNumber: DeviceInfo.getBuildNumber(),
    isTablet: DeviceInfo.isTablet(),
    // deliberately NOT exporting unique id, serial, MAC, IP
  };
}

This pattern makes your privacy surface auditable: a reviewer greps for react-native-device-info and finds exactly one import. Everything sensitive is a deliberate, documented exception rather than a getter someone called in a hurry.

Disclosure and platform rules

Both Apple and Google now require you to declare what data your app collects. If you read persistent identifiers through this library and send them anywhere, they belong in your App Store privacy nutrition label and your Play Data Safety form. The library will not fill those out for you, and a mismatch between what your binary does and what your label says is a rejection risk. Keep a short data-flow note for every field you extract.

FAQ

Is react-native-device-info safe to use in production?

Yes. It is actively maintained, widely used, and has no direct dependencies, which keeps its supply chain footprint small. The residual risk is almost entirely in how you handle the identifiers it returns, not in the package code itself.

Does react-native-device-info require special permissions?

Only some methods do. Network-related getters like getIpAddress() and getMacAddress() touch Android WiFi permissions, and on modern Android many of those return anonymized values anyway. Request permissions only for the methods you actually call.

Can I use getUniqueId() as a login token?

No. It is a stable identifier, not a secret, and can be read on rooted or jailbroken devices. Use it for analytics or fraud signals and hash it server-side if you need to persist it.

How do I keep the package secure over time?

Pin the version, review the diff on every upgrade, and run continuous SCA against your lockfile so any future advisory against the package or its build tooling is caught before you ship.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.