Attribution
AppRefer tells you which ad, campaign and network brought each install, and uses that to report trials and revenue back to the network.
Coming from a general mobile measurement partner? See how AppRefer compares with AppsFlyer, including what AppRefer doesn't do (deep linking, fraud protection).
How it works
Call configure() when the app starts. On the first launch the SDK sends one request with the install's signals; AppRefer matches it to the ad click that drove it and returns the result. Later launches return the cached result without waiting on the network.
import AppRefer
let attribution = await AppRefer.configure(apiKey: "pk_live_...")
print(attribution?.network ?? "unknown")If you need to tell an organic install from a failed request, use configureResult() (SDK 0.9.0+). It returns one of attributed (with the attribution), pending (the install is waiting for the user's tracking answer, see below), organic or failed. An Apple Ads match counts as attributed even while the tracking answer is pending.
What you get back
| Field | Description |
|---|---|
network | Where the install came from: meta, google, tiktok, openai, apple_ads, organic, or a source from your link or utm_source (for example email) |
matchType | How the match was made (see the table below) |
campaignId | Campaign ID from the click or Apple Ads |
campaignName | Campaign name |
adGroupId | Ad set or ad group ID |
adId | Ad ID |
keyword | Search keyword (Apple Ads, Google) |
fbclid, gclid, ttclid | The click ID, when the install matched a click from that network |
queryParams | Query parameters recorded on the click |
customData | Custom data set on the tracking link |
attributionId | AppRefer's ID for this install's attribution |
trackingDecisionPending | True while the install waits for the user's tracking answer |
createdAt | When the install was attributed |
Matching order
AppRefer tries each method in turn and stops at the first match. The deterministic methods come first; probabilistic matching is the last resort before organic.
| Order | Method | matchType | Notes |
|---|---|---|---|
| 1 | Apple AdServices | adservices | Apple Ads on iOS. Apple runs it without tracking permission, so it works for every install. |
| 2 | Play Install Referrer click ID | install_referrer | Android. The tracking link passes its click ID through Google Play to the install. |
| 3 | Play Install Referrer gclid | install_referrer_gclid | Android Google App campaigns that send people straight to Google Play, skipping the AppRefer page. The gclid is kept so purchases still reach Google Ads. |
| 4 | Play Install Referrer UTM | install_referrer_utm | Android, when the referrer has UTM values but no click ID. |
| 5 | Exact IP match | ip_match | One click from the same IP address in the last 24 hours, and only one. |
| 6 | Probabilistic | probabilistic | Scores clicks from the last 24 hours on several signals (IP, network prefix, OS, device). Accepted only when the best click scores high enough and clearly beats the next one. |
| 7 | Organic | organic | No match. |
Methods 2 to 6 need tracking permission (see below). Each click can be claimed by only one install.
Tracking consent
AppRefer never shows the App Tracking Transparency prompt. From SDK 0.6.0 the iOS SDK reads the status your app already has and sends it with the install: granted, denied (also restricted) or undetermined (not asked yet). On Android you pass your own consent with setTrackingConsent().
- Granted: full matching, conversions are sent to ad networks and advanced matching is kept.
- Denied: first-party only. The install gets Apple AdServices or organic, nothing is sent to ad networks, and no advertising ID or hashed personal data is stored.
- Undetermined: the decision is held. The install starts first-party and is not counted in reports yet. When the user answers, the SDK reports it: granted runs the full match once, denied keeps the first-party result. Purchases made in the meantime are queued for about 6.5 hours, so a purchase made just before the user taps Allow is still sent. With no answer after 24 hours the install is finalised as first-party.
- Not sent (older SDKs, or Android apps that never call
setTrackingConsent()): behaves as before consent existed, unless the app requires consent (see settings below).
AppRefer re-reads the stored consent on every forward, including retries and webhook purchases, so a later change in iOS Settings is honoured. The SDK checks again on every configure() and each time the app becomes active. Call trackingConsentDidChange() right after your own prompt so the answer is sent straight away.
import AppTrackingTransparency
_ = await ATTrackingManager.requestTrackingAuthorization()
await AppRefer.trackingConsentDidChange()Two hosts
Requests from installs that allowed tracking go to trk.apprefer.com. Everything else (installs that denied or haven't answered, and all Support traffic) goes to apprefer.com. AppRefer Billing picks its host the same way. The SDK never falls back from one to the other, so in your iOS privacy manifest you declare only trk.apprefer.com under NSPrivacyTrackingDomains.
App settings that change matching
Two per-app switches, set with PATCH /api/v1/apps/{appId} using an organisation API key with apps:write:
| Setting | Default | Effect |
|---|---|---|
probabilisticMatching | true | Set to false to turn off probabilistic matching. AppRefer then uses only Apple AdServices, Play Install Referrer click IDs and the exact single-candidate IP match. |
trackingConsentRequired | false | Set to true when every live version of your app sends consent (SDK 0.6.0+). Installs and purchases with no recorded consent are then treated as not granted, instead of the older default. |
curl -X PATCH https://apprefer.com/api/v1/apps/APP_ID \
-H "Authorization: Bearer ak_live_..." \
-H "Content-Type: application/json" \
-d '{"probabilisticMatching": false, "trackingConsentRequired": true}'Country
Each install gets a country for reporting. AppRefer uses the matched click's country or Apple Ads' country first, then the country the hosting edge reports for the request, and finally the region in the device locale (for example en_GB gives GB). The locale is an approximation, used only when nothing better exists.
Improve ad network match rates
After sign-up or login, call setAdvancedMatching() with the user's email or phone. Values are SHA-256 hashed on the device and attached to conversions for installs that allowed tracking. The call does nothing for installs that didn't. Code for each SDK is on the Events page.
Linking purchases to installs
CallsetUserId() with the same user ID your purchases use (your AppRefer Billing user or RevenueCat app user ID). Store and webhook purchases are then joined to the install's attribution.