Apple Search Ads is one of the few paid channels that actually works for indie app developers. You're showing up right at the moment someone searches for an app like yours โ intent doesn't get much higher than that.
But there's a gap. Apple Search Ads tells you taps, installs, and cost. It doesn't tell you which keywords led to purchases. If you're running five keyword groups and one of them is quietly driving 80% of your revenue, Apple won't tell you. They'll just show you aggregate install numbers.
For developers running small budgets โ and when you're bootstrapped, every pound counts โ knowing which keywords convert to paying customers changes everything.
What Apple Search Ads Tells You (And What It Doesn't)
The Apple Search Ads dashboard gives you solid data on the top of the funnel:
- Impressions, taps, and tap-through rate per keyword
- Cost per tap and cost per install
- Install volume by keyword, match type, and ad group
What it doesn't give you is purchase data. Once a user is in your app, Apple stops tracking. Whether they went on to buy your premium tier, subscribe to your annual plan, or bounce after 30 seconds โ none of that flows back into the Search Ads dashboard.
Apple does offer a framework called AdServices that can attribute an install back to a Search Ads keyword. But it only tells you the install happened and which keyword group triggered it. It doesn't connect that install to a specific RevenueCat purchase event unless you build that connection yourself.
For most indie developers, that integration never gets built. So you end up optimising for taps and installs, hoping that better install numbers eventually mean better revenue.
Why Install Data Isn't Enough
Installs are a leading indicator, not the outcome you care about. The problem is that different keywords attract very different users.
Someone searching for "kids brushing teeth app" might install your app out of curiosity and never pay. Someone searching for "best toothbrush timer for toddlers" is probably a parent actively looking for a solution and much more likely to convert.
Both look identical in your Search Ads dashboard if their install cost is similar. But one is worth twenty times more than the other.
If you're bidding the same on both because you have no purchase data, you're almost certainly leaving money on the table โ or burning budget on clicks that will never convert.
How to Connect Search Ads to Purchases
The approach is straightforward in principle: tag the install with the keyword source, then surface that tag when a purchase fires.
Here's how it works in practice:
Step 1: Read the AdServices token at app launch. Apple's AdServices framework provides an attribution token that you can exchange for keyword-level install data. You call the framework shortly after install, get a token, and send it to Apple's attribution API to get the details back. This tells you the campaign, ad group, keyword, and match type that drove the install.
Step 2: Store the attribution data locally. Save the keyword and campaign details in your app (UserDefaults or equivalent). This persists through the session.
Step 3: Pass it to RevenueCat as metadata. When a purchase happens, RevenueCat lets you attach custom attributes to the subscriber. Pass the keyword, campaign, and ad group as attributes at purchase time.
Step 4: Query it. You can now see, per subscriber, which Search Ads keyword they came from. If you're using a webhook-based attribution tool, you can surface this in a dashboard without digging through RevenueCat manually.
This takes a few hours to build if you're doing it from scratch in Swift. If you're using a cross-platform stack like Expo or React Native, the AdServices framework isn't directly accessible without a native module โ which is a real headache for managed Expo projects.
The Cheaper Shortcut: Campaign-Level Tracked Links
If the full AdServices implementation feels like too much right now, there's a simpler option that gets you 80% of the value.
Create a unique tracked link per Search Ads campaign (or ad group). Use that link as your App Store link in each campaign. When a purchase fires through your attribution tool, you can see which campaign drove it โ even if you lose keyword-level detail.
It's not perfect. You can't distinguish between two keywords in the same ad group. But it does tell you whether your "competitor keyword" campaign outperforms your "category keyword" campaign in terms of actual revenue, not just installs.
This approach works with any attribution tool that accepts a tracked link. The user clicks your ad, lands on the App Store via your tracked link, installs, and when they buy, the attribution fires back to that campaign.
What This Looks Like in Practice
Say you're running three Search Ads campaigns:
- Brand keywords โ people searching for your app by name
- Category keywords โ "toothbrush timer app", "kids dental routine"
- Competitor keywords โ names of rival apps
You create a tracked link for each campaign. After four weeks of data, you might find:
- Brand: 3 purchases, ยฃ0.80 average cost per purchase
- Category: 12 purchases, ยฃ1.40 cost per purchase
- Competitor: 1 purchase, ยฃ6.20 cost per purchase
Without purchase attribution, competitor keywords might look cost-efficient by install rate. With it, you can see they're burning budget. You cut them, shift the spend to category, and your revenue per pound spent goes up.
That's a decision you literally cannot make without purchase-level attribution.
Tools Worth Knowing
Apple AdServices (free, built-in). The native framework for keyword-level attribution. Requires native Swift code. Best for apps with full Xcode control. Gives you the most granular data.
Campaign-level tracked links. Simpler. Works with any attribution tool. No native code required. Loses keyword-level detail but still gives you campaign-level purchase data.
LinkOwl. Works well for the tracked-link approach โ create a link per campaign, connect RevenueCat, and purchases are automatically attributed to the right campaign. 5p per attributed purchase, nothing when attribution doesn't fire. Takes about 10 minutes to set up.
MMP integrations (AppsFlyer, Adjust, Branch). These have full AdServices integration built in. They also cost hundreds a month and are designed for teams running tens of thousands in monthly ad spend. If you're spending ยฃ50/month on Search Ads, the maths don't work.
Start Simple, Then Get Granular
If you're not tracking Search Ads purchases at all right now, start with campaign-level tracked links. It's one afternoon of work, and it immediately tells you whether Search Ads as a channel is actually profitable โ before you go deep on keyword-level attribution.
Once you've validated that Search Ads is worth investing in, then build the AdServices integration for keyword-level data. By then you'll have enough volume to actually use it.
Running Search Ads without purchase attribution is like bidding at auction with your eyes closed. You might win, but you don't know what you're paying for. The fix is simple, and the decision-making it unlocks is well worth the setup time.
Track which Search Ads campaigns drive actual purchases with LinkOwl โ 5p per attributed sale, no monthly fee.