attribution

Install Attribution Without IDFA: How iOS Deep Links Match Now

Install attribution without IDFA on iOS: what ATT changed, the signals that remain, what Apple's rules say, how confidence and match windows work.

WarpLink Team··16 min read

TL;DR: Install attribution without the IDFA works because the IDFA was never how link-driven installs were attributed. App Tracking Transparency gates the advertising identifier, and a browser never had one to give, so the tap that started the install could not have carried an IDFA even with full consent. Three signals remain on iOS 15 and later: a Universal Link delivered straight into an app that is already installed, the identifier for vendor when the same install asks again, and a probabilistic key the server computes from the request address, the device language, and the IANA timezone. The first is exact. The second returns the install the device already has, with its original score. The third is an inference that starts at 0.85 within an hour of the tap and decays to 0.30 by 24 hours, inside a per-link match window that defaults to 6 hours and is set per link, up to 24 hours. Apple's rules are two separate rules, one about joining your data with other companies' data for advertising and one about deriving a unique device identifier, and the design answer for the probabilistic tier is a coarse hashed key that is matchable only within a short window rather than a durable device identifier, while the IDFV is used only to recognize an install the device already has, as described below.

Attribution Without IDFA: What ATT Took Away, and What It Never Touched

The IDFA, or Identifier for Advertisers, is a single value per device that any company's app could once read. That is the whole point of it: because two unrelated apps saw the same string, an ad network could join a tap inside one of them to an install in the other.

App Tracking Transparency, the iOS permission framework usually shortened to ATT, ended the default availability of that join. Apple's own wording is unambiguous: "In iOS 14.5, iPadOS 14.5, and tvOS 14.5 or later, you need to receive the user's permission through the AppTrackingTransparency (ATT) framework in order to track them or access their device's advertising identifier," and "Unless you receive permission from the user to enable tracking, the device's advertising identifier value will be all zeros and you may not track them as described above" (User Privacy and Data Use, Apple).

Five years later, the industry summary of that change has hardened into a slogan: attribution is broken on iOS. That summary is wrong about a large category of installs, and the reason is structural rather than optimistic.

Think about what actually happens when someone taps a link you own. They are in a browser, on a URL resolving against a server you control, and they do not have your app. A browser has no advertising identifier. It never did. There is no IDFA on the click side of that join, and there never was one to lose, so no amount of tracking consent would have improved the answer. The IDFA solved the case where the tap happened inside somebody else's app and you needed a shared name for the device to reconcile the two sides. Your own link is the opposite case: you already own both sides.

That distinction is the whole subject of this post. The question a link answers is which of your links produced this install. The tap is on your URL, the redirect is yours, and the install reports to you. Nothing here ever needed a cross-company identifier.

That question is answerable today with signals Apple explicitly permits, no prompt, and no advertising identifier. It covers organic, referral, creator, community, email, support, and printed traffic. The rest of this post is how that answer is constructed and how sure you get to be.

The Three Signals iOS Still Gives You

Strip the vocabulary away and attribution is a join between two events: a click at 14:02 and a first launch at 14:09. On iOS there are exactly three ways to make that join, and they are not equally good.

The tap itself, when the app is already installed

The strongest case is the one nobody counts as attribution. When a user already has your app and taps a Universal Link, iOS hands the URL to the app directly. Nothing was lost, so nothing has to be reconstructed. The link identifier, the campaign values, and the destination arrive intact in the same payload that routes the user.

This is the re-engagement half of the picture, and it is worth naming because it is exact by construction. A newsletter link that reopens the app for an existing user is attributed with the same certainty as a click on your website. No identifier is involved at all.

The IDFV, when the same install asks again

The Identifier for Vendor, read from UIDevice.current.identifierForVendor, is a UUID shared by every app from one vendor on one device. Reading it needs no permission, and it is exempt from ATT because it cannot follow a user into another company's apps. When it answers, it returns the install the device already has, with that install's own match type and score, so it never turns a probabilistic match into a guaranteed one.

What it answers is narrower than the name suggests. It resolves the same install asking again, where an earlier attribution record for that device already exists, which happens after a cached answer is lost or after an upgrade from an older SDK. A reinstall the SDK reports as one is deliberately left to the tier below, so that install is recorded as the new install it is. Apple also resets the IDFV when the last app from a vendor is deleted, so a single-app vendor usually sees a fresh value after a full delete regardless.

A probabilistic key, for a genuine first install

