StoreKit 2 Revenue Tracking: Sending Purchases to an MMP Correctly
Why revenue can drift from App Store Connect after a StoreKit 2 migration, and how to send purchases, renewals and currency to an attribution tool correctly.

Key Takeaway
- StoreKit 2 shifts purchase handling to asynchronous streams, requiring your app to listen for background renewals and completions outside the paywall UI.
- An event is not stored if the semantic attribute transactionID does not match its designated string format, and a value over the 1,024 maximum length is cut short.
- Your subscription setup requires identical user IDs between the Airbridge SDK and RevenueCat, while Adapty can report proceeds after store fees.
StoreKit 2 changed how purchases reach your code: transactions now arrive through the purchase result and Transaction.updates instead of the old payment queue observer. Teams that switch often see analytics revenue drift away from App Store Connect, because renewals, restores and currency are handled differently. When that revenue feeds campaign reports, the drift also hides which ads paid for themselves.
StoreKit 1 vs. StoreKit 2 Transactions
StoreKit 1 relied on a central payment transaction observer (SKPaymentTransactionObserver) that delivered a queue of payment states, often requiring you to send base64-encoded receipts to a server to figure out what a subscriber actually bought. StoreKit 2 replaces that queue with Swift concurrency and signed JSON Web Signature (JWS) transactions. When a user taps purchase on your paywall, Product.purchase() returns a verification result directly to the caller right inside your purchase function.
Because the initial purchase response happens inline, it is easy to put your attribution event call right inside the button action and assume you are done. That inline result only covers what happens while the user is actively staring at the paywall. Promoted in-app purchases started on the App Store product page, Ask to Buy approvals from a family organizer, and automatic subscription renewals never pass through your paywall button logic. If your tracking code only lives inside the direct purchase call, all of those out-of-band transactions happen silently without firing a single event.
Listening to Transaction.updates
Catching every purchase state change requires setting up a background task for Transaction.updates the moment your app launches. If a subscriber's renewal processes while the app is suspended, or a parent approves a child's purchase hours after the paywall was dismissed, StoreKit 2 emits that transaction through the Transaction.updates asynchronous sequence on the next launch.
When you iterate through this stream, inspect the verified transaction before firing a revenue event, and call transaction.finish() only after your purchase logic and event logging have executed. Calling finish() too early tells the operating system the app has processed the transaction, so if the app closes before your attribution event fires, StoreKit 2 will not deliver that transaction to the stream again. At the same time, distinguish between Transaction.updates and Transaction.currentEntitlements. Querying currentEntitlements checks what access the user currently holds when unlocking premium features, so putting attribution tracking inside an entitlement check will fire duplicate revenue events every time the user opens the app.
Preventing Dropped or Duplicate Events
When a user taps "Restore Purchases" on a new phone or an existing subscription renews, your app needs a unique identifier attached to each transaction so you can separate a brand-new charge from a previously recorded one. In Airbridge, the Transaction ID semantic event property uses the transactionID field, has a string type, and has a maximum length of 1,024. If the semantic attribute transactionID does not match its designated format, the event itself is not stored.
Sending Revenue Events with Currency
Subscribers buying from different App Store storefronts pay in their local currencies, and sending raw price numbers without matching currency configuration skews your return on ad spend calculations. If your app processes StoreKit 2 transactions through a subscription management tool, check how currency conversion is handled before the event leaves that platform. When you configure the Adapty integration, for instance, checking the "Report user's currency" option reports revenue in the user's chosen currency; if you leave that option unchecked, it reports revenue in USD. Match this setting to how you monitor your ad spend.
Reconciling with App Store Connect
Even when your StoreKit 2 listener is running cleanly, comparing your attribution dashboard against App Store Connect requires checking how your subscription stack passes data and whether you are looking at gross sales or net proceeds. Airbridge supports subscription revenue aggregation through RevenueCat, Adapty, and Superwall, and receives supported subscription events from RevenueCat and Adapty once their integrations are configured.
When routing StoreKit 2 events through these integrations, check two specific settings to keep your numbers aligned:
- User identity matching: The user IDs logged in the Airbridge SDK and RevenueCat integration must be identical. Sending RevenueCat's App User ID to the Airbridge SDK during events like sign-up and sign-in—which typically happen before a user subscribes—helps match the records across both systems.
- Store fee deductions: App Store Connect displays both total sales and net proceeds after Apple's commission. In your Adapty setup, checking the "Report proceeds" box reports proceeds after App Store or Google Play Store fees are deducted.
FAQS
FAQ
What is included in the Airbridge Core Plan for subscription apps?
The Airbridge Core Plan includes subscription revenue aggregation, Predictive LTV, cost and ad spend aggregation, revenue/funnel/retention/cohort reports, attribution for Google, Meta, Apple Ads, and TikTok ad networks, and up to two third-party integrations.
How much does the Airbridge Core Plan cost?
The Core Plan starts with a 30-day free trial and then costs $40+/mo with 500K data points/month included and $0.0001 per additional data point, with no annual contract and the option to cancel anytime.
Match ad spend to sales
Aggregate subscription revenue from RevenueCat, Adapty, and Superwall.


