Send in-app subscription data to AppsFlyer

Accurately measure what drives your subscription revenue on ad campaign level by tracking events like trial-to-paying-user conversions, renewals, refunds, and upgrades.
Qonversion tracks revenue even if a user does not open your app. This allows measuring the performance of each subscription plan with 100% accuracy.

1. Set up the SDKs

  1. You need to have AppsFlyer SDK integrated into your app before starting with this integration. If you do not have AppsFlyer integration yet, please use this documentation.

  2. Set Qonversion SDKs following Installing the SDKs guides.

  3. Send AppsFlyer user ID to Qonversion via User Properties. In the onConversionDataSuccess callback use thesetProperty() method with the AppsFlyer user ID value.

// AppsFlyer 6

import AppsFlyerLib
extension AppDelegate: AppsFlyerLibDelegate {

    func onConversionDataSuccess(_ conversionInfo: [AnyHashable : Any]!) {
        Qonversion.shared().setUserProperty(.appsFlyerUserID, value: AppsFlyerLib.shared().getAppsFlyerUID())
    func onConversionDataFail(_ error: Error!) {

// Appsflyer 5

import AppsFlyerLib
extension AppDelegate: AppsFlyerTrackerDelegate {

    func onConversionDataSuccess(_ conversionInfo: [AnyHashable : Any]!) {
        Qonversion.shared().setUserProperty(.appsFlyerUserID, value: AppsFlyerTracker.shared()?.getAppsFlyerUID())
    func onConversionDataFail(_ error: Error!) {
/// AppsFlyer 6 
#import <AppsFlyerLib/AppsFlyerLib.h>

@interface AppDelegate: UIResponder <UIApplicationDelegate, AppsFlyerLibDelegate>

- (void)onConversionDataSuccess:(NSDictionary *)conversionInfo {
    [[Qonversion sharedInstance] setUserProperty:QONUserPropertyKeyAppsFlyerUserID value:[[AppsFlyerTracker sharedTracker] getAppsFlyerUID]];

- (void)onConversionDataFail:(NSError *)error {



/// AppsFlyer 5

#import <AppsFlyerTracker/AppsFlyerTracker.h>

@interface AppDelegate: UIResponder <UIApplicationDelegate, AppsFlyerTrackerDelegate>

- (void)onConversionDataSuccess:(NSDictionary *)conversionInfo {
    [[Qonversion sharedInstance] setUserProperty:QONUserPropertyKeyAppsFlyerUserID value:[[AppsFlyerLib shared] getAppsFlyerUID]];

- (void)onConversionDataFail:(NSError *)error {


AppsFlyerConversionListener conversionListener = new AppsFlyerConversionListener() {

    public void onConversionDataSuccess(final Map<String, Object> conversionData) {
        Qonversion.getSharedInstance().setUserProperty(QUserPropertyKey.AppsFlyerUserId, AppsFlyerLib.getInstance().getAppsFlyerUID(App.this));

    public void onConversionDataFail(String errorMessage) {


    public void onAppOpenAttribution(Map<String, String> conversionData) {


    public void onAttributionFailure(String errorMessage) {


AppsFlyerLib.getInstance().init("afDevKey", conversionListener, this);
val conversionListener: AppsFlyerConversionListener = object : AppsFlyerConversionListener {
    override fun onConversionDataSuccess(conversionData: Map<String, Any>) {

    override fun onConversionDataFail(errorMessage: String) {}
    override fun onAppOpenAttribution(conversionData: Map<String, String>) {}
    override fun onAttributionFailure(errorMessage: String) {}

AppsFlyerLib.getInstance().init("afDevKey", conversionListener, this)
_appsflyerSdk.onInstallConversionData((res) {
  print("res: " + res.toString());
  setState(() {
    _gcd = res;

  Qonversion.getSharedInstance().setUserProperty(QUserPropertyKey.appsFlyerUserId, 'your appsflyer user id');
this.onInstallConversionDataCanceller = appsFlyer.onInstallConversionData(
  (res) => {    
    appsFlyer.getAppsFlyerUID((err, appsFlyerUID) => {
      if (err) {
      } else {
        Qonversion.getSharedInstance().setUserProperty(UserPropertyKey.APPS_FLYER_USER_ID, appsFlyerUID);
using AppsFlyerSDK;
using QonversionUnity;

public class AppsFlyerObjectScript : MonoBehaviour , IAppsFlyerConversionData
    void Start()
        /* AppsFlyer.setDebugLog(true); */
        AppsFlyer.initSDK("devkey", "appID", this);

    public void onConversionDataSuccess(string conversionData)
        Qonversion.GetSharedInstance().SetUserProperty(UserPropertyKey.AppsFlyerUserId, AppsFlyer.getAppsFlyerId());


Do not track any purchase events on the client side

Qonversion tracks all revenue events so if you track revenue events with AppsFlyer SDK, you may double count the revenue in your AppsFlyer account.

2. Configure the Appsflyer integration

Provide Integration Details

  1. Get AppsFlyer Dev Key in your AppsFlyer account navigate to Configuration β†’ App Settings β†’ Dev Key.

  2. Get your App ID. You can find App ID in App Store URL:
    For iOS

    For Android
  3. Navigate to the Integrations section in your Qonversion project, select AppsFlyer, and provide the Dev Key and App ID, and Save.


AppsFlyer Dev Key, App ID, and other settings

Configure the event names

We recommend using the default event names provided by Qonversion. But you can change the event names based on your preferences.
Note, that the event names will not affect revenue recognition. All purchase events containing a value (subscription started, trial converted, subscription renewed, subscription refunded, in-app purchase) will be sent to AppsFlyer with af_revenue property, and the revenue will be recognized correctly in AppsFlyer.

β†’ Read more about tracked events here

3. Server to server configuration


Ensure that you've enabled the S2S configuration toggle at the ApssFlyer Scan Conversion Studio settings to send your data correctly.



Now Qonversion will start sending in-app purchases and subscriptions data to your AppsFlyer account.

Event Payload

In case you need details about data sent to CleverTap, follow the example below:

    'appsflyer_id': '', // A unique identifier, generated by AppsFlyer
    'os': '14.6',
    'app_version_name': '1.0.0',
    'customer_user_id': 'outside_uid', //Unique user identifier set by the app owner
    'idfa': '',
    'idfv': '',
    'eventCurrency': 'EUR',
    'ip': '',
    'bundleIdentifier': '', //Your app's bundle ID from AppStore Connect
    'eventName': 'trial_converted',
    'renewal': false,  
    'eventTime': 'Y-m-d H:i:s.u', // UTC time the event happened. AppsFlyer needs to get the event by 02:00 UTC of the following day. Otherwise AppsFlyer will use the time it has received the event.  
    'eventValue': {
        'af_content_type': 'product',
        'af_content_id': 'product_id',
        'af_revenue': '1.99',
        'af_currency': 'EUR',


Check out the sample Xcode Project

Here you can find the sample Xcode project that demonstrates the Qonversion and AppsFlyer integration

How to compare your app revenue in AppsFlyer to Qonversion

Navigate to your AppsFlyer β†’ Activity dashboard. The date range relates to the event date and isn't LTV-based. The revenue you see in this dashboard is the revenue generated for the selected period. Revenue consists of in-app purchases (if reported) and ad revenue.

To compare the total revenue from this dashboard to the revenue tracked by Qonversion:

  1. Navigate to Qonversion Customers dashboard.
  2. Select the same date range.
  3. See the "Sales" figure at the top right.

This sales figure should be equal to your revenue in AppsFlyer.
Please note:

  1. The sales data in Qonversion is before deducting app stores commissions. If you are sending the revenue to AppsFlyer net of App Store commission (step 1 (4) of this guide above), the sales number will be 15-30% higher in Qonversion than in AppsFlyer.
  2. Qonversion does not track ad revenue
  3. Qonversion Customers dashboard data does not contain one-off in-app purchases.

There also might be a minor difference due to:

  1. Time zones, Qonversion uses UTC time;
  2. FX rates.

What’s Next

Other Attribution Platforms