Everything the first two cannot reach falls to an inference. Three signals are compared, and only three: the address of the request, derived on the server at both ends; the device's preferred language, normalized to its primary subtag; and the timezone, as an IANA zone name where the SDK can resolve one and a minute offset otherwise.

The list is short on purpose, and what is missing matters more than what is present. User-Agent strings and screen dimensions are not collected, because they never match reliably across the boundary from a browser to a native app. The address is never sent by the app at all: an app cannot see the public address its own packets exit from, so the SDK sends raw signals and the server computes the key from the address it observes on each request.

Read that construction carefully, because it is the answer to the policy question in the next section. Three coarse components are not a device identifier, and the design does not try to make them one. Every first-install match carries a confidence score, so you can route on how sure the match is.

If you want the same four methods in one ordered list, covering Android as well as iOS, How to Attribute Installs Without a Click ID sets out each one with its accuracy limits. The install attribution page is the one-screen version.

What Apple's Rules Actually Say About This

Two separate Apple rules apply here, and conflating them produces most of the confusion in this area.

The first defines tracking. Apple's wording is precise: "Tracking refers to the act of linking user or device data collected from your app with user or device data collected from other companies' apps, websites, or offline properties for targeted advertising or advertising measurement purposes. Tracking also refers to sharing user or device data with data brokers" (User Privacy and Data Use, Apple). It is a rule about who you join data with and why, and it is what the ATT prompt gates.

The second is separate and applies whatever the user answered. On the same page, under the question of whether you may fingerprint a device, Apple writes: "Per the Apple Developer Program License Agreement, you may not derive data from a device for the purpose of uniquely identifying it." The examples given include "properties of a user's web browser and its configuration, the user's device and its configuration, the user's location, or the user's network connection," and the page adds that apps engaging in the practice, or referencing SDKs that do, "may be rejected from the App Store."

That second rule is the one an engineer should read closely before shipping any probabilistic matching, whoever built it. It is about deriving a unique identity for a device out of its properties. So the design question is not whether you compare signals at all, it is whether what you compare is capable of naming a device.

Here is where WarpLink stands, stated plainly. WarpLink matches a user's own tap on your own link to that same user's install of your own app. It does not join your data with another company's data, it does not share data with data brokers, and it does not do cross-app ad tracking. The advertising identifier is never read, on iOS or on Android. The probabilistic key is built for privacy. It has three coarse components and is hashed one way. Each tap is matchable only within the app's match window, and pending entries expire automatically. The raw IP address is not stored. An ambiguous bucket cuts the score by 40 percent. The iOS SDK's privacy manifest declares NSPrivacyTracking as false, lists the IDFV as a device identifier collected for app functionality, and marks it as neither linked to a user nor used for tracking.

The mechanism is described above so you can weigh it against the policy text yourself, which is why the quotes link to Apple's page rather than a summary.

Putting a Number on an Inference

The score states the match quality. Two fields carry it, and they are not interchangeable.

matchGuaranteed is a boolean and it is true only for a deterministic match: a tapped link the SDK resolved directly, or a Play Install Referrer match on Android. On iOS, matchConfidence carries the score for every install. It is a score from 0.0 to 1.0 that only means something once matchGuaranteed is false. A deterministic match always returns 1.0. An inference returns a band set by how long ago the tap happened and how much the SDK could send:

Gap between tap and first launchBest case scoreWeakest variant
Under 1 hour0.850.70
Under 3 hours0.650.50
Under 6 hours0.500.35
Under 24 hours0.300.20

The best case is the enriched_tz variant, which hashes the IANA zone name and is what current SDKs send. The weakest is basic, which drops the timezone entirely. The middle variant, enriched, hashes the minute offset instead of the zone name and sits between the two columns. The zone name earns its higher ceiling: roughly 340 zones against 38 offsets is far more entropy, and a zone name does not shift at a daylight-saving boundary, which used to break an otherwise good pair outright.

The window is the other half. It is set per link on the server rather than in the SDK, it defaults to 6 hours, and it is set per link, up to 24 hours. Installs that convert overwhelmingly convert soon after the tap.

Two further multipliers only ever reduce a score, never raise it, one for a bucket that held more than one distinct link and one for how shared the click address was. Their exact values are documented in the install attribution concept page.

The advertising identifier is not needed here: the click side of the join is a browser, and a browser has no IDFA to record, even with a granted ATT prompt and a fully populated IDFA inside your app. Two paths need no inference at all: a Universal Link that opens an installed app, which carries the link itself, and the store referrer on Android.

What to Route On: Reading the Match Result

