Developers: 5 Steps to Cross Platform Persistent Device IDs

Last updated on September 11, 2026 · 11 min read

A persistent device id is a stable identifier your app or backend generates and stores locally to recognize the same app instance or device across sessions. Use it for diagnostics, rate limiting, and secondary fraud signals, never as an authentication credential. It can and will be reset by app data clears, uninstalls, or factory resets, so any system built around it needs a fallback path for identity loss.
TL;DR:
- A persistent device id is stored locally to recognize app instances across sessions but resets when app data is cleared, uninstalled, or the device is factory reset.
- Android and iOS offer different storage methods that can survive reinstallations but not full device wipes, with Web storage being the most volatile.
- Use system APIs like Firebase Installation ID or platform-specific encrypted storage, verifying writes and migrating legacy data to ensure reliability.
- Never treat a device id as proof of identity or a hardware identifier, and keep clear separation from advertising IDs and authentication credentials.
- Build reconciliation and server-side signals into your design, and limit retention, linking device ids strictly to privacy policies and regulation compliance.
Table of Contents
- What Is a Persistent Device ID, and When Should You Use One?
- What a Persistent Device ID Is Not
- How Do Android, iOS, and Web Handle Persistent Storage?
- How Do You Implement a Persistent Device ID Reliably?
- What Happens to a Device ID After Reset, Reinstall, or Backup?
- How Do You Handle Privacy and Policy Requirements?
- What's the Practical Checklist for Adding a Device ID?
- Where Device Signals Fit in a Real Fraud Stack
- Where ShieldLabs Fits Into Your Device Signal Strategy
- Sources
What Is a Persistent Device ID, and When Should You Use One?
A persistent device id is a locally generated, locally stored value that survives app restarts and, depending on the storage layer, sometimes survives reinstalls. It differs from three adjacent concepts developers often conflate:
- Install-scoped ids reset every time the app is reinstalled or app data is cleared. Firebase Installation ID (FID) falls into this category.
- Device-scoped ids aim to survive reinstalls by anchoring to hardware-backed storage like Android's Widevine/MediaDrm or iOS Keychain, though even these are not immune to a factory reset.
- Session-scoped ids exist only for the length of a browser tab or app session, by design, and are the norm on the web.
Legitimate engineering uses include diagnostics (tying crash reports to a consistent instance), returning-device detection, rate-limiting heuristics on anonymous traffic, and feeding a secondary signal into a broader fraud model. Prefer building a device id when you need to recognize a client before a user logs in or without requiring one. Rely on server-side authentication whenever the action carries financial or account risk. The two are complementary, not interchangeable.
What a Persistent Device ID Is Not
A device id is not proof of identity, and it is not a credential. Anyone treating it as a login factor is building on a foundation that resets itself.
It's also not the same thing as a hardware identifier. IMEI and MAC address are hardware-level values tied to the physical radio or network interface. Both Android and iOS have restricted app access to these for years, pushing developers toward software-generated, app-scoped alternatives instead.
It's not an advertising id, either, even though the two get bundled together in casual conversation. The Advertising ID is user-resettable, opt-outable at the OS level, and Android's own policy prohibits caching it. Developers must call the API fresh each time and cannot silently link it to a persistent internal identifier without violating platform rules.
A quick gut check for scope confusion:
- Hardware id (IMEI/MAC): tied to physical hardware, largely inaccessible to apps now.
- Advertising id: user-resettable, opt-outable, must be fetched live rather than cached.
- App-scoped persistent id: developer-generated, stored locally, resets on data clear or uninstall.
Pro Tip: If your compliance team asks whether your device id "is like an advertising id," the answer they need to hear is no, and the follow-up question they should ask is whether you're storing it in a way that could accidentally merge with PII.
How Do Android, iOS, and Web Handle Persistent Storage?
Each platform gives you a different persistence ceiling, and none of them promise permanence.
Android offers two realistic paths. The stronger option uses Widevine/MediaDrm, a hardware-backed provisioning identifier available on most devices, which tends to survive longer than app-private storage. When MediaDrm isn't available, the practiced fallback is generating a UUID and writing it to EncryptedSharedPreferences, backed by the Android Keystore. Both approaches reset when the user clears app data, uninstalls the app, or performs a factory reset. Neither survives a full device wipe, and that's by design rather than a bug you need to work around.
iOS takes a different shape. The Keychain is the standard for persistent, service-scoped storage, and setting the accessibility attribute to kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly keeps the value off iCloud backups while still surviving app reinstalls on the same device, a meaningful distinction from Android's EncryptedSharedPreferences, which typically does not survive reinstall. That "this device only" clause matters: back up and restore to a new phone, and the Keychain entry does not travel with it.
Web is the most volatile of the three, deliberately. PointerEvent.persistentDeviceId is re-assigned per browser session specifically to prevent cross-site or cross-session fingerprinting, and Web Storage sits under the same privacy pressure that has been squeezing long-lived cookies for years. Treat any browser-side id as session-scoped unless you're pairing it with a server-issued cookie that has its own lifecycle rules.
If your backend needs to reconcile identity across Android, iOS, and web clients for the same user, don't expect a single device id to do that job. Build reconciliation around account-level signals and treat each platform's device id as a local hint, not a shared key.
How Do You Implement a Persistent Device ID Reliably?
Start with the system-provided option before you build your own. For app-instance analytics, Firebase Installation ID is the straightforward choice, and Android's own identity guidance recommends it over rolling a custom UUID scheme. If you're touching advertising use cases, follow the Advertising ID rules exactly, including the no-caching requirement.
When you do need a custom device id, a safe generation pattern looks like this:
- Generate a UUID client-side.
- Write it to encrypted storage (EncryptedSharedPreferences on Android, Keychain on iOS) synchronously.
- Verify the write succeeded before returning the id anywhere in your app logic.
- If a legacy plaintext id exists from an older app version, migrate it into encrypted storage and remove the plaintext copy only after the encrypted write is confirmed.
- If durable storage can't be initialized at all, return null rather than a temporary in-memory id that will silently disappear and confuse downstream analytics.
This create, persist, read, migrate, regenerate flow mirrors how the persistent_device_id Flutter plugin handles the problem: MediaDrm/Widevine first on Android, EncryptedSharedPreferences as fallback, Keychain on iOS, and an explicit null return when nothing durable is available.
Pro Tip: Never let a failed encrypted write pass silently. A device id that "exists" in memory but never made it to disk will vanish on the next cold start, and you'll spend a debugging session chasing a phantom identity split that a single log line would have caught.
Error handling deserves the same rigor as the happy path. Retry writes when storage becomes available again, rather than falling back to an unencrypted store out of convenience.
What Happens to a Device ID After Reset, Reinstall, or Backup?
Several everyday events change or destroy a device id, and your system needs to expect all of them rather than treat any as an edge case:
- App uninstall and reinstall (resets EncryptedSharedPreferences-backed ids on Android; Keychain ids may survive on iOS depending on accessibility settings).
- Clearing app data (resets both platforms' locally stored ids immediately).
- Factory reset (resets everything, including MediaDrm-derived values in most cases).
- Backup and restore to a new device (Keychain entries marked "this device only" do not transfer).
- Major OS updates (rare, but occasionally invalidate Keystore-backed entries on Android).
The migration pattern that avoids duplicate identities is straightforward in concept: on app start, check for a legacy id in the old storage location, and if one exists, migrate it into the new encrypted store atomically before issuing a fresh id. Never generate a new id first and check for a legacy one second. That ordering is how you end up with two ids representing one real installation.
Server-side, don't treat a changed device id as a hard loss of identity. Reconciliation approaches that link profiles through short-term activity signatures, account tokens, or incremental friction tend to hold up better than treating every new id as a brand-new visitor.
Pro Tip: Log every id change you detect, even the expected ones. A spike in "id changed" events after an app update is often your first signal that a migration path silently broke.
How Do You Handle Privacy and Policy Requirements?
Treat persistence as a liability you're managing, not a feature you're maximizing. A few operating rules keep you on the right side of both platform policy and reasonable user expectations:
- Minimize how long you retain a device id, and offer a user-facing reset path where the product context makes that reasonable.
- Never link the Advertising ID to PII or to your own persistent internal id. Play policy treats that combination as a violation, and the API's no-caching requirement exists partly to enforce it.
- For anything resembling authentication, prefer WebAuthn or passkeys, origin-scoped cryptographic credentials that NIST's SP 800-63B guidance treats as the stronger authenticator class. A device id belongs in the same request as a secondary signal, not as the deciding factor.
- Document your retention window, rotation triggers, and consent posture somewhere your legal team can actually find it, not just in a code comment.
- Log id-generation failures the same way you'd log any other storage error. Silent failures here compound into messy analytics months later.
Regulatory frameworks including GDPR in the EU and CCPA in California generally treat persistent device identifiers as personal data when they can be linked to an individual, which means consent and disclosure obligations apply the same way they would to cookies. Confirm your specific jurisdiction's requirements with counsel rather than assuming a general engineering pattern covers you.
What's the Practical Checklist for Adding a Device ID?
Before you write a line of storage code, work through this order:
- Decide the signal's role upfront: analytics and diagnostics, or a fraud-detection input. The answer changes how much rigor the implementation needs.
- Reach for system APIs first. FID covers most app-instance analytics needs without custom storage code.
- When a custom id is unavoidable, use encrypted storage with atomic writes, and migrate any legacy plaintext fallback safely rather than leaving two competing values in play.
- Build server-side reconciliation and logging into the design from day one, not as a patch after the first support ticket about duplicate accounts.
- Treat the device id as a soft signal everywhere in your stack. Require stronger verification, a password, a passkey, an OTP, for anything sensitive.
Where Device Signals Fit in a Real Fraud Stack
Device signals earn their place as inputs to a broader risk score, not as a verdict on their own. The strongest setups combine a device id with network, behavioral, and account-history signals, then keep every contributing signal visible enough to audit and adjust. Wiring in a client SDK plus server-side scoring is usually fast, and it pays off in debugging as much as detection.
— Jeff
Where ShieldLabs Fits Into Your Device Signal Strategy
Building reliable device recognition from scratch means solving persistence, migration, and reconciliation before you even get to the fraud logic. ShieldLabs gives engineering teams that groundwork already assembled: device and anonymity signals, a risk score built from over 100 data points, and detection covering VPNs, proxies, Tor, Private Relay, and anti-detect browser detection, delivered through a JavaScript snippet and server-side SDKs for Node.js, Python, Go, and PHP. Every score ships with the signals behind it, so your team decides what to do with the result rather than trusting a black box. For persistence specifically, the platform's returning-visitor recognition holds up to 99% accuracy even after cleared cookies and rotated IPs. Setup is designed to be quick to your first signal, with some free identifications available and no card required to start. If reconciling identity across resets and devices is eating your sprint time, check the product page and see whether a managed signal layer is faster than building your own.
Sources
- Work with advertising IDs | Android Developers
- PointerEvent.persistentDeviceId - MDN
- NIST SP 800-63B Digital Identity Guidelines
- persistent_device_id | Flutter package
Recommended
Related articles

Returning visitor conversion: recognizing the returning shopper to capture the lift
Returning visitors convert far better than first-timers, but logged-out shoppers look new. Recognizing the returning device captures the conversion lift.

Personalization for anonymous visitors: recognizing returning visitors without a login
How to personalize for returning visitors who are not logged in, by recognizing their device with a durable identifier that holds without cookies.

Persistent carts and preferences: keeping state for logged-out returning visitors
How to keep a returning visitor's cart and preferences across sessions without a login, by recognizing the device with a durable identifier.