At a glance: Use ROI360 store revenue to validate in-app purchases and subscriptions, prevent duplicates, and calculate net revenue.
Important!
ROI360 store revenue is available only to customers on the ROI360 premium plan. To check your plan or upgrade, contact your Customer Success Manager (CSM).
ROI360 store revenue is AppsFlyer’s premium solution for complete and accurate measurement of revenue from in-app purchases and subscriptions. It provides a comprehensive view of the customer life cycle, enabling the accurate measurement of Return On Ad Spend (ROAS).
| Feature | Details |
|---|---|
| Revenue measurement scope |
|
| Revenue validation and accuracy | The solution prevents duplicate transactions from being recorded. On iOS, this also includes preventing duplication caused by Family Sharing. ROI360 store revenue can also forward Apple App Store transaction data directly to advertisers. |
| Data sources |
|
| Reporting and data availability | Revenue data is available in AppsFlyer dashboards and reports and can also be shared with partners through postbacks. |
Warning
When using ROI360 store revenue, do not send in-app purchase events, as this will result in duplicate revenue reporting.
How does ROI360 store revenue work?
- A user makes an in-app purchase or an auto-renewable subscription.
- The app makes a transaction in the app store.
- The AppsFlyer purchase SDK connector automatically detects purchases and sends their payloads 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 in-app event.
- If receipt validation fails, the event displays in the blocked in-app events raw data report (available to Protect360 subscribers) and in the Live events viewer page with parameter
af_validated= false.
- AppsFlyer transfers the response to the SDK connector, which in turn transfers the receipt validation response (success or failure) to the app.
- Any incoming server notifications from the app stores 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.
Activate ROI360 store revenue
To activate ROI360 store revenue measurement, follow these steps:
- In AppsFlyer, from the side menu, open
Settings and under ROI360 select Revenue Settings.
- Open the Purchases & subscriptions tab.
- Under 1 Choose Product type, select ROI360.
- Click Next to continue.
Set up ROI360 store revenue
See the Set up ROI360 store revenue article
Reference
The following sections provide additional details about key aspects of ROI360 in-app purchase (IAP) and subscription revenue measurement. These include events and parameters for IAP and subscription events, Net revenue, which supports gross-to-net revenue calculations, and the general characteristics and limitations of the ROI360 IAP and subscription revenue measurement solution.
Note
To send additional custom parameters with your in-app events, configure a custom data source in the Purchase SDK Connector. This allows you to enrich purchase and subscription events with your own business logic or metadata.
These parameters will be available in the raw data report's custom_data field.
IAP-related events and parameters
The following sections display the IAP-related events that AppsFlyer measures and the parameters recorded for each event. For an explanation of the included parameters, see the event parameter dictionary.
All generated events have the following properties:
Server-to-server (S2S) events.
Available in raw data reports as organic or non-organic in-app events, and included in the Revenue ETL Stores reports.
Sent to partners via postbacks.
Supported in SKAN Conversion Studio.
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_cuids |
|
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_environment | The environment from which data is received, either production or sandbox. |
|
| af_expires_date_ms | The expiration date of the current subscription billing cycle | Subscription |
| af_net_revenue | Net revenue calculated based on all factored reasons. See af_net_revenue_factors. |
|
| af_net_revenue_country |
|
|
| af_net_revenue_factors |
|
|
| af_net_revenue_postal_code |
|
|
| af_net_revenue_subdivision |
|
|
| af_net_revenue_tax_exclusive |
|
|
| af_net_revenue_tax_name |
|
|
| af_net_revenue_tax_rate |
|
|
| af_offer_id |
|
|
| af_order_id |
|
|
| af_original_transaction_id |
|
|
| af_original_transaction_id |
|
|
| af_period_type |
|
Subscription |
| af_product_id | The subscription product ID |
|
| af_purchase_date_ms | The purchase date for the reported product ID in-app event |
|
| af_purchase_option_id |
|
IAP |
| af_purchase_option_type |
The purchase option type of the transaction. Possible values (Android):
|
IAP |
| af_purchase_state |
Possible values:
|
IAP |
| af_purchase_token |
|
|
| af_reason | [content unchanged] |
|
| af_refunded_transaction_ids |
|
|
| af_store | The app store the subscription product was purchased from |
|
| af_subscription_ownership_type | FAMILY_SHARED means the user has access via family sharing. PURCHASED means the paying user made the purchase. | Subscription |
| af_transaction_id |
|
|
| store_commission |
|
|
Net revenue
Net revenue is a business logic layer built to serve the ROI360 Store revenue solution. It automatically calculates the net revenue value for each incoming transaction in real time and includes it in reports.
Note
Net revenue is displayed in raw data reports and can be sent in real time via in-app event postbacks. The dashboards only display gross revenue of purchases and subscriptions.
To send net revenue in postbacks, configure the in-app event with the option Values, revenue & net revenue. See In-app event postback configuration for details.
Tip
You can also configure your in-app event postbacks to send net revenue in place of gross revenue in the standard revenue (monetary) parameter. To get access to this configuration, contact your Customer Success Manager (CSM).
Net revenue considers the following factors in the gross-to-net revenue calculation:
-
Store commission:
- It is calculated and reported automatically. No action is required on your part.
- For purchases (IAP), the default store commission depends on the storefront:
- App Store — Japan: 26%. China mainland (CN): 25%. Rest of the world: 30%.
- Play Store: 30%.
- For subscriptions, the commission is automatically calculated per subscriber, based on the subscriber's lifetime.
- App Store — first 12 months: 26% in Japan, 25% in China mainland (CN), 30% in the rest of the world. From the 13th month: 15% in Japan, 12% in China mainland (CN), 15% in the rest of the world.
- Play Store: 15% from day one.
- Related net revenue parameters are available in raw data reports.
- Use the Net revenue API to set a different store commission rate than the default. This is useful, for example, if your app is enrolled in Apple's Small Business Program, where the commission rate is 15% (12% in China mainland (CN)).
-
Tax:
- Tax is reported by default for any transaction measured by ROI360 using the default tax rate configuration.
- This applies to tax-inclusive countries (where tax is included in the list price). So, for example, in the UK, AppsFlyer deducts the sum of the tax and the store commission. For tax-exclusive countries, such as the USA, where the list price does not include tax, revenue and net revenue parameters do not include tax by default.
- The configuration can be edited using the Net revenue API. To learn which countries are supported and their default tax rates, see this JSON file. 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 |
| 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 |
|
|
| StoreKit 2 |
|
|
| Google one-time products | IAP |
|