Reporting an install and routing a user are two different decisions, and the second one deserves the stricter rule. Report on everything. Route on the field that tells you whether the answer is exact.

Sensitive means anything that would be a privacy incident: automatic sign-in, restoring a session, showing an order or a balance, prefilling a name or an address, applying a credit to an account. None of it belongs behind a match result alone, guaranteed or not. matchGuaranteed rules out routing a probabilistic guess anywhere near that territory, but authenticating the user and checking authorization is a separate step that still has to happen.

Not sensitive means anything a stranger could have reached on their own: a product page, a shared post, a public profile, a campaign-specific welcome screen. Above 0.5 route straight to it, and below that a welcome screen naming the content, so the user can opt in, beats a hard redirect on a low-confidence score.

Reporting is looser and can happen wherever it suits your analytics. The result is cached for the install, so a screen that runs later can read it without a second network call:

isDeferred is what separates the two cases in your reporting. True means the link was reconstructed after an install, which is the new-user story. False means the link was delivered to an app that was already there, which is the re-engagement story. Counting them as one number hides the difference that matters most about a campaign.

Notice what is absent from both samples. There is no ATTrackingManager call, no permission request, and no advertising identifier, and adding them would change nothing about the result.

Frequently Asked Questions

Can you do install attribution without the IDFA? Yes, and for installs that came from your own links the IDFA was never the mechanism. The advertising identifier exists to join a tap inside one company's app to an install in another company's app, which is not the shape of a link-driven install. On iOS a first install is matched by a probabilistic key the server computes from the request address, the device language, and the timezone, and the identifier for vendor, scoped to your own apps and readable without the tracking prompt, recognizes the same install when it asks again. A browser cannot read an IDFA in any case, so full tracking consent would add nothing on the click side of the join.

What is the difference between the IDFA and the IDFV on iOS? The IDFA is the Identifier for Advertisers, one value per device that every company's apps can read, which is why reading it needs permission through App Tracking Transparency and why it returns all zeros without that permission. The IDFV is the Identifier for Vendor, a separate UUID scoped to the apps of a single vendor, so it cannot be joined against another company's data. Apple treats it as exempt from the tracking prompt, and iOS resets it when the last app from that vendor leaves the device. Link-based attribution reads the second and never touches the first.

How does WarpLink handle attribution privacy on iOS? We use a keyed hash of the request IP address and primary language, with time zone in enriched matches, to find a recent tap. Apple's position is specific and worth reading in the original: per the Apple Developer Program License Agreement you may not derive data from a device for the purpose of uniquely identifying it, and apps that reference attribution SDKs doing so may be rejected. That rule is about building a durable unique identifier out of device properties, which is a different construction from a keyed hash of the request IP address and primary language that is matchable only within a window of hours. A few coarse components and a window measured in hours limit how long the key can be used, and every probabilistic match carries a confidence score.

How much attribution do I lose when a user denies tracking? None of the link-based kind. The App Tracking Transparency answer gates the advertising identifier and cross-company data joins, and neither appears anywhere in the match cascade, so a user who taps "Ask App Not to Track" is matched exactly like a user who allows tracking.

Which iOS versions does this work on? Everything described here holds on iOS 15 and later, which is the floor our SDK supports. The identifier for vendor is a long-standing UIKit property and is not gated by App Tracking Transparency, which has applied since iOS 14.5. The probabilistic tier runs on the server and keys on the request rather than on an OS API, so it does not shift between releases.

Two halves of this cannot live inside your app: the click recorder that captures the request signals before the App Store takes over, and the endpoint that derives the address from each request, computes the key on both sides, and walks the cascade. That is WarpLink's job as link infrastructure. In Swift it collapses to a configure call and a result carrying linkId, matchType, matchConfidence, matchGuaranteed, isDeferred, and the original link's deep link URL, with no ATT prompt and no advertising identifier anywhere in the flow.

One match, three pillars. Deep linking puts the new user on the screen the link promised, install attribution names the link and campaign that sent them, and real-time analytics turns a week of that into a channel report while the campaign is still running.

Create a free WarpLink account and get deep linking, install attribution, and real-time analytics in one SDK, with 10,000 clicks a month on the free plan and no time limit. The install attribution concept page is the reference behind every number above.

See which link drove each install

Deep linking, install attribution, and real-time analytics in one SDK. Free for 10K clicks a month, no sales call.

Stuck on setup? Email support@warplink.app and we will help you get one real link working.

WarpLink Team

Building affordable, reliable link infrastructure for mobile teams. Deep linking, install attribution, and real-time analytics in one SDK.

Related Posts