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··20 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 two are exact and score 1.0. The third is an inference that starts at 0.85 within an hour of the tap and decays to 0.30 by the 24 hour ceiling, inside a per-link match window that defaults to 6 hours and can be raised no higher than 24. 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 honest design answer is a coarse hashed key that expires rather than a durable device fingerprint. iCloud Private Relay lowers that tier further, because Safari traffic is relayed and your app's HTTPS traffic is not. Paid campaigns bought through ad networks are the one case this does not cover, and that is what SKAdNetwork and AdAttributionKit exist for, Apple's postback frameworks for paid acquisition, which credit a campaign rather than one of your links.

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. Two questions get called "attribution" and only one of them changed in 2021:

  • Which of my links produced this install? The tap is on your URL, the redirect is yours, the install reports to you. Nothing here ever needed a cross-company identifier.
  • Which ad network campaign produced this install? The tap happened inside another company's app, on a click URL you never see, and the reconciliation depends on a shared identifier or an Apple-mediated postback. This is the one ATT reshaped.

The first 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, which for a small team is most of what there is. The rest of this post is how that answer is constructed, how sure you get to be, and exactly where the boundary with the second question sits.

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, the match is deterministic and scores 1.0.

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. It cannot resolve a genuine first install, because there is no prior record to compare against. 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 phone behind one shared address that also shares a language and a timezone lands in the same bucket. The key names a network, and the confidence scores exist to say so out loud.

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 to be weak rather than strong: three low-entropy components, stored only as a one-way hash, expiring with the match window, and coarse enough that it routinely collects several unrelated people, which is why an ambiguous bucket cuts the score by 40 percent rather than reporting the pick as certain. 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.

None of that is a legal conclusion, and this post is not the place to offer one. 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. What your app collects, what your App Privacy answers say, and what your own privacy manifest declares remain yours to get right, and if the stakes justify it, your counsel's to review.

Putting a Number on an Inference

An honest probabilistic system publishes its uncertainty. Two fields carry it, and they are not interchangeable.

matchGuaranteed is a boolean and it is true only for a deterministic match, which on iOS means the IDFV. matchConfidence 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 honestly: 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 24 hours is the hard ceiling. Past the window there is no match at all, which also means the bottom row of the table only applies to a link deliberately configured past the 6 hour default. The low ceiling is a design choice: the key names a network, so every extra hour lets another stranger into the bucket while adding almost no genuine matches, because 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, and the four reasons an install comes back with no match at all, are documented in the install attribution concept page.

iCloud Private Relay Moves the Address Under You

iCloud Private Relay is an iCloud+ feature that hides a user's address by routing traffic through two separate relays, so no single party sees both who the user is and what they are visiting. It is one common reason a well-implemented probabilistic match comes back weaker than the table above suggests, and the mechanism is worth understanding rather than guessing at.

Apple states the coverage precisely: "Private Relay protects users' web browsing in Safari, DNS resolution queries, and insecure http app traffic" (Prepare Your Network for iCloud Private Relay, Apple).

Read that against the two halves of the join. When the tap opens in Safari it is relayed, and the click is recorded against a relay exit address. The install reports from inside your app over HTTPS, which is not in that list, so it arrives from the device's ordinary address. For a Private Relay user the two addresses differ structurally rather than accidentally, and a key built on the address therefore misses or scores low.

Two practical notes follow. First, a relay exit address is an ordinary public routable address, not carrier-grade shared space, so it takes the mild address multiplier rather than the heavy one. The system does not double-penalize these users, it simply cannot find them as often. Second, this affects a slice of your audience rather than all of it, since Private Relay requires an iCloud+ subscription and is not offered in every country or region.

The wrong response to all of this is to reach back for the advertising identifier. It would not help. Even with a granted ATT prompt and a fully populated IDFA inside your app, the click side of the join is a browser, and a browser has no IDFA to record. The deterministic tiers, the IDFV on iOS and the store referrer on Android, are untouched by Private Relay, so the practical mitigation is to make sure those tiers get their chance rather than to trade privacy for a signal that was never there.

What to Route On When the Answer Is a Guess

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 if the guess named the wrong person: automatic sign-in, restoring a session, showing an order or a balance, prefilling a name or an address, applying a credit to an account. All of it belongs behind matchGuaranteed. A high score does not make a probabilistic answer safe for those, because a high score only says the bucket was small and the gap was short.

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. Being wrong there costs a slightly odd first 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 you are 30 percent sure about.

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.

Where SKAdNetwork and AdAttributionKit Fit

There is one category of install none of this reaches, and being clear about it beats pretending otherwise.

If you buy installs, the tap happens inside another company's app on a click URL you never see. Apple's answer for that case is SKAdNetwork, a framework in which a registered ad network receives a signed postback per install attributing it to a campaign, delivered days after the install on a randomized delay, with fields such as the conversion value and the publisher app identifier withheld unless Apple's crowd anonymity thresholds are met. AdAttributionKit is the newer framework in the same family, introduced in 2024 and interoperable with SKAdNetwork, adding re-engagement conversions and support for alternative app marketplaces.

Running that pipeline properly is a real engineering commitment: conversion value schemas, postback decoding, per-network integrations that change without warning, and joining spend from each network to installs and revenue. That work is what an enterprise mobile measurement partner (MMP) exists to do: the service category built around ad network integrations, postback pipelines, cost and revenue joins, and fraud detection. It is worth paying for once you are spending meaningfully on paid acquisition. Install Attribution Without an MMP covers that boundary in detail, including the four capabilities link-based attribution genuinely does not replace.

The split is clean enough to decide from. A tap on a URL you own is yours to attribute, exactly, with no advertising identifier and no prompt. A tap inside somebody else's ad is reported through Apple's pipeline, on Apple's terms. Most teams need the first long before they need the second, and buying the second does not give you the first, because a measurement suite is not where you want your product's deep linking to live.

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 the deterministic signal is the identifier for vendor, scoped to your own apps and readable without the tracking prompt, and whatever it cannot answer falls to a short-lived probabilistic key the server computes from the request address, the device language, and the timezone. 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.

Does device fingerprinting for attribution break Apple's rules? 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 coarse, hashed key that identifies a network rather than a device and expires within hours. The trade is visible in the numbers: three low-entropy components and a window measured in hours are exactly why a probabilistic match is scored as a guess instead of reported as a fact. Read the policy and decide what your own app collects and declares, because that judgement is yours to make rather than a vendor's to make for you.

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. What the prompt genuinely costs is device-level measurement of paid ad campaigns, which is the gap SKAdNetwork and AdAttributionKit were built to fill.

Does SKAdNetwork replace link-based install attribution? No, the two answer different questions. SKAdNetwork is Apple's privacy-preserving pipeline for paid campaigns, where a registered ad network receives a signed postback per install, delivered days after the install on a randomized delay, with the identifying fields withheld unless crowd anonymity thresholds are met, and AdAttributionKit builds on the same foundations. It can tell an ad network which campaign produced an install. It cannot tell you that the link in your newsletter, the code printed on your poster, or the invite one user sent another produced this specific install, which is the question link-based attribution exists to answer.

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. What does shift is the share of your users on iCloud Private Relay, which weakens that tier for the population that has it switched on.

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.

WarpLink Team

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

Related Posts