Wire the call into the success branch of your StoreKit / Billing transaction handler. Use distinct event names per purchase category if you want to differentiate consumables from non-consumables (iap_consumable, iap_nonconsumable). Don't pass the SKU, price, or transaction ID.
▸Install the Swift (iOS) SDK
// Package.swift
dependencies: [
.package(url: "https://github.com/respectlytics/respectlytics-swift.git", from: "3.0.0")
]
// Or via Xcode → File → Add Packages → paste the URL above.
The SDK ships only via Swift Package Manager. CocoaPods and Carthage are not published — fewer integration paths means fewer surfaces to keep audited.
▸Initialize Respectlytics in Swift (iOS)
import Respectlytics
@main
struct MyApp: App {
init() {
Respectlytics.configure(appKey: "<YOUR_APP_KEY>")
}
var body: some Scene { WindowGroup { ContentView() } }
}
Call configure once at app launch — typically in your App struct's init. No Info.plist keys are required: the SDK does not call ATTrackingManager and does not request the IDFA, so NSUserTrackingUsageDescription should NOT be added.
▸Track the event in Swift (iOS)
import Respectlytics
import StoreKit
// One-time / consumable IAP using StoreKit 2:
Task {
let result = try await product.purchase()
if case .success(let verification) = result,
case .verified(let transaction) = verification {
// Distinct event_name per purchase category — not via parameter.
if product.type == .consumable {
Respectlytics.track("iap_consumable")
} else {
Respectlytics.track("iap_nonconsumable")
}
await transaction.finish()
}
}
If you also offer subscriptions, use paywall-conversion / trial-start events for those — iap_* here is for one-time purchases only.
✦Privacy & implementation notes
Consumables (a single in-game gold pack) and non-consumables (a one-time premium upgrade) have very different product implications: consumables drive ARPU directly, non-consumables drive long-term retention. Mixing them under one iap event hides the most useful breakdown.
Always finish the transaction with the platform billing API after firing the analytics event — not before. If your track call were to throw (it doesn't, but defensively), you'd want the platform to keep its retry behavior. Respectlytics's track is a fire-and-forget call into a RAM queue; it never blocks transaction completion.
Apple rejected approximately 3% of apps in 2024 for incorrectly omitting NSUserTrackingUsageDescription when ATT was required by the SDKs they shipped. Respectlytics doesn't trigger ATT. The corollary is also true: do not add the key on Respectlytics's account — its presence implies you track across apps, even if your code never calls requestTrackingAuthorization.
Internally the Swift SDK uses Swift Concurrency: events are queued in an actor-isolated buffer (RAM-only), flushed on a 30-second timer and on UIApplication.willResignActiveNotification. Force-quit before flush drops queued events — by design. There is no UserDefaults or file backing.
⇋How this compares to other analytics SDKs
| In-app purchase event | Firebase Analytics | Mixpanel | Respectlytics |
|---|---|---|---|
| SKU stored | Recommended | Recommended | Use distinct event_name |
| Price / currency stored | Recommended | Recommended | Rejected by API |
| Transaction ID stored | Yes | Yes | Rejected by API |
| Per-user spend total | Yes | Yes | Use billing system |
| Purchase *rate* by country / platform | Yes | Yes | Yes (default) |
❓Frequently asked questions
How do we differentiate consumables from non-consumables?
Distinct event names: iap_consumable, iap_nonconsumable, optionally iap_subscription for subscriptions. Don't embed the type as a parameter — the API rejects parameters.
What about lifetime spend per user?
Out of scope for Respectlytics. Your billing system or RevenueCat already computes lifetime spend per user, with authoritative timestamps and refund-aware totals. Asking your product analytics to do this duplicates a system of record and produces drift.
Do we differentiate purchases by SKU at all?
Only if a SKU breakdown is genuinely actionable for product decisions, and only via distinct event names: iap_gold_pack, iap_starter_bundle. Keep the set small — under 10 SKUs is fine; past that, bucket the long tail.
Should we fire on purchase initiation or completion?
Completion. Initiation-fire inflates the event count with abandoned platform billing prompts. The transaction observer's .purchased state is the right hook.