iOS SDK

Complete reference for the AppRefer iOS SDK. Native Swift, zero external dependencies, actor-based singleton.

Installation#

Xcode (recommended)#

  1. In Xcode, go to File → Add Package Dependencies...
  2. Enter the repository URL: https://github.com/AppAgentic/apprefer-ios-sdk.git
  3. Select Up to Next Major Version and click Add Package

Package.swift#

Package.swift
dependencies: [
    .package(
        url: "https://github.com/AppAgentic/apprefer-ios-sdk.git",
        from: "1.0.0"
    )
],
targets: [
    .target(
        name: "YourApp",
        dependencies: [
            .product(name: "AppRefer", package: "apprefer-ios-sdk")
        ]
    )
]

No extra setup needed

The SDK automatically uses the AdServices framework when available (iOS 14.3+) for Apple Search Ads attribution. No entitlements, no capabilities, and no Info.plist changes required.

API Reference#

All methods use await, not try await

The AppRefer SDK never throws. All methods handle errors internally and log them. If called before configure(), methods return silently with no effect.

AppRefer.configure(apiKey:userId:debug:logLevel:)#

Initialize the SDK and resolve attribution. Call once at app launch. The SDK uses an actor-based singleton — calling configure() multiple times reuses the existing instance.

ParameterTypeDefaultDescription
apiKeyStringrequiredYour SDK key (pk_live_... or pk_test_...)
userIdString?nilOptional user ID to associate with attribution
debugBoolfalseEnable verbose logging to console
logLevelLogLevel.noneGranular log level: .none, .error, .warn, .info, .debug
Details
ReturnsAttribution? — the resolved attribution, or nil for organic installs
ThrowsNever
let attribution = await AppRefer.configure(
    apiKey: "pk_live_your_key_here"
)

if let attribution {
    print("Network: \(attribution.network ?? "unknown")")
    print("Match type: \(attribution.matchType ?? "organic")")
}

AppRefer.trackEvent(_:properties:revenue:currency:)#

Send a custom event to AppRefer.

ParameterTypeDefaultDescription
nameStringrequiredEvent name (e.g., "signup", "tutorial_complete")
properties[String: Any]?nilArbitrary key-value metadata
revenueDouble?nilRevenue amount (e.g., 9.99)
currencyString?nilISO 4217 currency code (e.g., "USD")
await AppRefer.trackEvent(
    "tutorial_complete",
    properties: ["level": 3, "time_spent": 42]
)

// With revenue
await AppRefer.trackEvent(
    "purchase",
    revenue: 9.99,
    currency: "USD"
)

AppRefer.setAdvancedMatching(email:phone:firstName:lastName:dateOfBirth:)#

Send hashed PII to improve ad network match rates. All values are SHA256-hashed on the device before being sent to the server.

ParameterTypeDefaultDescription
emailString?nilUser's email address
phoneString?nilPhone number in E.164 format
firstNameString?nilUser's first name
lastNameString?nilUser's last name
dateOfBirthString?nilDate of birth (YYYYMMDD)
await AppRefer.setAdvancedMatching(
    email: "user@example.com",
    phone: "+15551234567",
    firstName: "Jane",
    lastName: "Doe"
)

AppRefer.setUserId(_:)#

Associate a user ID with the device's attribution. Typically called with the RevenueCat app user ID.

Details
Signaturestatic func setUserId(_ userId: String) async
ReturnsVoid
let customerInfo = try await Purchases.shared.customerInfo()
await AppRefer.setUserId(customerInfo.originalAppUserId)

appreferId must be set on RevenueCat FIRST

Before any purchase can be attributed, you must set the appreferId subscriber attribute on RevenueCat. This is how AppRefer links RevenueCat webhook events back to the attributed device. Without it, purchase events from RevenueCat cannot be matched to attributions and will not be forwarded to ad networks.
// REQUIRED: Set appreferId on RevenueCat immediately after configure()
let attribution = await AppRefer.configure(apiKey: "pk_live_...")

