← /writing #android#device-id#privacy#deprecated-apis

the four device IDs on Android — what changed since 2013

Secure Android ID, GSF ID, UUID, IMEI. Four ways to identify an Android device in 2013. The app I shipped to Play Store to expose them, and what happened to each over the decade.

In 2013 I shipped an Android app called DeviceID to the Play Store. The app fetched and displayed four unique identifiers for the device it ran on: the Secure Android ID, the Google Service Framework (GSF) ID, a UUID, and the IMEI. The app had a deliberate constraint — no INTERNET permission. Whatever you saw was computed locally; nothing left the device.

The reason the app existed at all was that developers needed device IDs and the documentation was scattered. Push notifications needed an ID. Anti-fraud needed an ID. Analytics needed an ID. The four IDs each had different lifetimes, different reset behaviour, and different uniqueness guarantees, and none of this was clearly explained in one place.

Here is what each ID was, what it was useful for, and what happened to it over the next decade.

1. the Secure Android ID

A 64-bit number generated when the device first boots after a factory reset. Stored in Settings.Secure.ANDROID_ID. Persistent across reboots, app installs, and Play Services updates, but reset to a new value when the user does a factory wipe.

This was the workhorse ID in 2013. Most apps used it for analytics and lightweight anti-fraud. It was cheap to fetch (no permissions needed), reasonably unique, and stable enough for cross-session correlation.

What changed. In Android 8 (2017), the Secure Android ID was scoped to the (app signing key, user, device) tuple. Two apps on the same device get different ANDROID_ID values. This broke cross-app correlation but made the ID safer from a privacy standpoint. The ID is still useful as a per-app device fingerprint. It is no longer useful as a universal device identifier.

2. the GSF (Google Service Framework) ID

A 64-bit number associated with the Google account on the device. Accessible via a query on the GSF content provider (com.google.android.gsf.gservices). Tied to the user’s Google account, not to the hardware.

This was the ID Google’s own push notification system (then GCM, now FCM) used internally. Fetching it required no special permissions but did require knowledge of the obscure content provider URI. The GSF ID was unique across devices for the same user, and persisted as long as the Google account was present.

What changed. The GSF ID still exists but is no longer the right way to get a stable user identifier. Firebase Cloud Messaging now exposes its own registration token (FirebaseMessaging.getInstance().token), which is scoped per app + per Firebase project and rotates on certain events. For push targeting, the FCM token replaced the GSF ID entirely.

3. UUID (locally generated)

Not really a “device ID” — a UUID generated by the app on first launch and stored in app-private storage. Uninstalling and reinstalling the app generates a new UUID.

In 2013 this was the “fallback” ID. If you wanted something stable for the lifetime of an install and didn’t want to depend on the device hardware, you generated a UUID and stored it. It was opaque to anyone outside your app and rotated whenever the user did a clean reinstall.

What changed. Nothing. The UUID approach still works exactly the same way. It is the only one of the four IDs whose semantics did not shift over the decade. For most analytics use cases in 2026, this is what you should be using.

4. IMEI

The hardware identifier burned into the device’s modem. Accessible via TelephonyManager.getDeviceId() in 2013 (deprecated since Android 6 and removed in Android 10 unless the app is a system app).

The IMEI was the strongest identifier — globally unique, never reset, tied to the physical hardware. It was also the most privacy-invasive, because it allowed cross-app, cross-account, cross-install tracking of a specific physical device.

What changed. Google steadily restricted IMEI access. Android 6 required READ_PHONE_STATE permission and the new runtime permission flow. Android 10 made the IMEI inaccessible to non-system apps regardless of permission. In 2026, a normal app cannot get the IMEI on any current Android version.

Good. The IMEI being accessible was a privacy mistake from the beginning. Removing it took six years too long.

why the app had no INTERNET permission

The thing I was proud of about the DeviceID app was that it had no INTERNET permission. Whatever it showed you was computed locally. Nothing was sent anywhere. There was no analytics, no telemetry, no anonymous-data-collection toggle.

For an app whose entire purpose was to expose device identifiers, this was the only honest design. If the app had INTERNET permission, the user would reasonably assume the app was phoning the IDs home. The whole proposition would collapse.

The “no internet permission” became part of the app’s listing copy in the Play Store. This app DOES NOT REQUIRE INTERNET permission. Its safe to use. In 2013 this was an unusual statement. Most utility apps shipped with INTERNET permission requested but unused, as a hedge against later needing it.

what the app taught me

Three things, in retrospect.

Privacy as a feature works even when the audience is developers. The “no internet permission” angle attracted positive comments on the Play Store and elsewhere. Developers (the audience for this utility) understood and appreciated the constraint. The same lesson reappeared a decade later with DailyVox’s “Data Not Collected” positioning.

Permission boundaries are user-visible commitments. What permissions an app declares is a public commitment to the user about what it cannot do. Apps that under-declare permissions earn trust over time; apps that over-declare permissions lose it.

Platform identifiers are not durable engineering primitives. Building on any of the four IDs in 2013 meant accepting that Google could change the semantics at any time. They did, repeatedly, over the next decade. The apps that depended heavily on IMEI or pre-2017 ANDROID_ID had to rewrite their identity stacks multiple times. The apps that used locally-generated UUIDs had to rewrite nothing.

For identifiers, bet on the things you control. The platform identifiers will keep moving. Yours will not.

the close

The DeviceID app is still on the Play Store as of 2026 with the same code from 2013. Some of the IDs it shows no longer return what they used to — ANDROID_ID is scoped, IMEI is not accessible to non-system apps. The app’s text explains what each ID was, and the difference between then and now is visible to the user.

The app has aged but the writeup has not. The mental model of “Android has multiple identifiers, each with different lifetimes and privacy properties” is still right in 2026. The specific APIs have changed; the underlying tension between developer needs and user privacy has not.

Pick the identifier whose semantics match your problem. Treat platform identifiers as movable. Treat your own UUIDs as durable. The decade of Android API changes has only made this clearer.

★ Achievement
NORMAL main ~/intrepidkarthi/writing/the-four-device-ids-on-android.md · est. 2008 ● 3y+ streak utf-8 visitor #043,217