# Attribute app installs to the campaign that drove them

> Give each channel, creator or placement its own link. Installs are matched back to the link and shown next to clicks by campaign source.

Page: https://warplink.app/use-cases/campaign-attribution-for-apps

Give each channel, creator or placement its own WarpLink link, with UTM fields set on the link. A tap records the click and the install is matched back to that link. Analytics breaks taps down by campaign source, and each link's stats count the installs attributed to it. You see which spend or post produced the installs.

## How it works

1. **Name your channels.** List the channels and placements you want to compare: a newsletter, a creator, a paid campaign, a store listing. One link per entry keeps the report easy to read.
2. **Create a link per entry.** Create each link in the dashboard, with the REST API or from an MCP client. Set utm_source, utm_medium and utm_campaign on the link, and they are added to the destination when someone taps it.
3. **Share each link in its channel.** Put each link where it belongs: the email, the bio, the ad, the post. The link opens your app when it is installed and the right store page when it is not.
4. **Add the SDK once.** After a tap and an install, the first launch receives the link context and reports the install, so the install is attributed to the link that was tapped.
5. **Read taps and installs by channel.** Open Analytics and break taps down by campaign source, referrer, country, device, operating system, browser and app. Open a channel's link to see the installs attributed to it. Recent taps show within minutes.
6. **Act on the comparison.** Keep the channels that bring installs and pause the rest. A paused link stops sending traffic, and its history stays in your analytics.

## Create a link and read the match

### REST API (TypeScript)

```typescript
// One link per channel. The UTM fields are added to the destination on redirect.
const response = await fetch("https://api.warplink.app/v1/links", {
  method: "POST",
  headers: {
    // API key from Keys > API
    Authorization: "Bearer wl_live_YOUR_API_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    app_id: "3f9a1c2e-6b7d-4e1a-9c2f-8a5b1d0e7c44",
    slug: "spring-newsletter",
    destination_url: "https://app.example/spring",
    utm_source: "newsletter",
    utm_medium: "email",
    utm_campaign: "spring",
    tags: ["spring"],
  }),
});

const link = (await response.json()) as { short_url: string };
```

### iOS (Swift)

```swift
if let attribution = WarpLink.attributionResult {
    let confidence = attribution.matchConfidence ?? 0

    if attribution.matchGuaranteed || confidence > 0.5 {
        navigate(to: attribution.destination)
    } else {
        showOnboarding()
    }
}
```

### Android (Kotlin)

```kotlin
val attribution = WarpLink.attributionResult

if (attribution != null) {
    val confidence = attribution.matchConfidence ?: 0.0

    if (attribution.matchGuaranteed || confidence > 0.5) {
        navigateTo(attribution.destination)
    } else {
        showOnboarding()
    }
}
```

### React Native

```typescript
import { WarpLink } from '@warplink/react-native'

const attribution = await WarpLink.getAttributionResult()

if (attribution) {
  if (attribution.matchGuaranteed || attribution.matchConfidence > 0.5) {
    navigateToLink(attribution.linkId)
  } else {
    showOnboarding()
  }
}
```

### Flutter

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

final attribution = await WarpLink.getAttributionResult();

if (attribution != null) {
  if (attribution.matchGuaranteed || attribution.matchConfidence > 0.5) {
    navigateToLink(attribution.linkId);
  } else {
    showOnboarding();
  }
}
```

## What you get

- **Linking.** A short link per channel on your app's address or a custom domain, with UTM defaults, Open Graph previews and separate iOS, Android and web fallbacks.
- **Attribution.** Installs that follow a tap on a WarpLink link, in any channel, are matched back to the link. Of 309 matched installs in our published test, 303 went to the correct link (98.1 percent).
- **Analytics.** Clicks are bot-filtered and deduplicated. Breakdowns cover country, referrer, device, operating system, browser, campaign source, app and tap source, and each link's stats count the installs attributed to it.

## Questions

### What does campaign attribution cover?

Installs that follow a tap on a WarpLink link, in any channel. Each install is matched back to its link, and the install records name that link, so channels compare side by side.

### How accurate is the install matching?

Of 309 matched installs in our published test, 303 went to the correct link (98.1 percent). The accuracy page lists each tested condition with its counts.

### Can I set UTM parameters once on a link?

Yes. utm_source, utm_medium and utm_campaign on a link are added to the destination when the link is tapped. Other parameters go in injected parameters, and an explicit injected entry for the same key wins.

### How do I create many links at once?

Post to /v1/links from a script, or ask an MCP client to create them. Each channel gets its own slug, so the report reads by channel.

### Do I need the SDK?

Click analytics work from the link alone. The SDK reports the install and delivers the link context at first launch, which is what joins installs to clicks.

### How soon do taps appear in analytics?

Recent taps show within minutes. Clicks are bot-filtered and deduplicated per link and visitor over a rolling 24 hours.

## Related

- [Attribution concepts](https://warplink.app/docs/concepts/attribution)
- [Analytics concepts](https://warplink.app/docs/concepts/analytics)
- [Attribution accuracy results](https://warplink.app/docs/trust/attribution-accuracy)
- [Install attribution](https://warplink.app/install-attribution)
- [Link analytics](https://warplink.app/analytics)
- [Attributing creator links](https://warplink.app/blog/creator-link-attribution)
- [Passing UTM parameters through deep links](https://warplink.app/blog/pass-utm-parameters-through-deep-links)
