> ## Documentation Index
> Fetch the complete documentation index at: https://docs.spendowl.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Attribution

> Access Apple Search Ads attribution data

## Overview

Attribution tells you how users discovered your app. SpendOwl fetches attribution data from Apple Search Ads and enriches it with campaign, ad group, and keyword details.

## Automatic Attribution

Attribution is automatically fetched when you call `configure()`. For most apps, you don't need to do anything else—the data flows to your dashboard automatically.

## Manual Attribution Access

Use the `attribution()` method to access attribution data in your app:

<Tabs>
  <Tab title="async/await">
    ```swift theme={null}
    Task {
        do {
            let attribution = try await SpendOwl.attribution()

            switch attribution.status {
            case .attributed:
                print("Campaign: \(attribution.campaignName ?? "unknown")")
                print("Keyword: \(attribution.keyword ?? "unknown")")
            case .organic:
                print("Organic install")
            case .unknown:
                print("Attribution pending")
            }
        } catch {
            print("Error: \(error)")
        }
    }
    ```
  </Tab>

  <Tab title="Completion Handler">
    ```swift theme={null}
    SpendOwl.attribution { result in
        switch result {
        case .success(let attribution):
            if attribution.status == .attributed {
                print("Campaign: \(attribution.campaignName ?? "unknown")")
            }
        case .failure(let error):
            print("Error: \(error)")
        }
    }
    ```
  </Tab>
</Tabs>

## Attribution Result

The `AttributionResult` struct contains all available attribution data:

```swift theme={null}
public struct AttributionResult {
    let id: String                  // Unique attribution ID
    let status: AttributionStatus   // .attributed, .organic, or .unknown

    // Campaign data (only when status == .attributed)
    let campaignId: Int?
    let campaignName: String?
    let adGroupId: Int?
    let adGroupName: String?
    let keywordId: Int?
    let keyword: String?

    // Additional data
    let countryOrRegion: String?    // "US", "GB", "JP", etc.
    let clickDate: Date?            // When the ad was clicked
    let conversionType: String?     // "Download" or "Redownload"
    let supplyPlacement: String?    // Ad placement type
}
```

## Attribution Status

| Status        | Description                                                                       |
| ------------- | --------------------------------------------------------------------------------- |
| `.attributed` | User installed after clicking an Apple Search Ads ad. Campaign data is available. |
| `.organic`    | User found the app organically (not through ads). No campaign data.               |
| `.unknown`    | Attribution couldn't be determined. May be pending or unavailable.                |

## Use Cases

### Display Campaign Info

Show users which campaign brought them:

```swift theme={null}
struct WelcomeView: View {
    @State private var campaignName: String?

    var body: some View {
        VStack {
            Text("Welcome!")
            if let campaign = campaignName {
                Text("You found us through: \(campaign)")
                    .font(.caption)
            }
        }
        .task {
            if let attr = try? await SpendOwl.attribution(),
               attr.status == .attributed {
                campaignName = attr.campaignName
            }
        }
    }
}
```

### Analytics Integration

Send attribution to your analytics platform:

```swift theme={null}
func trackAttribution() async {
    guard let attribution = try? await SpendOwl.attribution() else { return }

    Analytics.track("app_install", properties: [
        "source": attribution.status == .attributed ? "paid" : "organic",
        "campaign": attribution.campaignName ?? "none",
        "keyword": attribution.keyword ?? "none",
        "country": attribution.countryOrRegion ?? "unknown"
    ])
}
```

### A/B Testing by Source

Customize experience based on acquisition source:

```swift theme={null}
func getOnboardingFlow() async -> OnboardingFlow {
    guard let attribution = try? await SpendOwl.attribution() else {
        return .standard
    }

    if attribution.status == .attributed,
       attribution.keyword?.contains("premium") == true {
        return .premium
    }

    return .standard
}
```

## Caching

Attribution data is fetched once and cached:

* First call fetches from Apple and SpendOwl servers
* Subsequent calls return the cached result
* Cache persists across app launches

<Note>
  Attribution doesn't change after install, so caching is safe.
</Note>

## Error Handling

Handle attribution errors gracefully:

```swift theme={null}
do {
    let attribution = try await SpendOwl.attribution()
    // Use attribution
} catch SpendOwlError.notConfigured {
    // SDK not configured - call configure() first
} catch SpendOwlError.attributionUnavailable {
    // Device doesn't support attribution (iOS < 14.3)
} catch SpendOwlError.networkError {
    // Network issue - retry later
} catch {
    // Other error
}
```

## Next Steps

<CardGroup cols={2}>
  <Card title="User Identity" icon="user" href="/sdk/user-identity">
    Link attribution to user accounts
  </Card>

  <Card title="AttributionResult Reference" icon="code" href="/api-reference/attribution-result">
    See all attribution fields
  </Card>
</CardGroup>