// Link AppRefer device ID to RevenueCat subscriber
if let deviceId = await AppRefer.getDeviceId() {
    Purchases.shared.attribution.setAttributes(["appreferId": deviceId])
}

AppRefer.getAttribution()#

Returns the cached attribution from the last configure() call. Returns nil if configure() has not been called yet or the device is organic.

Details
Signaturestatic func getAttribution() async -> Attribution?
ReturnsAttribution? — cached attribution result

AppRefer.getDeviceId()#

Returns the device ID generated by AppRefer. This is a stable UUID stored in the Keychain, persisted across app reinstalls.

Details
Signaturestatic func getDeviceId() async -> String?
ReturnsString? — the device UUID, or nil before configure()

Keychain persistence

The iOS SDK stores the device ID in the Keychain, so it survives app reinstalls. This means a user who reinstalls the app will retain their original attribution.

Attribution Model#

The Attribution struct returned by configure() contains the following properties:

PropertyTypeDescription
networkString?Ad network name (e.g., "meta", "google", "tiktok", "apple_search_ads")
matchTypeString?Confidence level of the attribution match
campaignNameString?Campaign name from the tracking link
adsetNameString?Ad set / ad group name
adNameString?Ad creative name
fbclidString?Facebook click ID
gclidString?Google click ID
ttclidString?TikTok click ID
clickIdString?Generic click ID (AppRefer internal)
deviceIdString?Device UUID assigned by AppRefer
createdAtString?ISO 8601 timestamp of the attribution

Full Integration Example#

This example shows a complete integration in a SwiftUI app with RevenueCat:

MyApp.swift
import SwiftUI
import AppRefer
import RevenueCat

@main
struct MyApp: App {
    init() {
        // Configure RevenueCat
        Purchases.configure(withAPIKey: "your_revenuecat_api_key")

        Task {
            // 1. Initialize AppRefer and resolve attribution
            let attribution = await AppRefer.configure(
                apiKey: "pk_live_your_key_here"
            )

            if let attribution {
                print("Attributed to \(attribution.network ?? "organic")")
            }

            // 2. CRITICAL: Link AppRefer device ID to RevenueCat
            //    Without this, purchases CANNOT be attributed to ad campaigns
            if let deviceId = await AppRefer.getDeviceId() {
                Purchases.shared.attribution.setAttributes([
                    "appreferId": deviceId
                ])
            }

            // 3. Link RevenueCat user ID back to AppRefer
            if let customerInfo = try? await Purchases.shared.customerInfo() {
                await AppRefer.setUserId(customerInfo.originalAppUserId)
            }
        }
    }

    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}

// Later, after user signs up...
func onUserSignup(email: String, firstName: String) async {
    // 4. Send advanced matching data (hashed on-device)
    await AppRefer.setAdvancedMatching(
        email: email,
        firstName: firstName
    )

    // 5. Track the signup event
    await AppRefer.trackEvent("signup")
}

Best Practices#

  • Call configure() in your app's init() or application(_:didFinishLaunchingWithOptions:). The sooner you call it, the more accurate the attribution window.
  • Always set appreferId on RevenueCat immediately after configure(). This is the most important step for purchase attribution. Without it, RevenueCat webhook events cannot be linked to ad campaigns.
  • Use await without try. The SDK never throws. Using try await will compile but the try is unnecessary.
  • Always call setUserId() with the RevenueCat user ID if you use RevenueCat. This is how purchase webhooks are matched back to attributions.
  • The device ID is stored in the Keychain, so it persists across app reinstalls. This means attribution survives reinstalls.
  • Use pk_test_ keys during development. Sandbox events are completely isolated from production and never forwarded to ad networks.

Requirements#

RequirementMinimum Version
iOS14+
Swift5.9+
Xcode15+
DependenciesNone (zero external dependencies)