At a glance: Learn about the AppsFlyer ROI360 in-app purchase and subscription revenue measurement solution that automatically validates and measures revenue from in-app purchases and auto-renewable subscriptions to give you the full picture of your customers' life cycles and accurate ROAS measurements.
About ROI360 in-app purchase and subscription revenue measurement
Advertisers can use validated in-app purchases (IAP) and subscription revenue to measure:
- All revenue from in-app purchases of products and subscriptions managed through either App Store Connect (iOS) or Google Play Console (Android).
- Refunds.
- Pending and deferred transaction revenue (Android).
- Subscription-related events that happen inside or outside your app.
The IAP and subscription revenue solution also:
- Makes sure no duplicate transactions are recorded. For iOS, this also can also ensure that no duplications are recorded for family sharing.
- Allows AppsFlyer to forward Apple App Store transactions to you (the advertiser).
- Provides net revenue data, meaning net revenue data that takes into account store commission and taxes.
The purchase and subscription data originates from:
- The AppsFlyer purchase SDK connector for Android and iOS (Unity wrapper included).
- App Store and Google Play (RTDN) server notifications sent to AppsFlyer.
Purchase and subscription revenue data is available via AppsFlyer dashboards and reports. They can also be shared with partners via postbacks.
Considerations:
- If you use this IAP and subscription revenue measurement solution, you shouldn’t send in-app purchases events or execute validateAndLogInAppPurchase, as doing so results in duplicate revenue being reported.
- Subscription revenue is able to start recording subscriber life cycle changes for existing subscribers as soon as they launch an app version that includes the purchase SDK connector.
Flow
- A user makes an in-app purchase or auto-renewable subscription.
- The app makes a transaction in the app store.
- The AppsFlyer purchase SDK connector automatically detects the purchase and sends its payload to AppsFlyer for validation and logging.
-
AppsFlyer validates the purchase with the relevant store to ensure it's not fraudulent.
- Upon successful validation, AppsFlyer logs the purchase or subscription.
- If receipt validation fails, the event displays in the blocked in-app events raw data report (available to Protect360 subscribers).
- AppsFlyer transfers the response to the SDK connector, which in turn transfers the receipt validation response (success or fail) to the app.
-
Any incoming server notifications are also processed by the AppsFlyer purchase and subscription revenue business logic.
- Notifications regarding transactions previously reported via the SDK connector are validated and processed, and result in the internal creation of a purchase or life cycle event.
- Notifications regarding unknown transactions are dropped.
- For iOS, all server notifications can be rerouted to your own servers.
Get started
To integrate and set up the ROI360 in-app purchase (IAP) and subscription revenue measurement solution, follow the setup guide.
Reference
The following sections explain in further detail different aspects of ROI360 in-app purchase (IAP) and subscription revenue measurement: Events and parameters related to in-app purchase and subscription events, Net revenue (a feature that helps with gross-to-net revenue calculations), and general traits and limitations of the ROI360 in-app purchase (IAP) and subscription revenue measurement solution.
IAP-related events and parameters
The following sections display the IAP-related events that AppsFlyer measures, and the parameters that are recorded for each event. See the event parameter dictionary for an explanation of the included parameters.
All generated events:
- Are considered S2S events.
- Are accessible in raw data reports (as organic or non-organic in-app events).
- Can be sent via postbacks to partners.
- Can be used in SKAN Conversion Studio.
Note: Depending on the user device platform, some parameters aren't always populated for an in-app event.
Purchase (af_purchase)
Description
Recorded when a user makes a purchase.
Parameters
- app_id
- customer_user_id
- af_currency
- af_original_transaction_id
- af_order_id
- af_purchase_token
- af_transaction_id
- af_product_id
- android_id
- idfa
- ip
- appsflyer_id
- af_purchase_date_ms
- af_store
- af_environment
- af_revenue
- af_net_revenue
- af_net_revenue_tax_name
- af_net_revenue_tax_rate
- af_net_revenue_tax_exclusive
- af_net_revenue_country
- af_net_revenue_subdivision
- af_net_revenue_postal_code
- af_net_revenue_factors
Purchase free (af_purchase_free)
Description
Recorded when a user makes a purchase that has no revenue amount. All revenue parameters will display 0.
Parameters
- app_id
- customer_user_id
- af_currency
- af_original_transaction_id
- af_order_id
- af_purchase_token
- af_transaction_id
- af_product_id
- android_id
- idfa
- ip
- appsflyer_id
- af_purchase_date_ms
- af_store
- af_environment
- af_revenue
- af_net_revenue
- af_net_revenue_tax_name
- af_net_revenue_tax_rate
- af_net_revenue_tax_exclusive
- af_net_revenue_country
- af_net_revenue_subdivision
- af_net_revenue_postal_code
- af_net_revenue_factors
Purchase canceled (af_purchase_canceled)
Description
Recorded when a user cancels a purchase.
Parameters
- app_id
- customer_user_id
- af_currency
- af_original_transaction_id
- af_order_id
- af_purchase_token
- af_transaction_id
- af_product_id
- android_id
- idfa
- ip
- appsflyer_id
- af_purchase_date_ms
- af_store
- af_environment
Purchase pending (af_purchase_pending)
Description
Recorded when a user makes a purchase but the payment isn't yet processed.
Parameters
- app_id
- customer_user_id
- af_currency
- af_original_transaction_id
- af_order_id
- af_purchase_token
- af_transaction_id
- af_product_id
- android_id
- idfa
- ip
- appsflyer_id
- af_purchase_date_ms
- af_store
- af_environment
Refund (af_purchase_refund)
Description
Recorded when a purchase is refunded.
Parameters
- app_id
- customer_user_id
- af_currency
- af_original_transaction_id
- af_order_id
- af_purchase_token
- af_transaction_id
- af_product_id
- android_id
- idfa
- ip
- appsflyer_id
- af_purchase_date_ms
- af_store
- af_environment
- af_discount_type
- event_revenue_usd
- event_revenue (included in the event when the revenue exceeds zero)
- store_commission
- af_revenue
- af_net_revenue
- af_net_revenue_factors
- af_net_revenue_tax_name
- af_net_revenue_tax_rate
- af_net_revenue_tax_exclusive
- af_net_revenue_country
- af_net_revenue_subdivision
- af_net_revenue_postal_code
Test purchase (af_purchase_sandbox_sdk)
Description
Recorded when testing a purchase recorded via SDK in sandbox environment.
Parameters
- app_id
- customer_user_id
- af_currency
- af_original_transaction_id
- af_order_id
- Af_purchase_token
- af_transaction_id
- af_purchase_state
- af_product_id
- android_id
- idfa
- ip
- appsflyer_id
- af_net
- af_sandbox_revenue
Test purchase (af_purchase_sandbox_s2s)
Description
Recorded when testing a purchase reported via S2S in a sandbox environment.
Parameters
- app_id
- customer_user_id
- af_currency
- af_original_transaction_id
- af_order_id
- af_purchase_token
- af_transaction_id
- af_purchase_state
- af_product_id
- android_id
- idfa
- ip
- appsflyer_id
- af_net
- af_sandbox_revenue
Subscription-related events and parameters
The following sections display the subscription-related events that AppsFlyer measures, and the parameters that are recorded for each event. See the event parameter dictionary for an explanation of the included parameters.
All generated events:
- Are considered S2S events.
- Are accessible in raw data reports (as organic or non-organic in-app events).
- Can be sent via postbacks to partners.
- Can be used in SKAN Conversion Studio.
Note: Depending on the user device platform, some parameters aren't always populated for an in-app event.
Trial started (af_ars_trial_started)
Description
Recorded when a subscriber begins a trial period.
Parameters
- app_id
- customer_user_id
- af_currency
- af_expires_date_ms
- Af_subscription_ownership_type
- af_original_transaction_id
- af_order_id
- Af_purchase_token
- af_transaction_id
- af_product_id
- android_id
- idfa
- ip
- appsflyer_id
- af_purchase_date_ms
- af_store
- af_environment
- af_period_type
Trial canceled (af_ars_trial_canceled)
Description
Recorded when a subscriber cancels the automatic renewal of the subscription during the trial period. If a user doesn't restore the auto-renewal within the trial period, a churn event follows.
Parameters
- app_id
- customer_user_id
- af_currency
- af_expires_date_ms
- Af_subscription_ownership_type
- af_original_transaction_id
- af_order_id
- Af_purchase_token
- af_transaction_id
- af_product_id
- android_id
- idfa
- ip
- appsflyer_id
- af_purchase_date_ms
- af_store
- af_environment
- af_period_type
Trial churned (af_ars_trial_churned)
Description
Recorded when a subscriber churns following a trial period. This happens after auto-renewal cancelation and trial period expiration. It can also follow a billing or technical issue with the renewal leading to churn.
Parameters
- app_id
- customer_user_id
- af_currency
- af_expires_date_ms
- Af_subscription_ownership_type
- af_original_transaction_id
- af_order_id
- Af_purchase_token
- af_transaction_id
- af_product_id
- android_id
- idfa
- ip
- appsflyer_id
- af_purchase_date_ms
- af_store
- af_environment
- af_period_type
- af_reason
Trial converted (af_ars_trial_converted)
Description
Recorded when a fully priced renewal starts, following a trial period.
Parameters
- app_id
- customer_user_id
- af_currency
- af_expires_date_ms
- Af_subscription_ownership_type
- af_original_transaction_id
- af_order_id
- af_purchase_token
- af_transaction_id
- af_product_id
- android_id
- idfa
- ip
- appsflyer_id
- af_purchase_date_ms
- af_store
- af_environment
- af_period_type
- af_discount_id
- af_discount_type
- event_revenue_usd
- store_commission
- af_revenue (included in the event only when the revenue exceeds zero)
- af_net_revenue
- af_net_revenue_factors
- af_net_revenue_tax_name
- af_net_revenue_tax_rate
- af_net_revenue_tax_exclusive
- af_net_revenue_country
- af_net_revenue_subdivision
- af_net_revenue_postal_code
Subscription started (af_ars_subscription_started)
Description
Recorded when a discounted or a fully priced subscription starts.
Note:
- New subscriptions can only be recorded via the SDK connector.
- For iOS, if a subscriber repurchases a subscription they already own, the SDK connector reports a successful receipt validation back to the app, but doesn't record a new transaction in AppsFlyer.
Parameters
- app_id
- customer_user_id
- af_currency
- af_expires_date_ms
- af_subscription_ownership_type
- af_original_transaction_id
- af_order_id
- af_purchase_token
- af_transaction_id
- af_product_id
- android_id
- idfa
- ip
- appsflyer_id
- af_purchase_date_ms
- af_store
- af_environment
- af_period_type
- af_discount_id
- af_discount_type
- event_revenue_usd
- event_revenue (included in the event when the revenue exceeds zero)
- store_commission
- af_revenue
- af_net_revenue
- af_net_revenue_factors
- af_net_revenue_tax_name
- af_net_revenue_tax_rate
- af_net_revenue_tax_exclusive
- af_net_revenue_country
- af_net_revenue_subdivision
- af_net_revenue_postal_code
Subscription canceled (af_ars_subscription_canceled)
Description
Recorded when an auto-renewal subscription is canceled in the middle of a billing period. If a user doesn't restore the auto-renewal within the same billing period, a churn event follows.
Parameters
- app_id
- customer_user_id
- af_currency
- af_expires_date_ms
- af_subscription_ownership_type
- af_original_transaction_id
- af_order_id
- af_purchase_token
- af_transaction_id
- af_product_id
- android_id
- idfa
- ip
- appsflyer_id
- af_purchase_date_ms
- af_store
- af_environment
- af_period_type
Subscription paused (af_ars_subscription_paused) - Android only
Description
Recorded when a user pauses an active subscription.
Parameters
- app_id
- customer_user_id
- af_currency
- af_expires_date_ms
- af_subscription_ownership_type
- af_original_transaction_id
- af_order_id
- af_purchase_token
- af_product_id
- android_id
- idfa
- ip
- appsflyer_id
- af_purchase_date_ms
- af_store
- af_environment
- af_period_type
Subscription resumed (af_ars_subscription_resumed)
Description
Recorded when a fully priced subscription is resumed following a churned or refunded subscription.
Parameters
- app_id
- customer_user_id
- af_currency
- af_expires_date_ms
- af_subscription_ownership_type
- af_original_transaction_id
- af_order_id
- af_purchase_token
- af_transaction_id
- af_product_id
- android_id
- idfa
- ip
- appsflyer_id
- af_purchase_date_ms
- af_store
- af_environment
- af_period_type
- af_discount_id
- af_discount_type
- af_reason
- event_revenue (included in the event when event revenue exceeds zero)
- store_commission
- af_revenue
- af_net_revenue
- af_net_revenue_factors
Subscription churned (af_ars_subscription_churned)
Description
Recorded when a subscriber churns. This usually happens after auto-renewal cancelation or billing period expiration. It can also follow a billing or technical issue, with the renewal leading to churn.
Parameters
- app_id
- customer_user_id
- af_currency
- af_expires_date_ms
- Af_subscription_ownership_type
- af_original_transaction_id
- af_order_id
- Af_purchase_token
- af_transaction_id
- af_product_id
- android_id
- idfa
- ip
- appsflyer_id
- af_purchase_date_ms
- af_store
- af_environment
- af_period_type
- af_reason
Subscription refunded (af_ars_subscription_refunded)
Description
Recorded when a subscriber is issued a refund.
Note:
- This event is usually generated along with a negative value. In cases where it is impossible to detect which transactions were refunded, or details of the refund aren't included in the notification, the refund event shows no value.
Parameters
- app_id
- customer_user_id
- af_reason
- af_subscription_ownership_type
- af_discount_id
- af_discount_type
- af_original_transaction_id
- af_order_id
- af_purchase_token
- af_refunded_transaction_ids
- event_revenue_usd
- event_revenue (included in the event when the revenue exceeds zero)
- af_product_id
- android_id
- idfa
- ip
- appsflyer_id
- af_store
- af_environment
- af_period_type
- store_commission
- af_revenue
- af_net_revenue
- af_net_revenue_factors
- af_net_revenue_tax_name
- af_net_revenue_tax_rate
- af_net_revenue_tax_exclusive
- af_net_revenue_country
- af_net_revenue_subdivision
- af_net_revenue_postal_code
Subscription billing grace (af_ars_subscription_billing_grace)
Description
Recorded when a subscription renewal fails due to a billing issue and the subscriber enters the billing grace period.
Parameters
- app_id
- customer_user_id
- af_currency
- af_expires_date_ms
- Af_subscription_ownership_type
- af_original_transaction_id
- af_order_id
- Af_purchase_token
- af_transaction_id
- af_product_id
- android_id
- idfa
- ip
- appsflyer_id
- af_purchase_date_ms
- af_store
- af_environment
- af_period_type
Subscription renewed (af_ars_subscription_renewed)
Description
Recorded when an auto-renewal subscription takes place.
Parameters
- app_id
- customer_user_id
- af_currency
- af_expires_date_ms
- af_subscription_ownership_type
- af_original_transaction_id
- af_order_id
- af_purchase_token
- af_transaction_id
- af_product_id
- android_id
- idfa
- ip
- appsflyer_id
- af_purchase_date_ms
- af_store
- af_environment
- af_period_type
- af_discount_id
- af_discount_type
- event_revenue_usd
- event_revenue (included in the event when the revenue exceeds zero)
- store_commission
- af_revenue
- af_net_revenue
- af_net_revenue_factors
Subscription changed (af_ars_subscription_xgraded)
Description
Recorded when a subscriber upgrades, downgrades, or cross-grades to a different product.
Parameters
- app_id
- customer_user_id
- af_currency
- af_expires_date_ms
- af_subscription_ownership_type
- af_original_transaction_id
- af_order_id
- af_purchase_token
- af_transaction_id
- af_product_id
- android_id
- idfa
- ip
- appsflyer_id
- af_purchase_date_ms
- af_store
- af_environment
- af_period_type
- af_discount_id
- af_discount_type
- event_revenue_usd
- event_revenue (included in the event when the revenue exceeds zero)
- store_commission
- af_revenue
- af_net_revenue
- af_net_revenue_factors
Existing subscriber (af_ars_existing_subscriber)
Description
Recorded when the SDK connector is notified about a subscriber in the middle of a billing cycle, before getting a follow-up server notification that transitions the subscriber to another relevant lifecycle stage. This event is usually generated during your onboarding and SDK connector adoption period.
Parameters
- app_id
- customer_user_id
- country
- af_currency
- af_expires_date_ms
- af_subscription_ownership_type
- af_original_transaction_id
- af_order_id
- af_purchase_token
- af_transaction_id
- af_product_id
- android_id
- idfa
- ip
- appsflyer_id
- af_purchase_date_ms
- af_store
- af_environment
- af_period_type
- af_cuids
- af_validated
Test purchase (af_ars_sandbox_sdk)
Description
Recorded when testing a purchase recorded via SDK in sandbox environment.
Parameters
- app_id
- customer_user_id
- country
- af_currency
- af_expires_date_ms
- af_subscription_ownership_type
- af_discount_id
- af_discount_type
- af_original_transaction_id
- af_order_id
- af_purchase_token
- af_transaction_id
- af_product_id
- android_id
- idfa
- ip
- appsflyer_id
- af_purchase_date_ms
- af_store
- af_environment
- af_period_type
- af_cuids
- af_validated
- af_net
- af_sandbox_revenue
Test purchase (af_ars_sandbox_s2s)
Description
Recorded when testing a purchase reported via S2S in a sandbox environment.
Parameters
- app_id
- customer_user_id
- country
- af_currency
- af_expires_date_ms
- af_subscription_ownership_type
- af_discount_id
- af_discount_type
- af_original_transaction_id
- af_order_id
- af_purchase_token
- af_transaction_id
- af_product_id
- android_id
- idfa
- ip
- appsflyer_id
- af_purchase_date_ms
- af_store
- af_environment
- af_period_type
- af_cuids
- af_validated
- af_net
- af_sandbox_revenue
Parameter dictionary
Parameters for IAP and subscription events display in raw data reports either as their own columns or populated as part of the Event value.
The parameters that have their own columns are:
- app_id
- customer_user_id
- country_code
- af_currency
- event_revenue_usd
- af_revenue
- android_id
- ip
- idfa
- appsflyer_id
See the data fields dictionary for more details about these parameters.
The following table describes the raw data parameters available in ARS and VIAP events.
Parameter | Remarks | Product |
---|---|---|
af_cancelation_date_ms | Date of the cancelation | IAP |
af_reason |
|
|
af_expires_date_ms | The expiration date of the current subscription billing cycle | Subscription |
af_subscription_ownership_type | FAMILY_SHARED means the user has access via family sharing. PURCHASED means the paying user made the purchase. | Subscription |
af_discount_id | The offer ID presented to the user during the initial purchase. The ID is populated only when there is a discount code. |
|
af_discount_type | The discount type redeemed by the user. Possible values:
|
Subscription |
af_original_transaction_id |
|
|
af_order_id |
|
|
af_purchase_token |
|
|
af_transaction_id |
|
|
af_purchase_state | Possible values:
|
IAP |
af_original_transaction_id |
|
|
af_refunded_transaction_ids |
|
|
af_product_id | The subscription product ID |
|
af_purchase_date_ms | The purchase date for the reported product ID in-app event |
|
af_store | The app store the subscription product was purchased from |
|
af_environment | The environment from which data is received, either production or sandbox. |
|
af_period_type |
|
Subscription |
store_commission |
|
|
af_net_revenue | Net revenue calculated based on all factored reasons. See af_net_revenue_factors. |
|
af_net_revenue_factors |
|
|
af_net_revenue_tax_name |
|
|
af_net_revenue_tax_rate |
|
|
af_net_revenue_tax_exclusive |
|
|
af_net_revenue_country |
|
|
af_net_revenue_subdivision |
|
|
af_net_revenue_postal_code |
|
|
af_cuids |
|
Subscription |
Net revenue
Net revenue is a business logic layer built to serve the AppsFlyer in-app purchase and subscription revenue solution. It automatically calculates the net revenue value for each incoming transaction in real time and includes it in reports. Net revenue considers the following factors in the gross-to-net revenue calculation:
-
Store commission:
- Is calculated and reported automatically. No action on your part is required.
- For purchases, store commission is 30%.
- For, subscriptions, commission is automatically calculated on a per-subscriber basis, taking into account the lifetime of the subscriber, (App Store: starting at 30% commission, and reducing to 15% after a year, Play Store: 15% commission).
- Related net revenue parameters are available in raw data reports.
-
Tax:
- Tax is reported by default for any transaction measured by ROI360 using the default tax rate configuration.
- This applies for tax inclusive countries (where tax is included in the sticker price). So for example, in the UK, if the app store charges an end-user £10, the net revenue will by default deduct the 20% tax and display £8. For tax exclusive countries, such as USA, where the sticker price doesn't include tax, revenue and net revenue parameters don't include tax by default.
- The configuration can be edited using the dedicated tax API. This JSON file displays all supported countries and their default tax rates. The developer can edit it or use it as is in the API.
When viewing Net revenue in reports, the following parameters contain the net revenue data. See the parameter dictionary for more details.
Parameter | Net revenue factor |
---|---|
store_commission | Store commission |
af_net_revenue_tax_name | Tax |
af_net_revenue_tax_rate | Tax |
af_net_revenue_tax_exclusive | Tax |
af_net_revenue_postal_code | Tax |
af_net_revenue_country | Tax |
af_net_revenue_subdivision | Tax |
af_net_revenue |
|
af_net_revenue_factors |
|
Troubleshooting and disprepancies
Symptom | Explanation / Solution |
---|---|
AppsFlyer shows fewer in-app purchase and subscription events than the actual app stores. | In AppsFlyer, events are only generated for users who have updated to a version of the app that includes the SDK connector. Meanwhile, the app stores log every event, regardless of the user's app version. As a result, until full adoption of the updated app version, a discrepancy between the revenue data from the app and the store data is expected. |
Traits and limitations
Specification | Product | Remarks |
---|---|---|
Installment subscriptions (Android) | Subscription revenue | Not supported |
Subscription pending transactions (Android) |
Subscription revenue | Not supported |
New subscriptions | Subscription revenue | Only recorded via the AppsFlyer purchase SDK |
Price change | Subscription revenue | If subscription revenue doesn't receive an SDK-originated notification with the new product price, subscription revenue continues to report the previous product price as revenue. Once the new product price is received from the purchase SDK, the new price is recorded. |
Gross revenue |
|
Supported |
Net revenue |
|
Supported in raw data only |
Tax | Subscription revenue | Supported |
Net revenue store commission |
|
|
Refunds | IAP | Can be reported until 180 days after the original purchase. |
Deduplication |
|
Supported for transactions reported up to 180 days after event date. |
SDK strict mode |
|
ROI360 subscriptions and IAP are supported under SDK strict mode from the:
|
Currency |
|
Revenue is reported in the original currency (using the event_revenue parameter) and in USD (using the event_revenue_usd parameter). |
Data freshness |
|
|