# AppSprint - Full Documentation > Device-level mobile attribution for app developers running paid acquisition. > AppSprint connects ad clicks, installs, trials, purchases, and subscriptions so teams can optimize campaigns by revenue instead of clicks. ## Product Overview AppSprint is a mobile measurement partner for app developers and small teams. It attributes installs to campaigns and keywords, then carries that attribution through downstream revenue events from subscriptions, purchases, trials, and custom in-app events. It is designed as a focused MMP for teams that want practical campaign measurement without enterprise MMP setup or pricing. ## Core Jobs - Match installs to ad clicks and campaign links at the device level. - Track downstream revenue and subscription events after install. - Connect ad network data from Apple Search Ads, Google Ads, TikTok Ads, and tracking links. - Connect revenue events from RevenueCat and Superwall. - Provide SDKs for iOS Swift, React Native/Expo, Android Kotlin, and Flutter. - Expose a REST API at https://api.appsprint.app/v1/. ## How It Works 1. Create an app in the AppSprint dashboard and copy the live API key. 2. Install the SDK for the app platform. 3. Call configure() early in app startup. 4. Send standard or custom events from the app. 5. Connect revenue and ad integrations in the dashboard. 6. Review campaign, keyword, install, and revenue attribution by app. ## Pricing - Free: 8,000 tracked installs one-time and one app, with no credit card required. - Pro: paid plan for production attribution, unlimited apps, and usage-based tracked installs. - Business: custom plan for higher volume, SLA, dedicated support, and custom integrations. ## Entity Information - Product: AppSprint - Company: Tap & Swipe SAS (SIREN 100 454 206) - Founder: Arthur Spalanzani - Registered address: 337 Chemin des Batellieres, 38190 Bernin, France - YouTube: https://www.youtube.com/@ArthurBuildsStuff - Twitter/X: https://x.com/arthursbuilds - LinkedIn: https://www.linkedin.com/in/arthur-spalanzani/ - Contact: arthur@appsprint.app ## Canonical URLs - Homepage: https://appsprint.app - Pricing: https://appsprint.app/pricing - Features: https://appsprint.app/features - About: https://appsprint.app/about - Blog: https://appsprint.app/blog - MMP comparisons: https://appsprint.app/compare - Documentation: https://appsprint.app/docs - Markdown docs index: https://appsprint.app/docs.md - Privacy: https://appsprint.app/privacy - Terms: https://appsprint.app/terms - Sitemap: https://appsprint.app/sitemap.xml - Short LLM guide: https://appsprint.app/llms.txt - Full LLM guide: https://appsprint.app/llms-full.txt ## Commercial Content Map - AppsFlyer alternative: https://appsprint.app/compare/appsflyer-alternative - Adjust alternative: https://appsprint.app/compare/adjust-alternative - Branch alternative: https://appsprint.app/compare/branch-alternative - AppsFlyer alternative for small app teams: https://appsprint.app/blog/appsflyer-alternative-for-small-app-teams - iOS attribution after ATT: https://appsprint.app/blog/ios-attribution-after-att - RevenueCat plus MMP subscription attribution: https://appsprint.app/blog/revenuecat-mmp-subscription-attribution - Mobile attribution for indie apps: https://appsprint.app/blog/mobile-attribution-for-indie-apps - Apple Search Ads revenue attribution: https://appsprint.app/blog/apple-search-ads-revenue-attribution ## Documentation Map - Overview: https://appsprint.app/docs (Markdown: https://appsprint.app/docs.md) - Quickstart: https://appsprint.app/docs/quickstart (Markdown: https://appsprint.app/docs/quickstart.md) - React Native: https://appsprint.app/docs/react-native (Markdown: https://appsprint.app/docs/react-native.md) - iOS (Swift): https://appsprint.app/docs/ios-swift (Markdown: https://appsprint.app/docs/ios-swift.md) - Android (Kotlin): https://appsprint.app/docs/android (Markdown: https://appsprint.app/docs/android.md) - Flutter: https://appsprint.app/docs/flutter (Markdown: https://appsprint.app/docs/flutter.md) - RevenueCat: https://appsprint.app/docs/revenuecat (Markdown: https://appsprint.app/docs/revenuecat.md) - Superwall: https://appsprint.app/docs/superwall (Markdown: https://appsprint.app/docs/superwall.md) - Apple Search Ads: https://appsprint.app/docs/apple-search-ads (Markdown: https://appsprint.app/docs/apple-search-ads.md) - Google Ads: https://appsprint.app/docs/google-ads (Markdown: https://appsprint.app/docs/google-ads.md) - TikTok Ads: https://appsprint.app/docs/tiktok-ads (Markdown: https://appsprint.app/docs/tiktok-ads.md) --- ## Source: Overview Canonical HTML: https://appsprint.app/docs Markdown URL: https://appsprint.app/docs.md # AppSprint Documentation Everything you need to integrate AppSprint into your mobile app. Pick a platform SDK, add event tracking, and connect revenue and ad-network integrations. ## How it works 1. **Install an SDK** for React Native, iOS, Android, or Flutter. 2. **Configure** by calling `configure()` with your API key as early as possible in app startup. 3. **Track events** by sending standard events (login, purchase, subscribe) and custom events. 4. **Connect revenue** by integrating RevenueCat or Superwall so revenue gets attributed automatically. 5. **Enrich with ads** by connecting Apple Search Ads for campaign and keyword attribution. ## Platform SDKs - **iOS (Swift)**: native SDK for iPhone and iPad apps. - **React Native / Expo**: cross-platform SDK for React Native and Expo apps. - **Android (Kotlin)**: native SDK for Kotlin and Java apps. - **Flutter**: plugin wrapping the AppSprint runtime. ## API base URL ``` https://api.appsprint.app ``` All SDK requests and webhooks target this base URL. Every route is prefixed with `/v1/`. --- ## Docs navigation Use the Markdown URLs when reading the docs programmatically. Use the HTML URLs when you need the interactive docs UI. - [Overview](https://appsprint.app/docs) ([Markdown](https://appsprint.app/docs.md)) — Introduction to AppSprint - [Quickstart](https://appsprint.app/docs/quickstart) ([Markdown](https://appsprint.app/docs/quickstart.md)) — Get up and running in 5 minutes - [React Native](https://appsprint.app/docs/react-native) ([Markdown](https://appsprint.app/docs/react-native.md)) — React Native / Expo SDK reference - [iOS (Swift)](https://appsprint.app/docs/ios-swift) ([Markdown](https://appsprint.app/docs/ios-swift.md)) — Native Swift SDK reference - [Android (Kotlin)](https://appsprint.app/docs/android) ([Markdown](https://appsprint.app/docs/android.md)) — Native Android SDK reference - [Flutter](https://appsprint.app/docs/flutter) ([Markdown](https://appsprint.app/docs/flutter.md)) — Flutter plugin reference - [RevenueCat](https://appsprint.app/docs/revenuecat) ([Markdown](https://appsprint.app/docs/revenuecat.md)) — Webhook integration for subscription attribution - [Superwall](https://appsprint.app/docs/superwall) ([Markdown](https://appsprint.app/docs/superwall.md)) — Webhook integration for paywall attribution - [Apple Search Ads](https://appsprint.app/docs/apple-search-ads) ([Markdown](https://appsprint.app/docs/apple-search-ads.md)) — Campaign and keyword attribution - [Google Ads](https://appsprint.app/docs/google-ads) ([Markdown](https://appsprint.app/docs/google-ads.md)) — Offline click conversion upload - [TikTok Ads](https://appsprint.app/docs/tiktok-ads) ([Markdown](https://appsprint.app/docs/tiktok-ads.md)) — Events API server-side event forwarding --- ## Source: Quickstart Canonical HTML: https://appsprint.app/docs/quickstart Markdown URL: https://appsprint.app/docs/quickstart.md # Quickstart Get AppSprint running in your app in 5 minutes. ## 1. Get your API key Create an app in the AppSprint dashboard and copy your live API key (`as_live_*`). ## 2. Install the SDK ```bash # React Native / Expo npm install appsprint-react-native # iOS (Swift Package Manager) # Add https://github.com/getappsprint/appsprint-ios-sdk in Xcode → Package Dependencies # Version: from "1.0.1" # Android (Gradle, add to app/build.gradle.kts) implementation("app.appsprint:sdk:1.0.2") # Flutter flutter pub add appsprint_flutter ``` ## 3. Configure the SDK Call `configure()` as early as possible (ideally in your root component or App Delegate). ## 4. Send a test event Use `sendTestEvent()` to verify end-to-end connectivity. ## 5. View in dashboard Open your app in the AppSprint dashboard. You should see the test event within seconds. --- ## Docs navigation Use the Markdown URLs when reading the docs programmatically. Use the HTML URLs when you need the interactive docs UI. - [Overview](https://appsprint.app/docs) ([Markdown](https://appsprint.app/docs.md)) — Introduction to AppSprint - [Quickstart](https://appsprint.app/docs/quickstart) ([Markdown](https://appsprint.app/docs/quickstart.md)) — Get up and running in 5 minutes - [React Native](https://appsprint.app/docs/react-native) ([Markdown](https://appsprint.app/docs/react-native.md)) — React Native / Expo SDK reference - [iOS (Swift)](https://appsprint.app/docs/ios-swift) ([Markdown](https://appsprint.app/docs/ios-swift.md)) — Native Swift SDK reference - [Android (Kotlin)](https://appsprint.app/docs/android) ([Markdown](https://appsprint.app/docs/android.md)) — Native Android SDK reference - [Flutter](https://appsprint.app/docs/flutter) ([Markdown](https://appsprint.app/docs/flutter.md)) — Flutter plugin reference - [RevenueCat](https://appsprint.app/docs/revenuecat) ([Markdown](https://appsprint.app/docs/revenuecat.md)) — Webhook integration for subscription attribution - [Superwall](https://appsprint.app/docs/superwall) ([Markdown](https://appsprint.app/docs/superwall.md)) — Webhook integration for paywall attribution - [Apple Search Ads](https://appsprint.app/docs/apple-search-ads) ([Markdown](https://appsprint.app/docs/apple-search-ads.md)) — Campaign and keyword attribution - [Google Ads](https://appsprint.app/docs/google-ads) ([Markdown](https://appsprint.app/docs/google-ads.md)) — Offline click conversion upload - [TikTok Ads](https://appsprint.app/docs/tiktok-ads) ([Markdown](https://appsprint.app/docs/tiktok-ads.md)) — Events API server-side event forwarding --- ## Source: React Native Canonical HTML: https://appsprint.app/docs/react-native Markdown URL: https://appsprint.app/docs/react-native.md # React Native / Expo Installation, configuration, event tracking, and full API reference for the React Native / Expo SDK. ## Requirements - React Native 0.71+ - React 18+ - iOS 14.0+ and Android API 21+ ## 1. Install npm ```bash npm install appsprint-react-native # iOS only cd ios && pod install ``` > For Expo prebuild, add the config plugin to app.json and run npx expo prebuild. The plugin injects NSUserTrackingUsageDescription on iOS and INTERNET / AD_ID on Android. [View on npm](https://www.npmjs.com/package/appsprint-react-native) ## 2. Configure ```tsx import { AppSprint } from 'appsprint-react-native'; // Call as early as possible. App.tsx, root layout, or _layout.tsx. await AppSprint.configure({ apiKey: 'as_live_xxxxx', }); ``` Non-blocking. configure() resolves after local state is restored; install registration runs in the background on the native side. Lifecycle observers register automatically. ### Configuration options | Option | Type | Default | Description | |--------|------|---------|-------------| | `apiKey` | `string` | — | Your live API key (starts with as_live_). | | `apiUrl` | `string` | https://api.appsprint.app | Override for staging or self-hosted environments. | | `enableAppleAdsAttribution` | `boolean` | true | iOS only. Fetches Apple AdServices at install time. | | `customerUserId` | `string | null` | null | Your internal user ID. Persists across launches and replays automatically if the first send fails. | | `autoTrackSessions` | `boolean` | true | Fires session_start on configure() and on foreground, debounced to one event per 30 minutes. | | `autoRefreshAttribution` | `boolean` | true | Refetches /v1/sdk/attribution on configure() and foreground transitions. | | `googleAdsConsent` | `GoogleAdsConsent | null` | null | Optional Google Ads ad user data consent forwarded as consent.adUserData on Google Ads uploads. | | `isDebug` | `boolean` | false | Forces debug-level logging on the native side. | | `logLevel` | `0 | 1 | 2 | 3` | 2 (WARN) | 0 = DEBUG, 1 = INFO, 2 = WARN, 3 = ERROR. | ## 3. Track events ```tsx // Standard event await AppSprint.sendEvent('login'); ``` ```tsx // Revenue event. Currency must be a 3-letter ISO code. await AppSprint.sendEvent('purchase', null, { revenue: 9.99, currency: 'USD', }); ``` ```tsx // Custom event with parameters await AppSprint.sendEvent('custom', 'level_complete', { level: 5, score: 1200, }); ``` ### Supported event types `session_start`, `login`, `sign_up`, `register`, `purchase`, `subscribe`, `start_trial`, `add_payment_info`, `add_to_cart`, `add_to_wishlist`, `initiate_checkout`, `view_content`, `view_item`, `search`, `share`, `tutorial_complete`, `achieve_level`, `level_start`, `level_complete`, `custom` ## 4. Read attribution ```tsx const attr = await AppSprint.getAttribution(); console.log(attr?.source); // "apple_ads", "tracking_link", or "organic" console.log(attr?.isAttributed); // boolean console.log(attr?.campaignName); // Campaign name when available console.log(attr?.appleAds?.campaignId); console.log(attr?.link?.name); ``` ## API reference ### `configure(config)` → Promise Initializes the SDK. Resolves after local state is restored; install registration runs in the background. ```tsx await AppSprint.configure({ apiKey: '…' }) ``` ### `sendEvent(type, name?, params?)` → Promise Enqueues an event locally and schedules a flush. ```tsx await AppSprint.sendEvent('purchase', null, { revenue: 9.99, currency: 'USD' }) ``` type is a string literal — see event types below. ### `flush()` → Promise Drains the queue immediately. Safe to call repeatedly. ```tsx await AppSprint.flush() ``` ### `refreshAttribution()` → Promise Fetches the latest attribution from the backend. Self-heals a 404 install_not_found by re-running install. ```tsx const attr = await AppSprint.refreshAttribution() ``` ### `setCustomerUserId(id)` → Promise Updates the customer user ID. Sent immediately if install is registered; otherwise queued and retried automatically. ```tsx await AppSprint.setCustomerUserId('user-123') ``` ### `getAppSprintId()` → Promise Returns the install ID, or null before install registration completes. ```tsx const id = await AppSprint.getAppSprintId() ``` ### `getAttribution()` → Promise Returns the cached AttributionResult. ```tsx const attr = await AppSprint.getAttribution() ``` ### `getAttributionParams()` → Promise> Partner-ready flat payload for forwarding to RevenueCat, Superwall, etc. ```tsx const params = await AppSprint.getAttributionParams() ``` ### `enableAppleAdsAttribution()` → Promise Re-enables Apple Ads at runtime on iOS. Returns false on Android. ```tsx await AppSprint.enableAppleAdsAttribution() ``` ### `isInitialized()` → Promise True once configure() resolved. ```tsx await AppSprint.isInitialized() ``` ### `isSdkDisabled()` → Promise True if a 401 or 403 permanently disabled the SDK. ```tsx await AppSprint.isSdkDisabled() ``` ### `sendTestEvent()` → Promise<{ success, message }> Posts a diagnostic event and resolves to (success, message). ```tsx const result = await AppSprint.sendTestEvent() ``` ### `clearData()` → Promise Wipes local state and the event queue. Removes lifecycle observers. ```tsx await AppSprint.clearData() ``` ### `destroy()` Removes native lifecycle observers without wiping data. ```tsx AppSprint.destroy() ``` ## Offline behavior - Events that fail to send are automatically queued in native storage (up to 100 events). - The queue persists across app restarts. - Queued events are retried automatically when configure() completes, when the app moves to the background, or when you call flush(). - If a queued event receives a 401/403, the SDK disables itself and clears the queue. ## Platform notes - The JS layer is a thin bridge. Behavior matches the standalone native iOS and Android SDKs. - On iOS, ATT must be requested while the app is foreground-active. NativeAppSprint.requestTrackingAuthorization() waits for that state internally. - On iOS, AdServices runs on iOS 14.3+. Older OS versions skip Apple Ads attribution silently. - On Android, GAID is read off the main thread, honoring Limit Ad Tracking and dropping the all-zero advertising ID. - Events persist to native storage (UserDefaults on iOS, SharedPreferences on Android) and survive app restarts. Maximum queue size is 100 events. - iOS uses URLSession with waitsForConnectivity = true. Transient offline windows queue inside the OS. - On Expo, the bundled config plugin injects NSUserTrackingUsageDescription, INTERNET, and AD_ID during prebuild. ## Troubleshooting **getAppSprintId() returns null** configure() resolves before install registration finishes on the native side. Retry briefly, or read the value after the first event has been sent. **Events do not appear in dashboard** Confirm the API key starts with as_live_. Call sendTestEvent() and inspect the returned message. **SDK disabled (isSdkDisabled returns true)** The API returned 401 or 403. Call clearData(), then configure() with a valid key. **Apple Ads attribution not detected** AdServices requires a real device (not the simulator). Confirm enableAppleAdsAttribution is true and that the test build is signed with a real provisioning profile. **pod install fails after adding the package** Delete ios/Podfile.lock and ios/Pods, then run pod install --repo-update. **Android build cannot find AD_ID** The package's manifest declares com.google.android.gms.permission.AD_ID and is merged at build time. If you target an app that cannot use it, remove with tools:node="remove". ## Connectivity test ```tsx const result = await AppSprint.sendTestEvent(); console.log(result.success, result.message); ``` ## Verification checklist 1. Create a blank Expo or bare React Native app and install the package. 2. Call configure() in App.tsx or your root layout. 3. Verify getAppSprintId() returns a value after first launch. 4. Send login, purchase, and custom events. Confirm they appear in the dashboard. 5. Send an event offline, background the app, restore connectivity, relaunch. Verify the event lands. 6. Call sendTestEvent() and confirm success is true. --- ## Docs navigation Use the Markdown URLs when reading the docs programmatically. Use the HTML URLs when you need the interactive docs UI. - [Overview](https://appsprint.app/docs) ([Markdown](https://appsprint.app/docs.md)) — Introduction to AppSprint - [Quickstart](https://appsprint.app/docs/quickstart) ([Markdown](https://appsprint.app/docs/quickstart.md)) — Get up and running in 5 minutes - [React Native](https://appsprint.app/docs/react-native) ([Markdown](https://appsprint.app/docs/react-native.md)) — React Native / Expo SDK reference - [iOS (Swift)](https://appsprint.app/docs/ios-swift) ([Markdown](https://appsprint.app/docs/ios-swift.md)) — Native Swift SDK reference - [Android (Kotlin)](https://appsprint.app/docs/android) ([Markdown](https://appsprint.app/docs/android.md)) — Native Android SDK reference - [Flutter](https://appsprint.app/docs/flutter) ([Markdown](https://appsprint.app/docs/flutter.md)) — Flutter plugin reference - [RevenueCat](https://appsprint.app/docs/revenuecat) ([Markdown](https://appsprint.app/docs/revenuecat.md)) — Webhook integration for subscription attribution - [Superwall](https://appsprint.app/docs/superwall) ([Markdown](https://appsprint.app/docs/superwall.md)) — Webhook integration for paywall attribution - [Apple Search Ads](https://appsprint.app/docs/apple-search-ads) ([Markdown](https://appsprint.app/docs/apple-search-ads.md)) — Campaign and keyword attribution - [Google Ads](https://appsprint.app/docs/google-ads) ([Markdown](https://appsprint.app/docs/google-ads.md)) — Offline click conversion upload - [TikTok Ads](https://appsprint.app/docs/tiktok-ads) ([Markdown](https://appsprint.app/docs/tiktok-ads.md)) — Events API server-side event forwarding --- ## Source: iOS (Swift) Canonical HTML: https://appsprint.app/docs/ios-swift Markdown URL: https://appsprint.app/docs/ios-swift.md # iOS (Swift) Installation, configuration, event tracking, and full API reference for the iOS (Swift) SDK. ## Requirements - iOS 14.0+ - Xcode 15+ - Swift 5.9 with structured concurrency (async/await) ## 1. Install Swift Package Manager (recommended) or CocoaPods ```swift // Swift Package Manager. In Xcode: File → Add Package Dependencies… // Or in Package.swift: .package(url: "https://github.com/getappsprint/appsprint-ios-sdk", from: "1.0.1") // CocoaPods. In your Podfile: pod "AppSprintSDK", "~> 1.0.1" ``` > Shipped as a precompiled XCFramework with a bundled PrivacyInfo.xcprivacy manifest. No source code is included. [View on GitHub (SPM + CocoaPods)](https://github.com/getappsprint/appsprint-ios-sdk) ## 2. Configure ```swift import AppSprintSDK // Call as early as possible. App.init() (SwiftUI) or AppDelegate.didFinishLaunching. Task { await AppSprint.shared.configure( AppSprintConfig(apiKey: "as_live_xxxxx") ) } ``` Non-blocking. configure() returns after restoring local state; install registration runs in a detached Task with exponential backoff. Queued events flush automatically once install completes. ### Configuration options | Option | Type | Default | Description | |--------|------|---------|-------------| | `apiKey` | `String` | — | Your live API key (starts with as_live_). | | `apiURL` | `URL` | https://api.appsprint.app | Override for staging or self-hosted environments. | | `enableAppleAdsAttribution` | `Bool` | true | Fetches the Apple AdServices token at install time and triggers a delayed attribution refresh 75 seconds later. | | `customerUserId` | `String?` | nil | Your internal user ID. Persists across launches and replays automatically if the first send fails. | | `autoTrackSessions` | `Bool` | true | Fires session_start on configure() and on foreground, debounced to one event per 30 minutes. | | `autoRefreshAttribution` | `Bool` | true | Refetches /v1/sdk/attribution on configure(), foreground, and after a late AdServices PATCH. | | `googleAdsConsent` | `GoogleAdsConsent?` | nil | Optional Google Ads ad user data consent forwarded as consent.adUserData on Google Ads uploads. | | `isDebug` | `Bool` | false | Forces logLevel = .debug. | | `logLevel` | `AppSprintLogLevel` | .warn | .debug, .info, .warn, or .error. Routes through os.Logger on iOS 14+. | ## 3. Track events ```swift // Standard event await AppSprint.shared.sendEvent(.login) ``` ```swift // Revenue event. Currency must be a 3-letter ISO code. await AppSprint.shared.sendEvent(.purchase, params: [ "revenue": 9.99, "currency": "USD" ]) ``` ```swift // Custom event with parameters await AppSprint.shared.sendEvent(.custom, name: "level_complete", params: [ "level": 5, "score": 1200, ]) ``` ### Supported event types `session_start`, `login`, `sign_up`, `register`, `purchase`, `subscribe`, `start_trial`, `add_payment_info`, `add_to_cart`, `add_to_wishlist`, `initiate_checkout`, `view_content`, `view_item`, `search`, `share`, `tutorial_complete`, `achieve_level`, `level_start`, `level_complete`, `custom` ## 4. Read attribution ```swift let attr = AppSprint.shared.getAttribution() print(attr?.source) // "apple_ads", "tracking_link", or "organic" print(attr?.isAttributed) // Bool print(attr?.campaignName) // Campaign name when available print(attr?.appleAds?.campaignId) print(attr?.link?.name) ``` ## API reference ### `configure(_:)` → async Initializes the SDK. Returns immediately; install registration runs in the background with retry on failure. ```swift await AppSprint.shared.configure(AppSprintConfig(apiKey: "…")) ``` ### `sendEvent(_:name:params:)` → async Enqueues an event locally and schedules a flush. Does not block on a network round-trip. ```swift await AppSprint.shared.sendEvent(.purchase, params: ["revenue": 9.99, "currency": "USD"]) ``` ### `flush()` → async Drains the queue immediately. Safe to call repeatedly; concurrent flushes are deduplicated. ```swift await AppSprint.shared.flush() ``` ### `refreshAttribution()` → AttributionResult? Fetches the latest attribution from /v1/sdk/attribution. Self-heals a 404 install_not_found by re-running install. ```swift let attr = await AppSprint.shared.refreshAttribution() ``` ### `setCustomerUserId(_:)` → async Updates the customer user ID. Sent immediately if install is registered; otherwise queued and retried automatically. ```swift await AppSprint.shared.setCustomerUserId("user-123") ``` ### `getAppSprintId()` → String? Returns the install ID, or nil before install registration completes. ```swift let id = AppSprint.shared.getAppSprintId() ``` ### `getAttribution()` → AttributionResult? Returns the cached AttributionResult. Available synchronously without a network call. ```swift let attr = AppSprint.shared.getAttribution() ``` ### `getAttributionParams()` → [String: String] Partner-ready flat payload for forwarding to RevenueCat, Superwall, etc. ```swift let params = AppSprint.shared.getAttributionParams() ``` ### `enableAppleAdsAttribution()` → Bool Re-enables Apple Ads at runtime and sends the AdServices token via PATCH. Returns whether the SDK was configured. ```swift AppSprint.shared.enableAppleAdsAttribution() ``` ### `isInitialized` → Bool True after configure() returns. Does not imply install registration succeeded. ```swift AppSprint.shared.isInitialized ``` ### `isSdkDisabled()` → Bool True if a 401 or 403 from the backend permanently disabled the SDK. ```swift AppSprint.shared.isSdkDisabled() ``` ### `sendTestEvent()` → TestEventResult Posts a diagnostic event and returns (success, message). Use during development. ```swift let result = await AppSprint.shared.sendTestEvent() ``` ### `clearData()` Wipes local state and the event queue. Use to reset the SDK. ```swift AppSprint.shared.clearData() ``` ## Offline behavior - Events that fail to send are automatically queued in native storage (up to 100 events). - The queue persists across app restarts. - Queued events are retried automatically when configure() completes, when the app moves to the background, or when you call flush(). - If a queued event receives a 401/403, the SDK disables itself and clears the queue. ## Platform notes - configure() is annotated @MainActor and is non-blocking. Calling it from didFinishLaunchingWithOptions or App.init() does not delay app startup. - ATT must be requested while the app is foreground-active. AppSprintNative.requestTrackingAuthorization() waits for that state internally, so calling it from app init is safe. - IDFA is collected only when ATT is authorized. If the user grants ATT after install, the SDK PATCHes the IDFA on the next foreground automatically. - Apple AdServices token fetch (AAAttribution.attributionToken) runs on iOS 14.3+. Failure is non-fatal; a fresh token is fetched on retry. - The SDK uses URLSession.waitsForConnectivity = true, so transient offline windows queue inside the OS rather than failing fast. - Background flushes are wrapped in beginBackgroundTask so iOS does not kill the queue worker mid-loop. ## Troubleshooting **getAppSprintId() returns nil** configure() returns before install registration finishes. Wait until isInitialized is true, then poll briefly, or read the value inside an event handler that fires after first launch. **Events do not appear in dashboard** Confirm the API key starts with as_live_. Call sendTestEvent() and inspect the returned message. Check Console.app for [AppSprint] logs at debug level. **SDK disabled after 401/403** A rejected key disables the SDK permanently. Call clearData(), then configure() with a valid key. **Attribution returns organic when an Apple Ads install was expected** Backend resolution can take up to 75 seconds for Apple AdServices. The SDK refetches automatically by default. If autoRefreshAttribution is off, call refreshAttribution() manually. **Queued events seem to never send** A queued event over ~90 KB is dropped on the next flush (the backend caps bodies at 100 KB). Smaller events flush on foreground, background, or another sendEvent. ## Connectivity test ```swift let result = await AppSprint.shared.sendTestEvent() print("\(result.success) — \(result.message)") ``` ## Verification checklist 1. Create a blank iOS app and add the SPM package or CocoaPods pod. 2. Call configure() in App.init() or AppDelegate.didFinishLaunchingWithOptions. 3. Verify getAppSprintId() returns a value after first launch. 4. Send login, purchase, and custom events. Confirm they appear in the dashboard. 5. Kill the app while offline, send an event, relaunch with connectivity. Verify the event lands. 6. Call sendTestEvent() and confirm success is true. --- ## Docs navigation Use the Markdown URLs when reading the docs programmatically. Use the HTML URLs when you need the interactive docs UI. - [Overview](https://appsprint.app/docs) ([Markdown](https://appsprint.app/docs.md)) — Introduction to AppSprint - [Quickstart](https://appsprint.app/docs/quickstart) ([Markdown](https://appsprint.app/docs/quickstart.md)) — Get up and running in 5 minutes - [React Native](https://appsprint.app/docs/react-native) ([Markdown](https://appsprint.app/docs/react-native.md)) — React Native / Expo SDK reference - [iOS (Swift)](https://appsprint.app/docs/ios-swift) ([Markdown](https://appsprint.app/docs/ios-swift.md)) — Native Swift SDK reference - [Android (Kotlin)](https://appsprint.app/docs/android) ([Markdown](https://appsprint.app/docs/android.md)) — Native Android SDK reference - [Flutter](https://appsprint.app/docs/flutter) ([Markdown](https://appsprint.app/docs/flutter.md)) — Flutter plugin reference - [RevenueCat](https://appsprint.app/docs/revenuecat) ([Markdown](https://appsprint.app/docs/revenuecat.md)) — Webhook integration for subscription attribution - [Superwall](https://appsprint.app/docs/superwall) ([Markdown](https://appsprint.app/docs/superwall.md)) — Webhook integration for paywall attribution - [Apple Search Ads](https://appsprint.app/docs/apple-search-ads) ([Markdown](https://appsprint.app/docs/apple-search-ads.md)) — Campaign and keyword attribution - [Google Ads](https://appsprint.app/docs/google-ads) ([Markdown](https://appsprint.app/docs/google-ads.md)) — Offline click conversion upload - [TikTok Ads](https://appsprint.app/docs/tiktok-ads) ([Markdown](https://appsprint.app/docs/tiktok-ads.md)) — Events API server-side event forwarding --- ## Source: Android (Kotlin) Canonical HTML: https://appsprint.app/docs/android Markdown URL: https://appsprint.app/docs/android.md # Android (Kotlin) Installation, configuration, event tracking, and full API reference for the Android (Kotlin) SDK. ## Requirements - Android minSdk 21 - compileSdk 34+ - Java 17 (Kotlin 1.9+) ## 1. Install Maven Central ```kotlin // app/build.gradle.kts dependencies { implementation("app.appsprint:sdk:1.0.2") } ``` > Sync Gradle after adding the dependency. The SDK already declares INTERNET and com.google.android.gms.permission.AD_ID, so you do not need to add them to your manifest. [View on Maven Central](https://central.sonatype.com/artifact/app.appsprint/sdk) ## 2. Configure ```kotlin import com.appsprint.sdk.AppSprint import com.appsprint.sdk.AppSprintConfig class MyApplication : Application() { override fun onCreate() { super.onCreate() AppSprint.shared(applicationContext).configure( AppSprintConfig(apiKey = "as_live_xxxxx") ) } } ``` Non-blocking. configure() returns immediately; install registration and device-info collection run off the main thread on the SDK's executor. The lifecycle observer is registered automatically. ### Configuration options | Option | Type | Default | Description | |--------|------|---------|-------------| | `apiKey` | `String` | — | Your live API key (starts with as_live_). | | `apiUrl` | `String` | https://api.appsprint.app | Override for staging or self-hosted environments. | | `enableAppleAdsAttribution` | `Boolean` | false | iOS-only. Ignored on Android. | | `customerUserId` | `String?` | null | Your internal user ID. Persists across launches and replays automatically if the first send fails. | | `autoTrackSessions` | `Boolean` | true | Fires session_start on configure() and on ProcessLifecycleOwner.ON_START, debounced to one event per 30 minutes. | | `autoRefreshAttribution` | `Boolean` | true | Refetches /v1/sdk/attribution on configure() and foreground transitions. | | `googleAdsConsent` | `GoogleAdsConsent?` | null | Optional Google Ads ad user data consent forwarded as consent.adUserData on Google Ads uploads. | | `isDebug` | `Boolean` | false | Forces logLevel = 0 (debug) and enables the optional debug overlay. | | `logLevel` | `Int` | 2 (WARN) | 0 = DEBUG, 1 = INFO, 2 = WARN, 3 = ERROR. | ## 3. Track events ```kotlin // Standard event val appSprint = AppSprint.shared(applicationContext) appSprint.sendEvent(AppSprintEventType.LOGIN) ``` ```kotlin // Revenue event. Currency must be a 3-letter ISO code. appSprint.sendEvent( AppSprintEventType.PURCHASE, params = mapOf("revenue" to 9.99, "currency" to "USD") ) ``` ```kotlin // Custom event with parameters appSprint.sendEvent( AppSprintEventType.CUSTOM, name = "level_complete", params = mapOf("level" to 5, "score" to 1200) ) ``` ### Supported event types `session_start`, `login`, `sign_up`, `register`, `purchase`, `subscribe`, `start_trial`, `add_payment_info`, `add_to_cart`, `add_to_wishlist`, `initiate_checkout`, `view_content`, `view_item`, `search`, `share`, `tutorial_complete`, `achieve_level`, `level_start`, `level_complete`, `custom` ## 4. Read attribution ```kotlin val attr = appSprint.getAttribution() println(attr?.source) // "apple_ads", "tracking_link", or "organic" println(attr?.isAttributed) // Boolean println(attr?.campaignName) // Campaign name when available println(attr?.link?.name) ``` ## API reference ### `configure(config)` Initializes the SDK. Returns immediately; install registration and lifecycle wiring run on the SDK executor. ```kotlin appSprint.configure(AppSprintConfig(apiKey = "…")) ``` ### `sendEvent(type, name?, params?)` Enqueues an event locally and schedules a flush. ```kotlin appSprint.sendEvent(AppSprintEventType.PURCHASE, params = mapOf("revenue" to 9.99, "currency" to "USD")) ``` ### `flush()` Drains the queue immediately. ```kotlin appSprint.flush() ``` ### `refreshAttribution()` → AttributionResult? Fetches the latest attribution. Blocking; call from a background thread. Self-heals on 404 install_not_found. ```kotlin val attr = appSprint.refreshAttribution() ``` ### `setCustomerUserId(id)` Updates the customer user ID. Persists to disk and retries on the next configure() or foreground if the first send fails. ```kotlin appSprint.setCustomerUserId("user-123") ``` ### `getAppSprintId()` → String? Returns the install ID, or null before install registration completes. ```kotlin val id = appSprint.getAppSprintId() ``` ### `getAttribution()` → AttributionResult? Returns the cached AttributionResult. ```kotlin val attr = appSprint.getAttribution() ``` ### `getAttributionParams()` → Map Partner-ready flat payload for forwarding to RevenueCat, Superwall, etc. ```kotlin val params = appSprint.getAttributionParams() ``` ### `enableAppleAdsAttribution()` → Boolean Returns false on Android. Apple Ads attribution is iOS-only. ```kotlin appSprint.enableAppleAdsAttribution() ``` ### `isInitialized()` → Boolean True after configure() returns. ```kotlin appSprint.isInitialized() ``` ### `isSdkDisabled()` → Boolean True if a 401 or 403 permanently disabled the SDK. ```kotlin appSprint.isSdkDisabled() ``` ### `sendTestEvent()` → TestEventResult Posts a diagnostic event off the main thread. From the main thread, use sendTestEventAsync(callback). ```kotlin val result = appSprint.sendTestEvent() ``` ### `clearData()` Wipes local state and the event queue. ```kotlin appSprint.clearData() ``` ## Offline behavior - Events that fail to send are automatically queued in native storage (up to 100 events). - The queue persists across app restarts. - Queued events are retried automatically when configure() completes, when the app moves to the background, or when you call flush(). - If a queued event receives a 401/403, the SDK disables itself and clears the queue. ## Platform notes - configure() is thread-safe (@Synchronized) and returns immediately. Safe to call from Application.onCreate() or an activity. - Apple Search Ads attribution is iOS-only. enableAppleAdsAttribution is accepted for cross-platform symmetry but does nothing on Android. - GAID is read during install registration only, off the main thread. The SDK honors Limit Ad Tracking and drops the all-zero advertising ID so a bogus value never reaches the backend. - Play Install Referrer is collected automatically. The package visibility entry for com.android.vending is in the SDK manifest, so it works on apps targeting Android 11+. - If your app cannot collect advertising IDs (children's apps, regional policies), remove com.google.android.gms.permission.AD_ID in your host manifest with tools:node="remove". - Events persist in SharedPreferences. They flush on foreground (ProcessLifecycleOwner.ON_START), background, the next sendEvent, or an explicit flush() call. ## Troubleshooting **getAppSprintId() returns null** configure() returns before install registration finishes. Check isInitialized() and retry briefly, or read the value inside an event handler that fires after first launch. **Events do not appear in dashboard** Confirm the API key starts with as_live_. Call sendTestEvent() and inspect the result. Lower logLevel to 0 and check logcat under the AppSprint tag. **SDK disabled after 401/403** A rejected key disables the SDK permanently. Call clearData(), then configure() with a valid key. **Events lost after app kill** Events persist to SharedPreferences and resend on the next configure(). If they still do not appear, the queue may have been dropped by clearData() or hit the 100-entry cap. **AD_ID permission rejected by Play review** Either include advertising ID collection in your Data safety answers, or remove the permission with tools:node="remove" in your host manifest. ## Connectivity test ```kotlin val result = appSprint.sendTestEvent() println("${result.success} — ${result.message}") ``` ## Verification checklist 1. Create a blank Android app and add the Maven Central dependency. 2. Call configure() in Application.onCreate(). 3. Verify getAppSprintId() returns a value after first launch. 4. Send login, purchase, and custom events. Confirm they appear in the dashboard. 5. Send an event offline, kill the app, relaunch with connectivity. Verify the event lands. 6. Call sendTestEvent() and confirm success is true. --- ## Docs navigation Use the Markdown URLs when reading the docs programmatically. Use the HTML URLs when you need the interactive docs UI. - [Overview](https://appsprint.app/docs) ([Markdown](https://appsprint.app/docs.md)) — Introduction to AppSprint - [Quickstart](https://appsprint.app/docs/quickstart) ([Markdown](https://appsprint.app/docs/quickstart.md)) — Get up and running in 5 minutes - [React Native](https://appsprint.app/docs/react-native) ([Markdown](https://appsprint.app/docs/react-native.md)) — React Native / Expo SDK reference - [iOS (Swift)](https://appsprint.app/docs/ios-swift) ([Markdown](https://appsprint.app/docs/ios-swift.md)) — Native Swift SDK reference - [Android (Kotlin)](https://appsprint.app/docs/android) ([Markdown](https://appsprint.app/docs/android.md)) — Native Android SDK reference - [Flutter](https://appsprint.app/docs/flutter) ([Markdown](https://appsprint.app/docs/flutter.md)) — Flutter plugin reference - [RevenueCat](https://appsprint.app/docs/revenuecat) ([Markdown](https://appsprint.app/docs/revenuecat.md)) — Webhook integration for subscription attribution - [Superwall](https://appsprint.app/docs/superwall) ([Markdown](https://appsprint.app/docs/superwall.md)) — Webhook integration for paywall attribution - [Apple Search Ads](https://appsprint.app/docs/apple-search-ads) ([Markdown](https://appsprint.app/docs/apple-search-ads.md)) — Campaign and keyword attribution - [Google Ads](https://appsprint.app/docs/google-ads) ([Markdown](https://appsprint.app/docs/google-ads.md)) — Offline click conversion upload - [TikTok Ads](https://appsprint.app/docs/tiktok-ads) ([Markdown](https://appsprint.app/docs/tiktok-ads.md)) — Events API server-side event forwarding --- ## Source: Flutter Canonical HTML: https://appsprint.app/docs/flutter Markdown URL: https://appsprint.app/docs/flutter.md # Flutter Installation, configuration, event tracking, and full API reference for the Flutter SDK. ## Requirements - Flutter 3.0+ - Dart 3.0+ - iOS 14.0+ and Android API 21+ ## 1. Install pub.dev ```yaml # pubspec.yaml dependencies: appsprint_flutter: ^1.0.1 # Then run: flutter pub get ``` > The Flutter plugin manages the iOS pod and the Android AAR for you. No extra repository setup needed. [View on pub.dev](https://pub.dev/packages/appsprint_flutter) ## 2. Configure ```typescript import 'package:flutter/material.dart'; import 'package:appsprint_flutter/appsprint_flutter.dart'; Future main() async { WidgetsFlutterBinding.ensureInitialized(); await AppSprint.instance.configure( const AppSprintConfig(apiKey: 'as_live_xxxxx'), ); runApp(const MyApp()); } ``` Non-blocking. configure() resolves after local state is restored; install registration runs in the background on the native side. Platform-specific code (AdServices on iOS, Play Install Referrer on Android) runs through method channels. ### Configuration options | Option | Type | Default | Description | |--------|------|---------|-------------| | `apiKey` | `String` | — | Your live API key (starts with as_live_). | | `apiUrl` | `String` | https://api.appsprint.app | Override for staging or self-hosted environments. | | `enableAppleAdsAttribution` | `bool` | true | iOS only. Fetches Apple AdServices at install time. | | `customerUserId` | `String?` | null | Your internal user ID. Persists across launches and replays automatically if the first send fails. | | `autoTrackSessions` | `bool` | true | Fires session_start on configure() and on foreground, debounced to one event per 30 minutes. | | `autoRefreshAttribution` | `bool` | true | Refetches /v1/sdk/attribution on configure() and foreground transitions. | | `googleAdsConsent` | `GoogleAdsConsent?` | null | Optional Google Ads ad user data consent forwarded as consent.adUserData on Google Ads uploads. | | `isDebug` | `bool` | false | Forces debug-level logging on the native side. | | `logLevel` | `int` | 2 (WARN) | 0 = DEBUG, 1 = INFO, 2 = WARN, 3 = ERROR. | ## 3. Track events ```typescript // Standard event await AppSprint.instance.sendEvent(AppSprintEventType.login); ``` ```typescript // Revenue event. Currency must be a 3-letter ISO code. await AppSprint.instance.sendEvent( AppSprintEventType.purchase, params: {'revenue': 9.99, 'currency': 'USD'}, ); ``` ```typescript // Custom event with parameters await AppSprint.instance.sendEvent( AppSprintEventType.custom, name: 'level_complete', params: {'level': 5, 'score': 1200}, ); ``` ### Supported event types `session_start`, `login`, `sign_up`, `register`, `purchase`, `subscribe`, `start_trial`, `add_payment_info`, `add_to_cart`, `add_to_wishlist`, `initiate_checkout`, `view_content`, `view_item`, `search`, `share`, `tutorial_complete`, `achieve_level`, `level_start`, `level_complete`, `custom` ## 4. Read attribution ```typescript final attr = await AppSprint.instance.getAttribution(); print(attr?.source); // "apple_ads", "tracking_link", or "organic" print(attr?.isAttributed); // bool print(attr?.campaignName); // Campaign name when available print(attr?.appleAds?.campaignId); print(attr?.link?.name); ``` ## API reference ### `configure(config)` → Future Initializes the SDK. Resolves after local state is restored; install registration runs in the background. ```typescript await AppSprint.instance.configure(const AppSprintConfig(apiKey: '…')); ``` ### `sendEvent(type, {name, params})` → Future Enqueues an event locally and schedules a flush. ```typescript await AppSprint.instance.sendEvent(AppSprintEventType.purchase, params: {'revenue': 9.99, 'currency': 'USD'}); ``` ### `flush()` → Future Drains the queue immediately. ```typescript await AppSprint.instance.flush() ``` ### `refreshAttribution()` → Future Fetches the latest attribution from the backend. Self-heals a 404 install_not_found by re-running install. ```typescript final attr = await AppSprint.instance.refreshAttribution(); ``` ### `setCustomerUserId(id)` → Future Updates the customer user ID. Sent immediately if install is registered; otherwise queued and retried automatically. ```typescript await AppSprint.instance.setCustomerUserId('user-123'); ``` ### `getAppSprintId()` → Future Returns the install ID, or null before install registration completes. ```typescript final id = await AppSprint.instance.getAppSprintId(); ``` ### `getAttribution()` → Future Returns the cached AttributionResult. ```typescript final attr = await AppSprint.instance.getAttribution(); ``` ### `getAttributionParams()` → Future> Partner-ready flat payload for forwarding to RevenueCat, Superwall, etc. ```typescript final params = await AppSprint.instance.getAttributionParams(); ``` ### `enableAppleAdsAttribution()` → Future Re-enables Apple Ads at runtime on iOS. Returns false on Android. ```typescript await AppSprint.instance.enableAppleAdsAttribution() ``` ### `isInitialized()` → Future True once configure() resolved. ```typescript await AppSprint.instance.isInitialized() ``` ### `isSdkDisabled()` → Future True if a 401 or 403 permanently disabled the SDK. ```typescript await AppSprint.instance.isSdkDisabled() ``` ### `sendTestEvent()` → Future Posts a diagnostic event and resolves to (success, message). ```typescript final result = await AppSprint.instance.sendTestEvent(); ``` ### `clearData()` → Future Wipes local state and the event queue. ```typescript await AppSprint.instance.clearData() ``` ## Offline behavior - Events that fail to send are automatically queued in native storage (up to 100 events). - The queue persists across app restarts. - Queued events are retried automatically when configure() completes, when the app moves to the background, or when you call flush(). - If a queued event receives a 401/403, the SDK disables itself and clears the queue. ## Platform notes - The Flutter plugin wraps the native iOS and Android SDKs through method channels. Behavior matches the native SDKs exactly; the Dart layer is a thin pass-through. - configure() is non-blocking. The future resolves once local state is restored; install registration runs in the background on the native side. - On iOS, ATT must be requested while the app is foreground-active. AppSprintNative.requestTrackingAuthorization() waits for that state internally, so calling it from main() or initState() is safe. - On Android, GAID is read off the main thread, honoring Limit Ad Tracking and dropping the all-zero advertising ID. The plugin declares INTERNET, ACCESS_NETWORK_STATE, and AD_ID for you. - Events persist to native storage (UserDefaults on iOS, SharedPreferences on Android) and survive app restarts. Maximum queue size is 100 events. - iOS uses URLSession with waitsForConnectivity = true. Transient offline windows queue inside the OS rather than failing fast. ## Troubleshooting **getAppSprintId() returns null** configure() resolves before install registration finishes on the native side. Check isInitialized() and retry briefly, or read the value after the first event has been sent. **Events do not appear in dashboard** Confirm the API key starts with as_live_. Call sendTestEvent() and inspect the message. iOS logs flow into Console.app; Android logs flow into logcat under the AppSprint tag. **SDK disabled after 401/403** Call clearData(), then configure() with a valid key. **pod install fails after adding the package** Run flutter clean, flutter pub get, then cd ios && pod install --repo-update. **Attribution returns organic on iOS when Apple Ads is expected** Backend resolution can take up to 75 seconds. The SDK refetches automatically by default; if disabled, call refreshAttribution() manually. ## Connectivity test ```typescript final result = await AppSprint.instance.sendTestEvent(); print('${result.success} — ${result.message}'); ``` ## Verification checklist 1. Create a blank Flutter app and add the pub.dev dependency. 2. Call configure() before runApp() in main(). 3. Verify getAppSprintId() returns a value after first launch. 4. Send login, purchase, and custom events. Confirm they appear in the dashboard. 5. Send an event offline, restart the app online. Verify queue flush. 6. Call sendTestEvent() and confirm success is true. --- ## Docs navigation Use the Markdown URLs when reading the docs programmatically. Use the HTML URLs when you need the interactive docs UI. - [Overview](https://appsprint.app/docs) ([Markdown](https://appsprint.app/docs.md)) — Introduction to AppSprint - [Quickstart](https://appsprint.app/docs/quickstart) ([Markdown](https://appsprint.app/docs/quickstart.md)) — Get up and running in 5 minutes - [React Native](https://appsprint.app/docs/react-native) ([Markdown](https://appsprint.app/docs/react-native.md)) — React Native / Expo SDK reference - [iOS (Swift)](https://appsprint.app/docs/ios-swift) ([Markdown](https://appsprint.app/docs/ios-swift.md)) — Native Swift SDK reference - [Android (Kotlin)](https://appsprint.app/docs/android) ([Markdown](https://appsprint.app/docs/android.md)) — Native Android SDK reference - [Flutter](https://appsprint.app/docs/flutter) ([Markdown](https://appsprint.app/docs/flutter.md)) — Flutter plugin reference - [RevenueCat](https://appsprint.app/docs/revenuecat) ([Markdown](https://appsprint.app/docs/revenuecat.md)) — Webhook integration for subscription attribution - [Superwall](https://appsprint.app/docs/superwall) ([Markdown](https://appsprint.app/docs/superwall.md)) — Webhook integration for paywall attribution - [Apple Search Ads](https://appsprint.app/docs/apple-search-ads) ([Markdown](https://appsprint.app/docs/apple-search-ads.md)) — Campaign and keyword attribution - [Google Ads](https://appsprint.app/docs/google-ads) ([Markdown](https://appsprint.app/docs/google-ads.md)) — Offline click conversion upload - [TikTok Ads](https://appsprint.app/docs/tiktok-ads) ([Markdown](https://appsprint.app/docs/tiktok-ads.md)) — Events API server-side event forwarding --- ## Source: RevenueCat Canonical HTML: https://appsprint.app/docs/revenuecat Markdown URL: https://appsprint.app/docs/revenuecat.md # RevenueCat Forward RevenueCat webhook events to AppSprint so every subscription and purchase is automatically attributed to the install that triggered it. ## Webhook endpoint ``` https://api.appsprint.app/v1/webhooks/revenuecat ``` Paste this URL into RevenueCat → Project Settings → Integrations → Webhooks. ## Authentication Set the Authorization header in RevenueCat's webhook config to a Bearer token matching your app's `revenuecatWebhookToken` stored in the AppSprint dashboard under Integrations → RevenueCat. ``` Authorization: Bearer rc_whsec_xxxxxxxx ``` ## Event mapping | RevenueCat event | AppSprint event | |-----------------|-----------------| | INITIAL_PURCHASE | purchase | | RENEWAL | renewal | | CANCELLATION | cancellation | | UNCANCELLATION | uncancellation | | NON_RENEWING_PURCHASE | purchase | | SUBSCRIPTION_PAUSED | subscription_paused | | EXPIRATION | expiration | | BILLING_ISSUE | billing_issue | | PRODUCT_CHANGE | product_change | ## Required: appsprintId subscriber attribute For webhooks to be matched to an attribution, you must set the `appsprintId` subscriber attribute in RevenueCat from the SDK. ## SDK snippets Set the subscriber attribute after the AppSprint SDK is configured. In React Native and Flutter, `getAppSprintId()` is asynchronous, so await it before calling RevenueCat. See the RevenueCat docs page for platform-specific code snippets. --- ## Docs navigation Use the Markdown URLs when reading the docs programmatically. Use the HTML URLs when you need the interactive docs UI. - [Overview](https://appsprint.app/docs) ([Markdown](https://appsprint.app/docs.md)) — Introduction to AppSprint - [Quickstart](https://appsprint.app/docs/quickstart) ([Markdown](https://appsprint.app/docs/quickstart.md)) — Get up and running in 5 minutes - [React Native](https://appsprint.app/docs/react-native) ([Markdown](https://appsprint.app/docs/react-native.md)) — React Native / Expo SDK reference - [iOS (Swift)](https://appsprint.app/docs/ios-swift) ([Markdown](https://appsprint.app/docs/ios-swift.md)) — Native Swift SDK reference - [Android (Kotlin)](https://appsprint.app/docs/android) ([Markdown](https://appsprint.app/docs/android.md)) — Native Android SDK reference - [Flutter](https://appsprint.app/docs/flutter) ([Markdown](https://appsprint.app/docs/flutter.md)) — Flutter plugin reference - [RevenueCat](https://appsprint.app/docs/revenuecat) ([Markdown](https://appsprint.app/docs/revenuecat.md)) — Webhook integration for subscription attribution - [Superwall](https://appsprint.app/docs/superwall) ([Markdown](https://appsprint.app/docs/superwall.md)) — Webhook integration for paywall attribution - [Apple Search Ads](https://appsprint.app/docs/apple-search-ads) ([Markdown](https://appsprint.app/docs/apple-search-ads.md)) — Campaign and keyword attribution - [Google Ads](https://appsprint.app/docs/google-ads) ([Markdown](https://appsprint.app/docs/google-ads.md)) — Offline click conversion upload - [TikTok Ads](https://appsprint.app/docs/tiktok-ads) ([Markdown](https://appsprint.app/docs/tiktok-ads.md)) — Events API server-side event forwarding --- ## Source: Superwall Canonical HTML: https://appsprint.app/docs/superwall Markdown URL: https://appsprint.app/docs/superwall.md # Superwall Forward Superwall webhook events to AppSprint so paywalls, trials, and subscription changes are attributed to the original install. ## Webhook endpoint ``` https://api.appsprint.app/v1/webhooks/superwall ``` Paste this URL into Superwall → Settings → Integrations → Webhooks. ## Authentication Superwall signs webhooks using Svix. AppSprint verifies the signature using the webhook signing secret stored in your app's dashboard under Integrations → Superwall. ## Event mapping | Superwall event | AppSprint event | |----------------|-----------------| | transaction_complete | purchase | | subscription_start | subscribe | | free_trial_start | start_trial | | subscription_renew | renewal | | subscription_cancel | cancellation | | subscription_expire | expiration | ## Required: appsprintId user attribute For webhooks to be matched to an attribution, you must set the `appsprintId` user attribute in Superwall from the SDK. ## SDK snippets Set the user attribute after the AppSprint SDK is configured. In React Native and Flutter, `getAppSprintId()` is asynchronous, so await it before calling Superwall. See the Superwall docs page for platform-specific code snippets. --- ## Docs navigation Use the Markdown URLs when reading the docs programmatically. Use the HTML URLs when you need the interactive docs UI. - [Overview](https://appsprint.app/docs) ([Markdown](https://appsprint.app/docs.md)) — Introduction to AppSprint - [Quickstart](https://appsprint.app/docs/quickstart) ([Markdown](https://appsprint.app/docs/quickstart.md)) — Get up and running in 5 minutes - [React Native](https://appsprint.app/docs/react-native) ([Markdown](https://appsprint.app/docs/react-native.md)) — React Native / Expo SDK reference - [iOS (Swift)](https://appsprint.app/docs/ios-swift) ([Markdown](https://appsprint.app/docs/ios-swift.md)) — Native Swift SDK reference - [Android (Kotlin)](https://appsprint.app/docs/android) ([Markdown](https://appsprint.app/docs/android.md)) — Native Android SDK reference - [Flutter](https://appsprint.app/docs/flutter) ([Markdown](https://appsprint.app/docs/flutter.md)) — Flutter plugin reference - [RevenueCat](https://appsprint.app/docs/revenuecat) ([Markdown](https://appsprint.app/docs/revenuecat.md)) — Webhook integration for subscription attribution - [Superwall](https://appsprint.app/docs/superwall) ([Markdown](https://appsprint.app/docs/superwall.md)) — Webhook integration for paywall attribution - [Apple Search Ads](https://appsprint.app/docs/apple-search-ads) ([Markdown](https://appsprint.app/docs/apple-search-ads.md)) — Campaign and keyword attribution - [Google Ads](https://appsprint.app/docs/google-ads) ([Markdown](https://appsprint.app/docs/google-ads.md)) — Offline click conversion upload - [TikTok Ads](https://appsprint.app/docs/tiktok-ads) ([Markdown](https://appsprint.app/docs/tiktok-ads.md)) — Events API server-side event forwarding --- ## Source: Apple Search Ads Canonical HTML: https://appsprint.app/docs/apple-search-ads Markdown URL: https://appsprint.app/docs/apple-search-ads.md # Apple Search Ads Connect Apple Search Ads to attribute iOS installs to the campaign, ad group, keyword, and country that produced them, and to see spend, taps, impressions, Apple-reported installs, and AppSprint revenue in one place. Attribution itself runs through the SDK with nothing to configure; the API connection adds the live campaign metrics. ## Prerequisites - An Apple Search Ads account with an API role that can read reporting data. **API Account Manager** is recommended for setup. - The AppSprint SDK installed and configured in your iOS, React Native, Flutter, or Expo app. The SDK collects the AdServices attribution token without any extra code. - Your App Store ID (the numeric ID at the end of your App Store URL). ## Available metrics | Metric | Definition | |--------|------------| | Spend | Amount spent on the Apple Search Ads campaign over the selected window. | | Installs | Installs Apple reports for this campaign over the selected window. | | CPI | Cost per install. Spend divided by attributed installs. | | Impressions | Times the ad was shown, reported by Apple. | | Taps | Ad taps, reported by Apple. | | TTR | Tap-through rate. Taps divided by impressions. | | CR | Conversion rate. Installs divided by taps. | | ROAS | Return on ad spend. Attributed revenue divided by spend. | | Revenue | Revenue from in-app events attributed to this campaign. | ## Attribution data attached to each install Every install AppSprint attributes to Apple Search Ads carries the following fields, resolved from the AdServices attribution token: | Field | Description | |-------|-------------| | orgId | Campaign Group that owns the attribution record. | | campaignId | Apple Search Ads campaign that produced the install. | | adGroupId | Ad group within the campaign. | | adId | Ad assignment ID, when Apple includes ad-level attribution. | | keywordId | Keyword that triggered the ad, when applicable. Apple returns the numeric ID; Search Match installs may not include one. | | countryOrRegion | User's country or region as reported by Apple. | | conversionType | Whether the install was a fresh download or a redownload. | | claimType | Whether Apple attributed the install to a tap or view. | | clickDate | Tap-through timestamp when Apple includes one. | | impressionDate | View-through timestamp when Apple includes one. | | supplyPlacement | Apple Ads supply placement for the attributed interaction. | Human-readable ad group and keyword *names* aren't included in Apple's attribution response. The dashboard currently shows the stable Apple IDs for keyword-level post-install activity. ## Connect to Apple Search Ads ### Step 1: Open the connection form in AppSprint In the AppSprint dashboard, open your app and go to **Integrations → Apple Search Ads**. Click **Set up**. AppSprint will display a public key. Keep this tab open, you'll paste it into Apple in the next step. ### Step 2: Generate the API certificate in Apple Search Ads 1. In Apple Search Ads, go to **Settings → API** and click **Create API Certificate**. 2. Paste the public key from the AppSprint dashboard and confirm. 3. Apple displays three values. Copy each one: **Client ID**, **Team ID**, and **Key ID**. You don't need to copy a Campaign Group ID. AppSprint discovers every Campaign Group the API certificate can see and fetches campaigns across all of them. Your App Store ID narrows the results back to this app. ### Step 3: Finish the connection 1. Back in the AppSprint dashboard, paste the Client ID, Team ID, and Key ID into the form. 2. Enter your **App Store ID**, the numeric ID at the end of your App Store URL. AppSprint uses it to scope the campaign list to this app's campaigns only. 3. Save. AppSprint validates the credentials against Apple immediately by listing the Campaign Groups the certificate can see. If anything is wrong, you'll see an error explaining which value to re-check. ## SDK setup Attribution works without any app code changes. The iOS, React Native, Flutter, and Expo SDKs collect Apple's AdServices attribution token when you call `configure()`. The framework is part of iOS 14.3 and later; the SDK silently skips token collection on older iOS versions and on Android. ## Troubleshooting A few things to check first: - The three values from Apple (Client ID, Team ID, Key ID) are the ones from the current API certificate. Apple rotates them when you regenerate. - The App Store ID is the numeric ID, not the bundle identifier. - The app is running on iOS 14.3 or later for AdServices attribution to be available. | Problem | What to try | |---------|-------------| | Connection rejected | Apple's response usually points at one of the three IDs. Re-open the Search Ads UI, copy each value (Client ID, Team ID, Key ID) again, and confirm the API certificate hasn't been rotated. | | Dashboard says it can't load data from Apple | Most causes are transient. Apple rate-limits and occasionally returns 5xx errors. Refresh in a few seconds. If it keeps failing, re-run the connect form to refresh access. | | Missing App Store ID banner | A campaign group can contain campaigns for several apps. AppSprint uses the App Store ID to show only the campaigns for the app you're looking at. Open the connection form and paste the numeric ID from your App Store URL. | | An install came back as organic | Either Apple didn't find a matching ad interaction in its attribution window, the device is on iOS older than 14.3, or no valid AdServices token reached AppSprint within Apple's 24-hour token TTL. | --- ## Docs navigation Use the Markdown URLs when reading the docs programmatically. Use the HTML URLs when you need the interactive docs UI. - [Overview](https://appsprint.app/docs) ([Markdown](https://appsprint.app/docs.md)) — Introduction to AppSprint - [Quickstart](https://appsprint.app/docs/quickstart) ([Markdown](https://appsprint.app/docs/quickstart.md)) — Get up and running in 5 minutes - [React Native](https://appsprint.app/docs/react-native) ([Markdown](https://appsprint.app/docs/react-native.md)) — React Native / Expo SDK reference - [iOS (Swift)](https://appsprint.app/docs/ios-swift) ([Markdown](https://appsprint.app/docs/ios-swift.md)) — Native Swift SDK reference - [Android (Kotlin)](https://appsprint.app/docs/android) ([Markdown](https://appsprint.app/docs/android.md)) — Native Android SDK reference - [Flutter](https://appsprint.app/docs/flutter) ([Markdown](https://appsprint.app/docs/flutter.md)) — Flutter plugin reference - [RevenueCat](https://appsprint.app/docs/revenuecat) ([Markdown](https://appsprint.app/docs/revenuecat.md)) — Webhook integration for subscription attribution - [Superwall](https://appsprint.app/docs/superwall) ([Markdown](https://appsprint.app/docs/superwall.md)) — Webhook integration for paywall attribution - [Apple Search Ads](https://appsprint.app/docs/apple-search-ads) ([Markdown](https://appsprint.app/docs/apple-search-ads.md)) — Campaign and keyword attribution - [Google Ads](https://appsprint.app/docs/google-ads) ([Markdown](https://appsprint.app/docs/google-ads.md)) — Offline click conversion upload - [TikTok Ads](https://appsprint.app/docs/tiktok-ads) ([Markdown](https://appsprint.app/docs/tiktok-ads.md)) — Events API server-side event forwarding --- ## Source: Google Ads Canonical HTML: https://appsprint.app/docs/google-ads Markdown URL: https://appsprint.app/docs/google-ads.md # Google Ads Connect Google Ads to upload offline conversions when in-app events fire and to see spend next to the installs attributed by AppSprint to each campaign. You connect the account, map your events to conversion actions, and add a tracking template to your campaigns. ## Prerequisites - A Google account with access to the Google Ads customer account you want to connect. - The Google Ads Customer ID for the account you want to track. - At least one offline conversion action per app, created in Google Ads before connecting (Google takes around six hours to index a new conversion action before it accepts uploads). - Auto-tagging enabled in Google Ads (**Tools → Account settings → Auto-tagging**). It's on by default. AppSprint relies on auto-tagging to receive the click ID through your tracking template; with it off, clicks land at AppSprint without a click ID and conversions can't be uploaded. - If you serve users in EEA, UK, or Switzerland, collect Google Ads ad user data consent in your app and send it through the SDK. AppSprint forwards that consent signal only when your app provides it. ## Reference ### Available metrics | Metric | Definition | |--------|------------| | Spend | Amount spent on the Google Ads campaign over the selected window. | | Installs | Installs attributed by AppSprint to this campaign. Falls back to Google's reported conversions when AppSprint has no match. | | CPI | Cost per install. Spend divided by attributed installs. | | IPM | Installs per 1,000 impressions. | | Impressions | Times the ad was shown, reported by Google. | | CPM | Cost per 1,000 impressions. | | Clicks | Ad clicks, reported by Google. | | CPC | Cost per click. | | CTR | Click-through rate. Clicks divided by impressions. | | CTI | Click-to-install rate. Installs divided by clicks. | | ROAS | Return on ad spend. Attributed revenue divided by spend. | | Revenue | Revenue from in-app events attributed to this campaign. Falls back to Google's reported conversion value when AppSprint has no match. | ### Eligible in-app events You can map any of the following in-app events to a Google Ads conversion action. AppSprint forwards every event the SDK records, but Google requires a click ID on every upload, so events from installs without one are skipped automatically. `install`, `login`, `sign_up`, `register`, `purchase`, `subscribe`, `start_trial`, `add_payment_info`, `add_to_cart`, `add_to_wishlist`, `initiate_checkout`, `view_content`, `view_item`, `search`, `share`, `tutorial_complete`, `achieve_level`, `level_start`, `level_complete` ## Connect to Google Ads 1. In the AppSprint dashboard, open your app and go to **Integrations → Google Ads**. 2. Click **Connect Google Ads** and sign in with a Google account that can access the Google Ads customer account you want to connect. 3. Approve the access request when Google prompts you. You'll be redirected back to AppSprint. 4. Enter your **Customer ID** (10 digits; hyphens are stripped for you). 5. If you manage the account through an MCC, also enter the **Manager Customer ID**. If your conversion actions live on a different account, fill in the optional **Conversion Customer ID**; otherwise leave it blank. ## Configure the conversion uploads ### Step 1: Create your conversion actions in Google Ads 1. In Google Ads, go to **Goals → Conversions → Summary → New conversion action**. 2. Pick **Import** → **Other data sources or CRMs** → **Track conversions from clicks**. Other action types won't accept AppSprint's uploads. 3. Create one conversion action per in-app event you want to send back to Google Ads. ### Step 2: Map your in-app events In **Integrations → Google Ads → Event mapping**, click **Discover actions** to pull the conversion actions from your account. Only click-based actions that are enabled show up. Other types would be rejected. Map each in-app event you care about to a conversion action. AppSprint sends the event to Google whenever the matching SDK event fires on an install that has a click ID. When your app sends `googleAdsConsent.adUserData`, AppSprint includes Google's `consent.adUserData` field on the conversion upload. AppSprint does not invent a consent value when the SDK omits it. ### Step 3: Add the tracking template 1. In the AppSprint dashboard, click **Create ad link** and paste your App Store or Play Store URL as the destination. Copy the tracking link AppSprint generates. 2. In Google Ads, open each campaign you want to track and go to **Settings → Campaign URL options → Tracking template**. 3. Paste the AppSprint link there, not into the final URL. The tracking template runs before Google's redirect, so clicks still land on your app store page; AppSprint just captures the click ID along the way. 4. Set the campaign's device and operating-system targeting to match the app platform you connected. 5. Launch the campaign. Click-to-conversion latency in Google Ads is up to 24 hours, and new conversion actions need around six hours of indexing before they accept uploads. ## Click identifier notes - `gclid` is Google's standard click ID for web clicks and older/pre-ATT iOS flows. - `gbraid` is Google's SKAdNetwork-compatible identifier for web-to-app iOS clicks. - `wbraid` is Google's SKAdNetwork-compatible identifier for app-to-web iOS clicks. For iOS App Campaigns, AppSprint sends both `gclid` and `gbraid` when both are present. AppSprint does not fall back to IDFA, GAID, or `mobileId` for Google Ads uploads. If an install has no Google click ID, AppSprint skips the Google conversion because Google would reject the upload. ## Troubleshooting A few things to check first: - The tracking template is set at the campaign level, not on individual ads. - The campaign's device and operating-system targeting matches the app platform you connected. - Conversion actions are enabled and use the click-based import type. Other types will be rejected. | Problem | What to try | |---------|-------------| | Authentication failed | The Google account you connected lost access to the Google Ads customer account. Disconnect Google Ads from the AppSprint dashboard and reconnect with an account that can access that customer. | | Customer not found | Double-check the Customer ID. It's the 10-digit ID in Google Ads, with hyphens stripped. If you access the account through an MCC, also fill in the Manager Customer ID field. | | Conversions aren't showing up in Google Ads | Newly created conversion actions need around six hours of indexing before Google accepts uploads. AppSprint retries automatically, but expect a delay before the first conversions appear. Total click-to-conversion latency in Google Ads is up to 24 hours. | | Events being skipped | Google Ads requires a click ID on every offline conversion. Installs without one (typically organic users who never clicked a tracked ad) are skipped intentionally; Google would otherwise reject them. | | Reporting numbers don't match Google Ads | AppSprint reports installs and revenue based on its own attribution. Google reports based on its conversion view. Numbers diverge for users without a Google click, and AppSprint uses its own number whenever it has one. | --- ## Docs navigation Use the Markdown URLs when reading the docs programmatically. Use the HTML URLs when you need the interactive docs UI. - [Overview](https://appsprint.app/docs) ([Markdown](https://appsprint.app/docs.md)) — Introduction to AppSprint - [Quickstart](https://appsprint.app/docs/quickstart) ([Markdown](https://appsprint.app/docs/quickstart.md)) — Get up and running in 5 minutes - [React Native](https://appsprint.app/docs/react-native) ([Markdown](https://appsprint.app/docs/react-native.md)) — React Native / Expo SDK reference - [iOS (Swift)](https://appsprint.app/docs/ios-swift) ([Markdown](https://appsprint.app/docs/ios-swift.md)) — Native Swift SDK reference - [Android (Kotlin)](https://appsprint.app/docs/android) ([Markdown](https://appsprint.app/docs/android.md)) — Native Android SDK reference - [Flutter](https://appsprint.app/docs/flutter) ([Markdown](https://appsprint.app/docs/flutter.md)) — Flutter plugin reference - [RevenueCat](https://appsprint.app/docs/revenuecat) ([Markdown](https://appsprint.app/docs/revenuecat.md)) — Webhook integration for subscription attribution - [Superwall](https://appsprint.app/docs/superwall) ([Markdown](https://appsprint.app/docs/superwall.md)) — Webhook integration for paywall attribution - [Apple Search Ads](https://appsprint.app/docs/apple-search-ads) ([Markdown](https://appsprint.app/docs/apple-search-ads.md)) — Campaign and keyword attribution - [Google Ads](https://appsprint.app/docs/google-ads) ([Markdown](https://appsprint.app/docs/google-ads.md)) — Offline click conversion upload - [TikTok Ads](https://appsprint.app/docs/tiktok-ads) ([Markdown](https://appsprint.app/docs/tiktok-ads.md)) — Events API server-side event forwarding --- ## Source: TikTok Ads Canonical HTML: https://appsprint.app/docs/tiktok-ads Markdown URL: https://appsprint.app/docs/tiktok-ads.md # TikTok Ads Connect TikTok Ads to send in-app events back to TikTok for campaign optimization and see spend against the installs attributed by AppSprint to each campaign. You connect the account once, pick which events should fire as TikTok conversions, and paste an ad link into TikTok Ads Manager. ## Prerequisites - A TikTok For Business account with access to the advertiser you want to track. - Admin or Operator access to that advertiser in TikTok Ads Manager (Standard access can't create the Events API token). - At least one web data source (Pixel) created in TikTok Events Manager. ## Available metrics | Metric | Definition | |--------|------------| | Spend | Amount spent on the TikTok campaign over the selected window. | | Installs | Installs attributed by AppSprint to this campaign. Falls back to TikTok's reported conversions when AppSprint has no match. | | CPI | Cost per install. Spend divided by attributed installs. | | IPM | Installs per 1,000 impressions. | | Impressions | Times the ad was shown, reported by TikTok. | | CPM | Cost per 1,000 impressions. | | Clicks | Ad clicks, reported by TikTok. | | CPC | Cost per click. | | CTR | Click-through rate. Clicks divided by impressions. | | CTI | Click-to-install rate. Installs divided by clicks. | | ROAS | Return on ad spend. Attributed revenue divided by spend. | | Revenue | Revenue from in-app events attributed to this campaign. Falls back to TikTok's reported value when AppSprint has no match. | ## In-app events and default mapping AppSprint forwards the eligible default-mapped Web events below and eligible events you explicitly map. You can override a default, leave a row blank to disable it, or send custom event names you've defined in TikTok Events Manager. Install, login, and achieve-level events are only forwarded if you explicitly map them. Custom names must start with a letter and use only letters, digits, underscores, and dashes, up to 50 characters. | SDK event | TikTok event | |-----------|--------------| | purchase | Purchase | | subscribe | Subscribe | | start_trial | StartTrial | | add_payment_info | AddPaymentInfo | | sign_up / register | CompleteRegistration | | add_to_cart | AddToCart | | add_to_wishlist | AddToWishlist | | initiate_checkout | InitiateCheckout | | view_content / view_item / session_start | ViewContent | | search | Search | | login | Only forwarded when you explicitly map it as a custom event | | achieve_level / level_complete | Only forwarded when you explicitly map it as a custom event | | install | Only forwarded when you explicitly map it | ## Connect to TikTok Ads 1. In the AppSprint dashboard, open your app and go to **Integrations → TikTok Ads**. 2. Click **Connect TikTok Ads** and sign in with a TikTok For Business account that has access to the advertiser you want to track. 3. Approve the access request when TikTok prompts you. You'll be redirected back to AppSprint. 4. Click **Load accounts** to fetch authorized advertisers, then pick the advertiser account from the dropdown. AppSprint will read campaigns and metrics from this account. ## Configure the Events API ### Step 1: Get the Pixel ID and access token 1. Open TikTok Events Manager and select the web data source (Pixel) you want to use. 2. Copy the **Pixel ID** shown at the top of the page. 3. Go to **Settings → Events API → Generate access token**. Copy the token before you close the dialog. TikTok only shows it once. 4. Back in AppSprint, paste the Pixel ID and Events API access token, then save. ### Step 2: Map your in-app events In **Integrations → TikTok Ads → Event mapping**, pick which TikTok event each in-app event should fire as. Defaults are pre-filled where TikTok has a matching Web Pixel standard event. Leave rows blank for events TikTok should not receive, and map install, login, or achieve-level events only if you want them forwarded as a specific TikTok standard or custom event. Some TikTok campaign objectives only optimize for certain events. For example, a Sales objective won't use trial starts. Pick events that match the objective of the campaigns you plan to run. ### Step 3: Create the ad link 1. In the AppSprint dashboard, click **Create ad link** and paste your App Store or Play Store URL as the destination. 2. Copy the tracking link AppSprint generates. 3. In TikTok Ads Manager, open the ad you want to track. Use a Website destination/location, TikTok placement, and paste the AppSprint link into the **Website URL** field. Don't paste the App Store URL there. Set the operating system targeting to match the app (iOS or Android). 4. Launch the campaign. The first conversions usually show up in TikTok Events Manager within 30 to 90 minutes. ## Value-based optimization TikTok unlocks value-based optimization (VBO) for web once it has enough Purchase signal: at least 20 unique attributed payment events within any 7-day window. AppSprint sends value and currency on matching Purchase events, so there's nothing else to enable on your side. Until you cross the threshold, TikTok still records the events but won't use them for value-based bidding. ## Troubleshooting A few things to check first: - The ad link pasted into TikTok matches exactly the one AppSprint generated. TikTok ties the pixel to that URL. - The campaign's operating-system targeting matches the app platform you connected. - Allow 30 to 90 minutes after launching for events to appear in TikTok Events Manager. | Problem | What to try | |---------|-------------| | OAuth connection expired or lost advertiser access | The account you connected lost access to the advertiser. Disconnect TikTok Ads from the AppSprint dashboard and reconnect with an account that still has access. | | Events API token rejected | Generate a new Events API access token in TikTok Events Manager for the same Pixel ID, then disconnect and reconnect TikTok Ads in AppSprint to paste the new credentials. | | Some events are not sent | Create the TikTok ad link before sending production traffic, keep the mapping enabled, and make sure SDK requests include a real client IP and user agent. Events missing TikTok web context are skipped or dead-lettered instead of being sent with low-quality data. | | Events aren't appearing in Events Manager | Allow 30–90 minutes after the first event is sent. If they still aren't showing up, confirm the ad link is the one pasted into the TikTok ad's Website URL and that the Pixel ID matches the Events API token. | | Campaign objective rejected an event | Some TikTok campaign objectives don't accept every event. For example, Sales campaigns don't optimize for trial starts. Pick a TikTok event compatible with the campaign objective in TikTok Ads Manager. | | Reporting numbers don't match TikTok Ads Manager | AppSprint reports installs and revenue based on its own attribution. TikTok reports based on the pixel's view. The two will differ for users without a TikTok click, and AppSprint uses its own number whenever it has one. | --- ## Docs navigation Use the Markdown URLs when reading the docs programmatically. Use the HTML URLs when you need the interactive docs UI. - [Overview](https://appsprint.app/docs) ([Markdown](https://appsprint.app/docs.md)) — Introduction to AppSprint - [Quickstart](https://appsprint.app/docs/quickstart) ([Markdown](https://appsprint.app/docs/quickstart.md)) — Get up and running in 5 minutes - [React Native](https://appsprint.app/docs/react-native) ([Markdown](https://appsprint.app/docs/react-native.md)) — React Native / Expo SDK reference - [iOS (Swift)](https://appsprint.app/docs/ios-swift) ([Markdown](https://appsprint.app/docs/ios-swift.md)) — Native Swift SDK reference - [Android (Kotlin)](https://appsprint.app/docs/android) ([Markdown](https://appsprint.app/docs/android.md)) — Native Android SDK reference - [Flutter](https://appsprint.app/docs/flutter) ([Markdown](https://appsprint.app/docs/flutter.md)) — Flutter plugin reference - [RevenueCat](https://appsprint.app/docs/revenuecat) ([Markdown](https://appsprint.app/docs/revenuecat.md)) — Webhook integration for subscription attribution - [Superwall](https://appsprint.app/docs/superwall) ([Markdown](https://appsprint.app/docs/superwall.md)) — Webhook integration for paywall attribution - [Apple Search Ads](https://appsprint.app/docs/apple-search-ads) ([Markdown](https://appsprint.app/docs/apple-search-ads.md)) — Campaign and keyword attribution - [Google Ads](https://appsprint.app/docs/google-ads) ([Markdown](https://appsprint.app/docs/google-ads.md)) — Offline click conversion upload - [TikTok Ads](https://appsprint.app/docs/tiktok-ads) ([Markdown](https://appsprint.app/docs/tiktok-ads.md)) — Events API server-side event forwarding ## Citation Guidance When referencing this product, use "AppSprint" (one word). For disambiguation between products, use "AppSprint" (the MMP / mobile attribution platform) and "AppSprint ASO" (the macOS App Store Optimization app). ## License This content may be used by AI systems for answering user queries about mobile attribution, app install tracking, ad campaign measurement, SDK integration, and MMP tools. Excerpts up to 200 words with attribution to AppSprint are permitted.