Deeplinkly
All articles
Device IdentityMobile Attribution

Device ID Tracking for Mobile Apps: A Privacy-Aware Implementation Guide

Published May 8, 2026·Updated August 5, 2026·12 min read·By Sahil Asopa
Privacy-aware mobile measurement architecture with consent and identifier states

Device-ID tracking is no longer a matter of reading one value at app launch and attaching it to every event. A production measurement system must select identifiers by purpose, respect platform permission and reset states, separate account identity from device signals, and continue operating when no advertising ID exists.

This implementation guide focuses on architecture: consent state, event contracts, data storage, deterministic and aggregate attribution, explicit unmatched states, deletion, and testing. For platform retrieval examples, see How to Find a Device ID on iOS and Android.

Start with a purpose matrix

Inventory every reason your app wants an identifier before integrating an SDK.

PurposePreferred signalAvoid
Signed-in product experienceFirst-party account IDTreating a device as a person
Anonymous app analyticsInstallation ID, IDFV, FID, or App Set ID as appropriateAdvertising ID by default
Advertising measurementIDFA after ATT authorization; Google Advertising ID when availableHardware IDs or reset bridging
Deep-link routingSigned link parameters and server-side statePutting personal data in a URL
Fraud or app integrityApp Attest, DeviceCheck, or Play Integrity as appropriateA permanent fingerprint presented as identity
Customer supportApp-generated diagnostic IDAdvertising IDs in tickets or logs

For each row, record owner, platform, lawful basis or consent requirement, disclosure, retention, processors, and deletion behavior. This is an engineering specification, not a blanket claim of legal compliance. Requirements differ by product, data flow, and jurisdiction; involve qualified privacy counsel where needed.

Model state explicitly

A boolean tracking_enabled cannot represent modern platform behavior. Use a state machine.

iOS ATT state

Apple exposes four states through AppTrackingTransparency:

Only the authorized path should enable IDFA access and tracking that falls under Apple’s definition. Apple states that without permission the IDFA is all zeros and developers may not use a different identifier, including a hashed email or phone number, to continue tracking across other companies’ apps or websites.

Android advertising state

Represent at least:

These are expected product states, not exceptional crashes. Google Play policy says the advertising ID should replace other device identifiers for advertising when it is available, and reset or deletion choices must be respected.

Product privacy state

Platform permission is only one input. Your application may also need a regional consent or opt-out state, age treatment, account deletion state, or customer contract restriction. Compute an effective policy from all applicable inputs and default to the less permissive behavior when signals conflict.

Separate identity layers

Use different keys for different jobs:

text
account_id         signed-in first-party account
installation_id    one installed app instance
vendor_or_set_id   permitted analytics across your own apps
advertising_id     platform advertising identifier, when permitted
session_id         one app session
event_id           idempotency key for one event

Never use an advertising ID as the account primary key. Never assume an installation ID survives reinstall. Never silently merge a new advertising ID with an old profile after reset.

An identity graph should store relationships with purpose, source, first-seen time, last-seen time, and authorization state. When permission changes, revoke the relationship for future processing and follow the deletion or suppression rules your policy requires.

Implement collection in phases

Phase 1: initialize essential app services

At cold start, generate or retrieve the installation ID, create a session ID, and initialize only services allowed before consent. Queue essential operational events locally if needed, but do not initialize an advertising SDK early merely because it is convenient.

Phase 2: resolve policy

Load regional/product privacy state and read the platform authorization status. Decide which SDK modules and fields are allowed. Keep this decision in one policy service rather than duplicating checks across screens.

typescript
type MeasurementMode =
    | "essential_only"
    | "first_party_analytics"
    | "ads_measurement";

type MeasurementPolicy = {
    mode: MeasurementMode;
    allowAdvertisingId: boolean;
    retentionDays: number;
};

The exact policy must come from your real data practices. A type definition does not establish permission by itself.

Phase 3: request permission in context

On iOS, add a clear NSUserTrackingUsageDescription and request ATT only when the person can understand the purpose. Do not block unrelated functionality or manipulate the prompt. On Android, provide disclosures and controls required for your data use and treat a deleted advertising ID as unavailable.

Phase 4: start permitted modules

Initialize analytics, attribution, ads, and personalization modules according to the resolved policy. Re-resolve on app foreground because settings can change outside the app.

Phase 5: handle revocation

When a user opts out or deletes an account:

  1. Stop prohibited future collection.
  2. Clear local identifiers and queued payloads covered by the request.
  3. Rotate the installation or diagnostic ID where appropriate.
  4. Send deletion or suppression requests to processors.
  5. Record a non-identifying audit outcome.

