AppsFlyer
This guide describes how to add and configure AppsFlyer integration.
AppsFlyer is the world's leading mobile attribution & marketing analytics platform, helping app marketers around the world make better decisions.
How does Integration Work?
This integration works in two ways.
1. Receive Attribution Data from AppsFlyer
Once you successfully configured AppsFlyer integration, Apphud will receive attribution data from it. You can view this data on the user's page:
2. Send Subscription Events to AppsFlyer
Apphud can also send all subscription events to AppsFlyer. So you could view these events in the AppsFlyer dashboard and AppsFlyer could pass this data to their partners. This will help to measure the efficiency of your ad campaigns.
How to Add Integration?
Step 1
- Integrate AppsFlyer SDK into your app.
- Pass attribution data to Apphud (required).
- Collect Device Identifiers (required).
Step 2
At Apphud go to "Integrations" section and add AppsFlyer:
Step 3
Paste AppsFlyer Dev Key into "Developer key" field:
Step 4
You may have one more app created in AppsFlyer used for testing purposes not to mix test and live data. If you have a such app, paste test App Store app ID or test Package Name into "Test App ID" field.
Note
Information about how to create an app for debug purposes can be found in AppsFlyer documentation.
Step 5
You can enter your custom event names or disable some.
Note
You can use AppsFlyer built-in rich events names. View more information here.
Important Note
From AppsFlyer help: each network has its own limitations regarding the permitted characters in event names. To avoid problems, use only lower-case alpha-numeric characters (a-z and 0-9) for your in-app event names.
Important Note
In order to receive AppsFlyer attribution data from Facebook, you should accept Facebook’s "Advanced Mobile Measurement Agreement" using this link.
Note
You can read more how Apple and Google calculate their commissions here and here.
Pass Attribution Data to Apphud (required)
Send attribution data to Apphud (or at least Appsflyer ID). Implement delegate methods or listener.
AppsFlyerLib.shared().delegate = self
...
func onConversionDataSuccess(_ conversionInfo: [AnyHashable : Any]!) {
Apphud.addAttribution(data: conversionInfo, from: .appsFlyer, identifer: AppsFlyerLib.shared().getAppsFlyerUID()) { _ in }
}
func onConversionDataFail(_ error: Error) {
Apphud.addAttribution(data: ["error" : error.localizedDescription], from: .appsFlyer, identifer: AppsFlyerLib.shared().getAppsFlyerUID()) { _ in }
}
val listener = object : AppsFlyerConversionListener {
override fun onConversionDataSuccess(map: MutableMap<String, Any>?) {
val uid = AppsFlyerLib.getInstance().getAppsFlyerUID(app)
Apphud.addAttribution(ApphudAttributionProvider.appsFlyer, map, uid)
}
override fun onConversionDataFail(p0: String?) {
val uid = AppsFlyerLib.getInstance().getAppsFlyerUID(app)
Apphud.addAttribution(ApphudAttributionProvider.appsFlyer, null, uid)
}
}
AppsFlyerLib.getInstance().init("APPSFLYER_DEV_KEY", listener, this)
AppsFlyerLib.getInstance().startTracking(this)
// initialize Apphud
val uid = AppsFlyerLib.getInstance().getAppsFlyerUID(this)
Apphud.addAttribution(ApphudAttributionProvider.appsFlyer, null, uid)
final options = AppsFlyerOptions(
afDevKey: _appSecrets.appsFlyerKey,
appId: _appSecrets.appsFlyerAppId,
showDebug: true,
timeToWaitForATTUserAuthorization: 15,
manualStart: true,
);
final appsflyerSdk = AppsflyerSdk(options);
await appsflyerSdk.initSdk(registerConversionDataCallback: true);
appsflyerSdk.onInstallConversionData((result) async {
final uid = await appsflyerSdk.getAppsFlyerUID();
final status = result['status'];
final payload = Map<String, dynamic>.from(result['payload'] as Map);
if (status == 'success') {
final data = Map<String, dynamic>.from(result);
Apphud.addAttribution(
provider: ApphudAttributionProvider.appsFlyer,
data: payload,
identifier: uid,
);
} else {
Apphud.addAttribution(
provider: ApphudAttributionProvider.appsFlyer,
identifier: uid,
data: {
'error': payload['data'],
},
);
}
});
appsflyerSdk.startSDK();
[AppsFlyerTracker sharedTracker].delegate = self;
...
- (void)onConversionDataSuccess:(NSDictionary *)conversionInfo{
[Apphud addAttributionWithData:conversionInfo from:ApphudAttributionProviderAppsFlyer identifer:AppsFlyerTracker.sharedTracker.getAppsFlyerUID callback:^(BOOL callback) {}];
}
- (void)onConversionDataFail:(NSError *)error{
[Apphud addAttributionWithData:@{@"error" : error.localizedDescription} from:ApphudAttributionProviderAppsFlyer identifer:AppsFlyerTracker.sharedTracker.getAppsFlyerUID callback:^(BOOL result){}];
}
public class AppsFlyerListener : MonoBehaviour, IAppsFlyerConversionData
{
public void Initialize()
{
AppsFlyer.initSDK({developerKey}, {appId}, this);
AppsFlyer.startSDK();
}
public void onConversionDataSuccess(string conversionData)
{
string id = AppsFlyer.getAppsFlyerId();
var data = JsonConvert.DeserializeObject<Dictionary<string, object>>(conversionData);
ApphudSDK.AddAttribution(ApphudAttributionProvider.appsFlyer, data, id);
}
public void onConversionDataFail(string error)
{
ApphudSDK.AddAttribution(ApphudAttributionProvider.appsFlyer, new Dictionary<string, object>{
{"error", error }
}, AppsFlyer.getAppsFlyerId());
}
}
Collect Device Identifiers (required)
iOS: Call setDeviceIdentifiers(idfa: String?, idfv: String?)
method immediately after the SDK initialization. If the advertising identifier (IDFA) is not available, pass only the IDFV.
When IDFA becomes available, you can call setDeviceIdentifiers(idfa: String?, idfv: String?)
again.
Android: Call Apphud.collectDeviceIdentifiers()
method after the SDK initialization.
When targeting Android 13 and above, you must also declare AD_ID permission in the manifest file.
For more details, refer to Device Identifiers guide.
Request IDFA Consent (required)
Starting iOS 14.5 access to IDFA requires user consent. You should request IDFA manually using AppTrackingTransparency framework and pass it to Apphud. Read more here.
Events Cheat Sheet
This is a list of some events and their parameters that are being sent to AppsFlyer.
Note
You can read more about subscription events here and parameters here.
Trial
Trial period started
Default event name: apphud_trial_started
Parameters:
af_content_id
: String
Successful conversion from trial period to regular subscription
Default event name: apphud_trial_converted
Parameters:
af_content_id
: Stringaf_revenue
: Floataf_currency
: String
Failed conversion from trial period to regular subscription
Default event name: apphud_trial_expired
Parameters:
af_content_id
: Stringreason
: String (iOS)
Cancellations
Trial Canceled
Default event name: apphud_trial_canceled
Parameters:
af_content_id
: String
Subscription Canceled
Default event name: apphud_subscription_canceled
Parameters:
af_content_id
: String
Autorenew disabled (Deprecated)
Default event name: apphud_autorenew_disabled
Parameters:
af_content_id
: String
Autorenew enabled
Default event name: apphud_autorenew_enabled
Parameters:
af_content_id
: String
Introductory Offer
Introductory offer started
Default event name: apphud_intro_started
Parameters:
af_content_id
: Stringaf_revenue
: Floataf_currency
: Stringoffer_type
: String (iOS)unit
: String (iOS)units_count
: Integer (iOS)
Introductory offer renewed
Default event name: apphud_intro_renewed
Parameters:
af_content_id
: Stringaf_revenue
: Floataf_currency
: Stringoffer_type
: String (iOS)unit
: String (iOS)units_count
: Integer (iOS)
Successful conversion from introductory offer to regular subscription
Default event name: apphud_intro_converted
Parameters:
af_content_id
: Stringaf_revenue
: Floataf_currency
: Stringoffer_type
: String (iOS)
Failed conversion from introductory offer to regular subscription or failed renewal
Default event name: apphud_intro_expired
Parameters:
af_content_id
: Stringreason
: String (iOS)offer_type
: String (iOS)
Refund during the introductory offer
Default event name: apphud_intro_refunded
Parameters:
af_content_id
: Stringaf_revenue
: Floataf_currency
: Stringreason
: String (iOS)offer_type
: String (iOS)
Regular
Subscription started
Default event name: apphud_subscription_started
Parameters:
af_content_id
: Stringaf_revenue
: Floataf_currency
: String
Subscription renewed
Default event name: apphud_subscription_renewed
Parameters:
af_content_id
: Stringaf_revenue
: Floataf_currency
: String
Subscription expired
Default event name: apphud_subscription_expired
Parameters:
af_content_id
: Stringreason
: String (iOS)
Subscription refunded
Default event name: apphud_subscription_refunded
Parameters:
af_content_id
: Stringaf_revenue
: Floataf_currency
: Stringreason
: String (iOS)
Promo Offer
Promotional offer started
Default event name: apphud_promo_started
Parameters:
af_content_id
: Stringoffer_id
: String (iOS)af_revenue
: Floataf_currency
: Stringoffer_type
: String (iOS)unit
: String (iOS)units_count
: Integer (iOS)
Promotional offer renewed
Default event name: apphud_promo_renewed
Parameters:
af_content_id
: Stringoffer_id
: String (iOS)af_revenue
: Floataf_currency
: Stringoffer_type
: String (iOS)unit
: String (iOS)units_count
: Integer (iOS)
Successful conversion from a promotional offer to a regular subscription
Default event name: apphud_promo_converted
Parameters:
af_content_id
: Stringoffer_id
: String (iOS)af_revenue
: Floataf_currency
: Stringoffer_type
: String (iOS)
Failed conversion from promotional offer to regular subscription or failed renewal
Default event name: apphud_promo_expired
Parameters:
af_content_id
: Stringoffer_id
: String (iOS)reason
: String (iOS)offer_type
: String (iOS)
Refund during the promotional offer
Default event name: apphud_promo_refunded
Parameters:
af_content_id
: Stringoffer_id
: String (iOS)af_revenue
: Floataf_currency
: Stringreason
: String (iOS)offer_type
: String (iOS)
Other Events
Non-renewing purchase
Default event name: apphud_non_renewing_purchase
Parameters:
af_content_id
: Stringaf_revenue
: Floataf_currency
: String
Non-renewing purchase refunded
Default event name: apphud_non_renewing_purchase_refunded
Parameters:
af_content_id
: Stringaf_revenue
: Floataf_currency
: Stringreason
: String (iOS)
Billing Issue
Default event name: apphud_billing_issue
Parameters:
af_content_id
: String
Billing issue Resolved
Default event name: [Apphud] billing_issue_resolved
Parameters:
af_content_id
: String
If you want sandbox purchases not to mix with your production purchases in AppsFlyer, you should create a Test App ID.
- Create a new app in AppsFlyer as described here.
- Enter the newly created Test App ID toTest App ID field in the AppsFlyer Integration page in Apphud.
- iOS: Change App ID to a Test App ID when initializing AppsFlyer SDK:
AppsFlyerLib.shared().appleAppID = "0123456789"
- Android: Change Package Name to a Test Package Name.
Testing Subscription Events
Step 1
Please make sure AppsFlyer SDK is properly integrated in your app and AppsFlyer integration is configured in Apphud.
Step 2
Re-install the app and launch it again.
Step 3
Make a test purchase in your app.
Note
You can read more about testing purchases here.
Step 4
You will see attribution data on the user's page:
Step 5
Open "Events" tab in AppsFlyer and you will see Apphud events there:
Troubleshooting
I can’t see my events in AppsFlyer or not all events are shown.
AppsFlyer displays events in the “Events” tab based on the app installation date.
For instance, if you select a specific date range in AppsFlyer, it will show all events that occurred for users who installed the app within that date range.
However, in "Activity > Activity Summary > In-App Events," AppsFlyer shows all events that occurred within the selected date range, regardless of the app installation date.
Events are in the Pending State
Ensure you are collecting attribution data from the app. The attribution data must include appsflyer_id, which is essential for the integration. If appsflyer_id is missing, we won't be able to send the event.
Events are in the Skipped State
Sandbox events are not sent by default. To send Sandbox events, you need to provide a Test App ID in the Integration page. You can use the same Test App ID, but note that doing so will mix sandbox purchases with production purchases, leading to inaccurate data.
If some production events are in the Skipped State, check the status of these events on your integration page.
Updated 4 months ago