This post first ran in July 2026 as a pure AdServices walkthrough. Two things have made that framing incomplete. Apple renamed Apple Search Ads to Apple Ads on April 14, 2025 (9to5Mac), and it keeps adding fields to the attribution payload. And RevenueCat shipped keyword and claim-type segmentation in Charts on March 27, 2025 (changelog), which answers "which keyword brings revenue" for many indie apps without any code of your own. So this version starts with what changed, then what RevenueCat covers, then the pipeline for everything it doesn't.
What changed since 2025
Most of these come from Apple's own AdServices changelog.
| When | Change | What it means for you |
|---|---|---|
| Nov 2024 | claimType field added, value Click | Each attributed payload says how the claim was made. |
| Mar 27, 2025 | View-through attribution: claimType: Impression and an impressionDate field | Some attributed installs never tapped your ad. Count them apart from taps. |
| Mar 27, 2025 | RevenueCat Charts filter and segment by Apple Ads keyword and claim type | Keyword revenue with no code, if you're on RevenueCat. |
| Apr 14, 2025 | Apple Search Ads renamed Apple Ads | Same framework, same endpoint. |
| Oct 2025 | Pre-order attribution, conversionType: PreOrder | Only relevant if you run pre-order campaigns. |
| Jan 2026 | supplyPlacement field | You can tell search results, Search tab, Today tab and product page ads apart per install. |
| Sep 2026 | Campaigns using age or gender targeting return attribution: false | Those installs look unattributed. Drop the targeting if you need the data. |
| Jan 26, 2027 (announced) | Apple will sunset the Campaign Management API; the Apple Ads Platform API replaces it (Apple Ads API docs) | Scripts that map IDs to names through the old API need moving before then. |
When RevenueCat's Apple Ads view is enough
If you use RevenueCat and your question is "which keywords bring revenue", start there. Turn on token collection in the SDK:
Purchases.shared.attribution
.enableAdServicesAttributionTokenCollection()
RevenueCat then requests the attribution record from Apple and stores campaign, ad group, keyword and claim type on the customer (RevenueCat's Apple Ads docs). Charts can then be filtered and segmented by those fields, including click-through versus view-through. The docs say to allow up to seven days for attribution data to arrive, and names instead of numeric IDs need the Apple Ads Advanced connection through Sign in with Apple.
For one app and a revenue question, that's a good answer and it costs nothing extra. Three questions stay open:
- What those users did in the app. RevenueCat sees purchases. It doesn't see whether a keyword's users finished onboarding, which features they used, or whether they came back in week two. For the first weeks after install, before trials convert, behavior is the only early signal you have.
- What it cost. RevenueCat's Apple Ads documentation describes no spend import, so cost per subscriber still means pulling spend from Apple Ads and dividing by hand.
- More than one app. Charts are scoped to a RevenueCat project. If each of your apps is its own project, comparing a keyword's results across apps means switching projects and copying numbers.
Those need the raw attribution on your own user record, next to events and purchases. The rest of this post is that pipeline.
Step 1: get the token
Import AdServices (iOS 14.3 and later) and call
AAAttribution.attributionToken(). Three properties matter:
- The token lives for 24 hours (Apple's reference). You don't have to resolve attribution in the first session. Keep the token and finish the job on a later launch.
- Expect it to throw in the simulator. Catch the error and test the real path on a device.
- The call is synchronous. Generate the token off the main thread so the user's first launch doesn't stutter.
Do this once per install and record that you did. Attribution is a fact about the install, not the session, so resolving it again every launch is wasted work and a source of conflicting data.
Step 2: POST it to Apple
Send the raw token as the body of a POST, as plain text:
POST https://api-adservices.apple.com/api/v1/
Content-Type: text/plain
<the token string>
Apple documents four responses:
- 200: a JSON payload.
attribution: truewith the IDs described below, orattribution: falsewhen Apple finds no matching ad interaction. - 404: the record isn't ready yet, or the token is past its 24 hours. Apple's guidance is to retry at 5-second intervals, at most three times. Since May 2024 Apple holds the connection for up to a second before answering 404, so don't set a client timeout below one second.
- 400: the token is invalid. Generate a new one instead of retrying.
- 500: Apple's server is down. Retry later.
You can make the call from the device or send the token to your backend and resolve it there. The device is simpler and fine for most indie apps. A backend call survives the app being killed mid-retry and lets you change the logic without an App Review round. Either way, if all three attempts return 404, keep the token and try once more on the next launch inside the 24 hours.
Step 3: read the payload
Field names and notes below are from Apple's attribution payload reference.
| Field | What it is | Watch out for |
|---|---|---|
attribution | true or false | false means "not Apple Ads", not "organic" |
orgId | Your Apple Ads account | |
campaignId | The campaign | |
adGroupId | The ad group | |
keywordId | The keyword | Not returned when search match is on |
adId | The ad | Devices on iOS 15.2 and later |
claimType | Click or Impression | A tap within 30 days beats a view within 24 hours |
clickDate / impressionDate | When the tap or view happened | Only for users who allowed tracking |
conversionType | Download, Redownload or PreOrder | Redownloads are returning users |
countryOrRegion | The campaign's country or region | |
supplyPlacement | Where the ad ran | Added January 2026 |
On consent: Apple's current reference no longer spells out the split, but RevenueCat and Adjust document it the same way. Users who didn't allow tracking get a "standard" payload without the tap or view timestamp; users who did get a "detailed" one with it. Everything you need for keyword decisions arrives in both.
Read attribution: false precisely. It means Apple found no
Apple Ads interaction for this install. The user may have come from a
Meta campaign, a Reddit thread or a friend. Store it as "not Apple Ads"
rather than "organic", and rather than leaving a null you'll misread in
three months.
Two fields change how you count. conversionType: Redownload
is someone coming back, so if you compute cost per new
subscriber, count redownloads separately or your best "keyword" may turn
out to be your own churned users returning. And
claimType: Impression marks installs where the person saw
the ad in the last 24 hours but never tapped it. Keep view-through
installs in their own column until you've seen whether those users
behave like tap-through users.
AdServices is the deterministic half of iOS attribution. The aggregate half (AdAttributionKit and SKAdNetwork, for every other network) is in do you need an MMP as an indie iOS developer.
Step 4: turn IDs into names
The payload carries numeric IDs only. Three ways to name them:
- The Apple Ads API. Apple's reference points each ID at a report (campaigns, ad groups, keywords). The Apple Ads Platform API supersedes the Campaign Management API, which Apple says will be sunset on January 26, 2027, so write new code against the Platform API.
- A lookup table you keep by hand. With a handful of campaigns and a few dozen keywords, a text file you update when you edit campaigns covers it. The IDs don't change once created.
- RevenueCat, if you connected Apple Ads Advanced, shows names in Charts.
Store the raw IDs on the user record and resolve names when you display them. Renaming a campaign shouldn't rewrite history.
Step 5: join it to behavior and revenue
Campaign and keyword IDs on a user record become useful next to what that user did and paid. That needs behavior and purchases on the same record, which is the one-ID pattern: one user ID shared by your analytics and RevenueCat, with the attribution fields stored on it. With that join in place you can ask what RevenueCat Charts can't answer:
- Onboarding completion and week-two return per keyword, readable days before any trial converts.
- Trial rate and revenue per keyword, split by tap-through and view-through.
- The same keyword across several apps, side by side.
The number worth building toward is cost per subscriber, not cost per install. Spend per campaign and keyword comes from Apple Ads reports; your joined data supplies subscribers per the same IDs. Divide monthly, not weekly: on a few hundred euros of spend, weekly cost per subscriber swings on two or three people, and a keyword needs a few dozen attributed installs before its conversion rate says much. A keyword with expensive taps can still be your cheapest per subscriber if its users convert better, and the Apple Ads console alone can't show you that.
Gotchas
- One resolution per install, persisted. Not per launch.
- Search match hides the keyword. Apple doesn't
return
keywordIdwhen search match is enabled. Keep search-match discovery in its own ad group so your other installs keep their keyword IDs. - Age and gender targeting now kills attribution.
Since September 2026 those campaigns return
attribution: false. - Paused campaigns keep attributing. A tap counts for 30 days and a view for 24 hours, so installs keep arriving after you pause. Don't unpause in a panic.
- Developer mode returns test data. Apple's
reference shows a sample payload with placeholder IDs like
1234567890; if you see those in production data, check that the device isn't in developer mode. - TestFlight and simulator installs don't attribute. Fail quietly and flag those devices as internal. At indie volume, a handful of test devices can bend every number.
- Log failures distinctly. "Not Apple Ads", "token failed" and "gave up after retries" are three different facts. One bucket for all three hides integration bugs.
FAQ
Is Apple Ads the same as Apple Search Ads?
Yes. Apple renamed it on April 14, 2025. The AdServices framework, the endpoint and the payload fields carried over; Apple's developer documentation now uses the new name.
Does Apple Ads attribution need the ATT prompt?
No. Campaign, ad group, keyword, claim type, conversion type and country arrive without tracking consent. Only the tap or view timestamp is reserved for users who allowed tracking.
Is RevenueCat's Apple Ads integration enough?
For keyword-level revenue in one app, usually yes. It doesn't show what those users did inside the app, its Apple Ads documentation describes no spend import, and each RevenueCat project is charted on its own.
Why do I get 404s for a valid token?
The record isn't ready yet, or the token is older than 24 hours. Retry at 5-second intervals up to three times as Apple recommends, then once more on a later launch inside the 24 hours.
Why is keywordId missing?
Search match is on for that ad group. Apple doesn't return keyword IDs for search-match installs.
Can AdServices attribute Meta or TikTok installs?
No. AdServices covers Apple Ads only. Other networks measure through AdAttributionKit or SKAdNetwork, which send aggregate postbacks with no user attached.
Sources
- Apple, attributionToken() and attribution payload reference and AdServices changelog
- Apple, Ad attribution on the App Store (30-day tap and 24-hour view windows)
- Apple, Apple Ads API documentation (Platform API, Campaign Management API sunset)
- RevenueCat, Charts: keyword and claim type and Apple Ads integration docs
- 9to5Mac, Apple rebrands Search Ads as Apple Ads (April 14, 2025)
- Adjust, How Apple Ads attribution works (standard and detailed responses)