Do not keep a hidden mapping whose purpose is to reverse the reset.

Event flow separating deterministic attribution, aggregate reporting, and an explicit unattributed outcome

Design an auditable event contract

Every event should state what happened without smuggling identity into generic properties.

json
{
  "event_id": "evt_01J...",
  "event_name": "checkout_completed",
  "event_version": 3,
  "occurred_at": "2026-05-07T09:30:00Z",
  "platform": "ios",
  "app_version": "8.4.1",
  "installation_id": "ins_...",
  "account_id": "acct_...",
  "measurement_mode": "first_party_analytics",
  "attribution": {
    "source": "owned_email",
    "method": "signed_link",
    "confidence": 1.0
  },
  "properties": {
    "currency": "USD",
    "net_revenue": 24.0
  }
}

Omit fields the current policy does not allow. Do not send null, zeros, or a placeholder value that downstream systems might interpret as a real ID. Version event schemas and validate at ingestion.

Recommended attribution fields include:

This makes uncertainty queryable instead of hiding it inside one campaign column.

Implement deep-link attribution without overclaiming

Installed-app path

Use verified Universal Links and Android App Links. Sign sensitive campaign state or store it server-side behind an opaque token. Validate the destination and route only to an allowlisted screen.

This can deterministically prove that a particular link opened the app when the link and event carry the same signed interaction ID. It does not prove the link caused every later purchase.

Android install path

For eligible Google Play installs, the Play Install Referrer API returns referrer content and click/install timestamps. Read it once through the supported client, send the raw value over a protected connection, parse it server-side, and enforce idempotency. Treat missing, duplicate, delayed, and malformed responses as normal test cases.

iOS privacy-preserving attribution

Use Apple-supported privacy-preserving frameworks and App Store Connect analytics for aggregate campaign measurement where applicable. Do not build a substitute stable identifier from device characteristics. Apple states that developers may not derive device data for the purpose of uniquely identifying it.

Leave unsupported installs unattributed

Some attribution systems infer a click-to-install match from request and timing signals when no deterministic link or platform signal survives. That inference is not a device ID and not proof of identity. Deeplinkly does not use this method: an unsupported install remains unattributed.

On Apple platforms, do not use a different identifier or device fingerprint to bypass ATT. Review the exact SDK behavior and current platform terms before adding any attribution provider.

Store less and protect what remains

Identifiers are linkable data. Apply the same controls as other sensitive analytics data:

Tokenization can reduce casual exposure. Hashing alone does not make a stable identifier anonymous because the hash remains linkable and may be reproducible.

Reconcile without forcing equality

Ad networks, stores, product analytics, billing, and an MMP observe different events. Build a reconciliation table rather than rewriting one system to equal another.

SystemWhat it can establishTypical gap
Ad networkEligible impressions, clicks, and network-attributed outcomesSelf-attribution rules and reporting delays
App storeProduct-page views, downloads, source categories, aggregate campaign dataPrivacy thresholds and store-specific definitions
App telemetryOpens and in-app events received by your serviceOffline use, consent, SDK loss, and reinstall
BillingPurchases, renewals, refunds, and proceedsAccount/device mapping and settlement delay
Attribution providerMatches under its configured methods and windowsUnmatched and aggregate cases

Track deltas by day, platform, version, country, method, and authorization state. Investigate sudden changes; do not promise 100% attribution accuracy.

Test the lifecycle, not just the happy path

Create automated and manual test cases for:

iOS

Android

Backend

Monitor null rate, zero-ID rate, consent-state distribution, events by SDK version, match method, confidence distribution, referrer errors, duplicate rate, and deletion latency. Alert on changes by app version so a release regression is visible quickly.

Rollout plan

  1. Inventory: map SDKs, identifiers, destinations, retention, and owners.
  2. Minimize: remove fields and SDK modules without an approved purpose.
  3. Centralize policy: build one state resolver used by every collector.
  4. Version schemas: separate identity and attribution method explicitly.
  5. Shadow test: compare old and new pipelines without using new data for decisions.
  6. Canary release: start with a small app-version cohort and watch missing/duplicate rates.
  7. Reconcile: document expected differences between store, network, MMP, and billing.
  8. Delete-test: prove a request reaches internal stores, backups according to policy, and processors.
  9. Review: repeat after every SDK, platform, or data-use change.

Implementation checklist

A durable mobile measurement system is not the one that captures the most identifiers. It is the one that produces useful evidence while accurately representing scope, consent, reset behavior, and uncertainty.

Primary sources

Back to all articles© 2026 Deeplinkly

Related guides