> For the complete AppRefer docs index, see https://apprefer.com/llms.txt (every page as markdown) or https://apprefer.com/llms-full.txt (all docs in one file).

# 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](https://apprefer.com/appsflyer-alternative), 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.

**Swift**

```swift
import AppRefer

let attribution = await AppRefer.configure(apiKey: "pk_live_...")
print(attribution?.network ?? "unknown")
```

**Kotlin**

```kotlin
import com.apprefer.sdk.AppRefer

lifecycleScope.launch {
    val attribution = AppRefer.configure(this@MainActivity, apiKey = "pk_live_...")
    Log.d("AppRefer", attribution?.network ?: "unknown")
}
```

**Dart**

```dart
import 'package:apprefer/apprefer.dart';

final attribution = await AppReferSDK.configure(
  AppReferConfig(apiKey: 'pk_live_...'),
);
print(attribution?.network);
```

**TypeScript**

```typescript
import { AppRefer } from '@apprefer/react-native-sdk';

const attribution = await AppRefer.configure({ apiKey: 'pk_live_...' });
console.log(attribution?.network);
```

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.

**Swift**

```swift
import AppTrackingTransparency

_ = await ATTrackingManager.requestTrackingAuthorization()
await AppRefer.trackingConsentDidChange()
```

**Kotlin**

```kotlin
// After your own consent screen. Null restores the default behaviour.
AppRefer.setTrackingConsent(granted = userAllowedTracking)
```

**Dart**

```dart
// iOS: after your ATT prompt
await AppReferSDK.trackingConsentDidChange();

// Android: pass your own consent
await AppReferSDK.setTrackingConsent(userAllowedTracking);
```

**TypeScript**

```typescript
// iOS: after your ATT prompt
await AppRefer.trackingConsentDidChange();

// Android: pass your own consent
await AppRefer.setTrackingConsent(userAllowedTracking);
```

### 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. |

```bash
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](https://apprefer.com/docs/events.md#advanced-matching) page.

> **Linking purchases to installs**
>
> Call `setUserId()` 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.

---

Source: https://apprefer.com/docs/attribution · Last updated: 2026-10-19
