AppsFlyer is an industry-leading mobile attribution and marketing analytics platform, provided as a Software-as-a-Service (SaaS). It offers intuitive dashboards, real-time data reports, and a unique deep linking technology to understand your customers better.
Getting started
RudderStack supports sending events to AppsFlyer via the following connection modes:
Connection Mode | Web | Mobile | Server |
---|---|---|---|
Device mode | - | Supported | - |
Cloud mode | Supported | Supported | Supported |
- If you want to use RudderStack's Transformations feature.
- If you want to send server-side events.
Once you have confirmed that the source platform supports sending events to AppsFlyer, follow these steps:
- From your RudderStack dashboard, add a source. Then, from the list of destinations, select AppsFlyer.
- Assign a name to the destination and click Continue.
Connection settings
The following connection settings are required to configure AppsFlyer as a destination in RudderStack:
- AppsFlyer Dev Key: Refer to the FAQ section below for more information on obtaining your AppsFlyer dev key.
- App ID: Enter your Apple or Android app ID.
- Android App ID: This the application ID used in your
app/build.gradle
file. - Apple App ID: This is the iTunes Application ID and it is mandatory for the iOS applications.
- Android App ID: This the application ID used in your
Use Rich Event Names: Enable this setting to include your app's screen or page name in the
screen
orpage
event names.Sharing Filter: By default, the value for this setting is set to
all
. You can use this setting to meet any regulatory requirements like GDPR and CCPA, complying with user opt-out mechanisms, and for any other business use-case. For more information, refer to the AppsFlyer Help Center.Client-side Event Filtering: This setting is applicable only if you are sending events to AppsFlyer via device mode. It lets you specify which events should be blocked or allowed to flow through to AppsFlyer. Refer to the Client-side Event Filtering guide for more information on this setting.
Status Callback URLs: Specify the callback URLs to be used for user deletion requests. You can provide multiple callback URLs by separating them by a comma.
API Token: Enter your AppsFlyer API token. For more information on obtaining your API token, refer to this AppsFlyer guide.
- Use device-mode to send events: Enable this setting to send events from the Android/iOS SDK to Appsflyer via the device mode.
Adding device mode integration
Once you add AppsFlyer as a destination in the RudderStack dashboard, follow these steps to add it to your project depending on your integration platform:
- Add the following line to your CocoaPods
Podfile
:pod 'Rudder-Appsflyer' - After adding the dependency, you need to register
RudderAppsflyerFactory
with yourRudderClient
initialization as afactory
ofRudderConfig
. To do so, import theRudderAppsflyerFactory.h
file in yourAppDelegate.m
file:#import <Rudder-Appsflyer/RudderAppsflyerFactory.h> - Starting from AppsFlyer iOS device mode version
2.0.0
and above, the RudderStack SDK does not automatically initialize the AppsFlyer SDK. You need to initialize the AppsFlyer SDK as shown:#import <AppsFlyerLib/AppsFlyerLib.h>[[AppsFlyerLib shared] setAppsFlyerDevKey:<devKey>];[[AppsFlyerLib shared] setAppleAppID:<appleAppId>];[AppsFlyerLib shared].isDebug = YES;[[AppsFlyerLib shared] start]; - Then, change the iOS SDK initialization to the following:RSConfigBuilder *builder = [[RSConfigBuilder alloc] init];[builder withDataPlaneUrl:DATA_PLANE_URL];[builder withTrackLifecycleEvens:YES];[builder withRecordScreenViews:YES];[builder withFactory:[RudderAppsflyerFactory instance]];[builder withLoglevel:RSLogLevelDebug];[RSClient getInstance:WRITE_KEY config:[builder build]];
- Install
RudderAppsFlyer
(available through CocoaPods) by adding the following line to yourPodfile
:pod 'RudderAppsFlyer', '~> 1.0.0' - Run the
pod install
command. - Then, import the SDK depending on your preferred platform:import RudderAppsFlyer@import RudderAppsFlyer;
- Next, add the imports to your
AppDelegate
file under thedidFinishLaunchingWithOptions
method, as shown:let config: RSConfig = RSConfig(writeKey: WRITE_KEY).dataPlaneURL(DATA_PLANE_URL)RSClient.sharedInstance().configure(with: config)client?.addDestination(RudderAppsFlyerDestination())RSConfig *config = [[RSConfig alloc] initWithWriteKey:WRITE_KEY];[config dataPlaneURL:DATA_PLANE_URL];[[RSClient sharedInstance] configureWith:config];[[RSClient sharedInstance] addDestination:[[RudderAppsFlyerDestination alloc] init]];
- Add the
mavenCentral()
repository, as shown:repositories {mavenCentral()} - Then, add the following lines to your
app/build.gradle
file underdependencies
:implementation 'com.rudderstack.android.sdk:core:1.+'implementation 'com.rudderstack.android.integration:appsflyer:1.+'implementation 'com.appsflyer:af-android-sdk:6.+'implementation 'com.android.installreferrer:installreferrer:2.+' - Starting from AppsFlyer Android device mode version
2.0.0
and above, the RudderStack SDK does not automatically initialize the AppsFlyer SDK. You need to initialize the AppsFlyer SDK as shown:import com.appsflyer.AppsFlyerLib;import com.appsflyer.AFLogger;AppsFlyerLib.getInstance().init(DEV_KEY, null, this);AppsFlyerLib.getInstance().setLogLevel(AFLogger.LogLevel.DEBUG);AppsFlyerLib.getInstance().start(this); - Finally, change the SDK initialization in your
Application
class, as shown:val rudderClient: RudderClient = RudderClient.getInstance(this,WRITE_KEY,RudderConfig.Builder().withDataPlaneUrl(DATA_PLANE_URL).withFactory(AppsFlyerIntegrationFactory.FACTORY).build())
- Add the RudderStack-AppsFlyer module to your app using the following command:npm install @rudderstack/rudder-integration-appsflyer-react-native// OR //yarn add @rudderstack/rudder-integration-appsflyer-react-nativeFor AppsFlyer React Native device mode version less than 1.1.0, follow the below step:
- Import the module and add it to your SDK initialization code, as shown:import rudderClient from "@rudderstack/rudder-sdk-react-native"import appsflyer from "@rudderstack/rudder-integration-appsflyer-react-native"const config = {dataPlaneUrl: DATA_PLANE_URL,trackAppLifecycleEvents: true,withFactories: [appsflyer],}rudderClient.setup(WRITE_KEY, config)
- For AppsFlyer React Native device mode version 1.1.0 or above, follow these steps:
- Initialize the AppsFlyer SDK as shown:As seen above, the propertiesimport rc from '@rudderstack/rudder-sdk-react-native';import appsflyer from '@rudderstack/rudder-integration-appsflyer-react-native';import {setOptions} from '@rudderstack/rudder-integration-appsflyer-react-native/src/appsflyer';// Setting options for initializing the appsflyer sdksetOptions({// dev key from the appsflyer dashboard"devKey": "<dev_key>",// whether we want to run the appsflyer SDK in the debug mode"isDebug": true,// whether we want to register for the listeners which would return the conversion data"onInstallConversionDataListener": true,// ID assigned by the Apple app store for any app which is either published or in the process of getting published"appleAppId": "<apple_app_id>",// whether we want to register for the listeners which would return the deeplink data"onDeepLinkListener": true,// the number of seconds for which the appsflyer iOS SDK should wait to allow the app to retrieve the user consent."timeToWaitForATTUserAuthorization": 60})// Configuration object to be passed while initializing the Rudder React Native // SDKconst config = {dataPlaneUrl: DATA_PLANE_URLtrackAppLifecycleEvents: true,// Passing appsflyer factory here, since we want to run appsflyer as a device// mode destination.withFactories: [appsflyer]};// Finally, initializing the RudderStack React Native SDKawait rc.setup( WRITE_KEY , config);
onInstallConversionDataListener
andonDeepLinkListener
are set totrue
in thesetOptions
API to get access to the conversion as well as the attribution data. - Then, register the callbacks with the listeners, as shown:import {onAppOpenAttribution,onAttributionFailure,onDeepLink,onInstallConversionData,onInstallConversionFailure} from '@rudderstack/rudder-integration-appsflyer-react-native/src/appsflyer';var onInstallConversionDataCanceller = onInstallConversionData((data) => {console.log("On Install Conversion Success data is ", data);if (JSON.parse(res.data.is_first_launch) == true) {if (res.data.af_status === 'Non-organic') {var media_source = res.data.media_source;var campaign = res.data.campaign;console.log('This is first launch and a Non-Organic install. Media source: ' + media_source + ' Campaign: ' + campaign);} else if (res.data.af_status === 'Organic') {console.log('This is first launch and a Organic Install');}} else {console.log('This is not first launch');}})var onAppOpenAttributionCanceller = onAppOpenAttribution((data) => {console.log("On App Open Attribution Success and the data is ", data);// write your own custom logic here})var onAttributionFailureCanceller = onAttributionFailure((data) => {console.log("On App Attribution Failure and the data is ", data);// write your own custom logic here})var onInstallConversionFailureCanceller = onInstallConversionFailure((data) => {console.log("On Install Conversion Failure data is ", data);// write your own custom logic here})var onDeepLinkCanceller = onDeepLink((data) => {console.log("On Deeplink data is ", data);// write your own custom logic here})
- Depending on the React Native components you are using, you can trigger an appropriate method, for example:
- If it's a class-based component, trigger the
remove()
method incomponentWillUnMount()
, as shown:import React, {Component} from 'react';import {AppState,Platform,StyleSheet,Text,View,Button} from 'react-native';import appsFlyer from 'react-native-appsflyer';const options = {devKey: "********",isDebug: true,onInstallConversionData: true};if (Platform.OS === 'ios') {options.appId = "123456789";}this.onInstallConversionDataCanceller = appsFlyer.onInstallConversionData(data => {console.log("GCD");console.log(data);});this.onAppOpenAttributionCanceller = appsFlyer.onAppOpenAttribution(data => {console.log("OAOA");console.log(data);});appsFlyer.initSdk(options, (result) => {console.log(result);}, (error) => {console.error(error);});type Props = {};export default class App extends Component < Props > {componentWillUnmount() {if (onInstallConversionDataCanceller) {onInstallConversionDataCanceller();console.log('unregister onInstallConversionDataCanceller');onInstallConversionDataCanceller = null;}if (onAppOpenAttributionCanceller) {onAppOpenAttributionCanceller();console.log('unregister onAppOpenAttributionCanceller');onAppOpenAttributionCanceller = null;} - If it's a functional component, trigger the
useEffect()
hook, as shown:import React, {useEffect, useState} from 'react';import {AppState, SafeAreaView, Text, View} from 'react-native';import appsFlyer from 'react-native-appsflyer';var onInstallConversionDataCanceller = appsFlyer.onInstallConversionData((res) => {if (JSON.parse(res.data.is_first_launch) == true) {if (res.data.af_status === 'Non-organic') {var media_source = res.data.media_source;var campaign = res.data.campaign;console.log('This is first launch and a Non-Organic install. Media source: ' + media_source + ' Campaign: ' + campaign);} else if (res.data.af_status === 'Organic') {console.log('This is first launch and a Organic Install');}} else {console.log('This is not first launch');}},);var onAppOpenAttributionCanceller = appsFlyer.onAppOpenAttribution((res) => {console.log(res);});appsFlyer.initSdk({devKey: 'K2a*********99',isDebug: false,appId: '41******5',},(result) => {console.log(result);},(error) => {console.error(error);},);const Home = (props) => {useEffect(() => {return () => {// Optionaly remove listeners for deep link data if you no longer need them after componentWillUnmountif (onInstallConversionDataCanceller) {onInstallConversionDataCanceller();console.log('unregister onInstallConversionDataCanceller');onInstallConversionDataCanceller = null;}if (onAppOpenAttributionCanceller) {onAppOpenAttributionCanceller();console.log('unregister onAppOpenAttributionCanceller');onAppOpenAttributionCanceller = null;}};});return ({'App'});};
- If it's a class-based component, trigger the
- Finally, open
AppDelegate.m
in theios
folder of your app and include the following snippet:#import "RudderIntegrationAppsflyerReactNative.h"- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url options:(NSDictionary *) options {[[AppsFlyerAttribution shared] handleOpenUrl:url options:options];return YES;}// Open URI-scheme for iOS 8 and below- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString*)sourceApplication annotation:(id)annotation {[[AppsFlyerAttribution shared] handleOpenUrl:url sourceApplication:sourceApplication annotation:annotation];return YES;}// Open Universal Links- (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity restorationHandler:(void (^)(NSArray * _Nullable))restorationHandler {[[AppsFlyerAttribution shared] continueUserActivity:userActivity restorationHandler:restorationHandler];return YES;}
- Navigate to the root folder of your application and run the following command:cordova plugin add rudder-integration-appsflyer-cordova
- Add the platforms that you want to target for your app:cordova platform add ioscordova platform add android
- Run the following command to build the project for all the platforms:cordova build
- Finally, add the following code in the
onDeviceReady()
function of your home page to initialize the SDK, as shown:RudderClient.initialize(WRITE_KEY , {dataPlaneUrl: DATA_PLANE_URL,factories: [RudderAppsflyerFactory]})Make sure to use theawait
keyword with theinitialize
call.
Connecting AppsFlyer to non-Android/iOS sources
AppsFlyer supports all the RudderStack sources in addition to Android and iOS. However, you need to add a transformation to the destination as shown:
export function transformEvent(event, metadata) { event.context.os = { name: "android", version: "8.1.0" }; return event;}
Save the transformation and connect it to your AppsFlyer destination in the RudderStack dashboard.
Sending events via the RudderStack cloud mode
- To use RudderStack's Transformations feature to transform your events
- To send server-side events
To send events to AppsFlyer via cloud mode, you need the AppsFlyer ID generated by the Appsflyer SDK that is integrated with your app.
Once you obtain the AppsFlyer ID, you can send events to AppsFlyer via cloud mode by including the externalId
key within your events' context
. The format of externalId
is as shown:
"externalId": [ { "id": "AppsFlyer_ID", "type": "appsflyerExternalId" }]
The following table lists the externalId
fields:
Field | Description |
---|---|
id | Your AppsFlyer ID. |
type | The type of externalId . This must always be set to appsFlyerExternalId . |
Obtaining the AppsFlyer ID
As mentioned above, the AppsFlyer ID is generated by the Appsflyer SDK integrated with your app.
- If the AppsFlyer SDK is directly loaded on your app, refer to this AppsFlyer documentation to obtain the AppsFlyer ID.
- If your AppsFlyer SDK is loaded through RudderStack (device mode integration), then you can obtain the AppsFlyer ID by including the code snippet in your app, depending on your platform of integration:
#import <AppsFlyerLib/AppsFlyerLib.h>NSString *appsflyerId = [AppsFlyerLib shared].getAppsFlyerUID;
import com.appsflyer.AppsFlyerLib;String appsFlyerId = AppsFlyerLib.getInstance().getAppsFlyerUID(this);
import AppsFlyerIntegrationFactory from "@rudderstack/rudder-integration-appsflyer-react-native/src/bridge"const appsFlyerId = await AppsFlyerIntegrationFactory.getAppsFlyerId()
Identify
The identify
call sets userId
through the setCustomerUserId
method of AppsFlyerLib
.
identify
calls only in the device mode.RudderStack sets email
from the event traits to AppsFlyer using the native SDK's setUserEmails
method, as shown:
[[RSClient sharedInstance] identify:@"developer_user_id" traits:@{@"email": @"bar@foo.com"}];
Deleting a user
You can delete a user in AppsFlyer using the Suppression with Delete regulation of the RudderStack Data Regulation API.
userId
in the event. Additionally, you can specify any of the following in the event:- AppsFlyer ID
- iOS advertising ID/Android advertising ID (depending on your platform)
- Any custom identifier like
email
,phone
, etc.
A sample regulation request body for deleting a user in AppsFlyer is shown below:
In this case, you must specify either the Android App ID/ iOS App ID in the RudderStack dashboard setting.
{ "regulationType": "suppress_with_delete", "destinationIds": [ "2FIKkByqn37FhzczP23eZmURciA" ], "users": [{ "userId": "1hKOmRA4GRlm", "phone": "+1-202-555-0146", "email": "alex@example.com" "appsflyerId": "asdhw126" }]}
In this case, you must specify the iOS App ID in the RudderStack dashboard setting.
{ "regulationType": "suppress_with_delete", "destinationIds": [ "2FIKkByqn37FhzczP23eZmURciA" ], "users": [{ "userId": "1hKOmRA4GRlm", "phone": "+1-202-555-0146", "email": "alex@example.com" "ios_advertising_id": "asdhw126" }]}
In this case, you must specify the Android App ID in the RudderStack dashboard setting.
{ "regulationType": "suppress_with_delete", "destinationIds": [ "2FIKkByqn37FhzczP23eZmURciA" ], "users": [{ "userId": "1hKOmRA4GRlm", "phone": "+1-202-555-0146", "email": "alex@example.com" "android_advertising_id": "asdhw126" }]}
Track
RudderStack's track
call is mapped to the standard AppsFlyer events wherever possible.
The following table lists the event mapping from RudderStack to AppsFlyer:
RudderStack event | AppsFlyer event |
---|---|
Products Searched | af_search |
Product Viewed | af_content_view |
Product List Viewed | af_list_view |
Product Added to Wishlist | af_add_to_wishlist |
Product Added | af_add_to_cart |
Checkout Started | af_initiated_checkout |
Order Completed | af_purchase |
Product Removed | remove_from_cart |
first_purchase | first_purchase |
For any event not present in the above table, RudderStack makes the following changes to the event name before sending it to AppsFlyer via the native SDK:
- Converting the entire event name to lower case
- Replacing any space with an underscore
Along with the above event mapping, RudderStack also maps the event properties to the corresponding AppsFlyer event properties, as shown below:
RudderStack property name | AppsFlyer property name |
---|---|
query | af_search_string |
price | af_price |
product_id | af_content_id |
category | af_content_type |
currency | af_currency |
products | RudderStack formulates this list as per the List View specification and passes it to the property af_content_list . |
quantity | af_quantity |
order_id | af_receipt_id |
revenue | af_revenue |
A sample track
call for an iOS app is shown below:
[[RSClient sharedInstance] track:@"Accepted Terms of Service" properties:@{ @"foo": @"bar", @"foo_int": @134}];
Screen
For all the screen
calls sent from the SDK, RudderStack calls AppsFlyer's trackEvent
method with screen
as the event name. All the event properties are passed to AppsFlyer without any modification.
For the automatically recorded screen
calls, RudderStack obtains a Boolean property called automatic
.
Advertising ID
RudderStack utilizes the advertising ID for the AppsFlyer destination if it is set as per the following specifications:
For iOS: Advertisement ID documentation
For Android: Advertisement ID documentation
You can find the advertising ID in your event's context.device.advertisementId
.
ATTrackingManager
If the ATTrackingManager.trackingAuthorizationStatus
is passed according to ATTrackingManager authorization consent, RudderStack will utilize it for the AppsFlyer destination.
You can find trackingAuthorizationStatus
in your event's context.device.attTrackingStatus
.
Error messages
This section covers some of the possible error messages you may encounter while using this integration.
Invalid platform / required androidAppId / appleAppId missing
This error occurs when either the OS Name
or your respective App ID is not set.
You can set the App ID in your settings.
The SDK automatically sets the OS Name
and it can be found in context.os.name
.
Appsflyer ID is not set. Rejecting the event.
This error occurs when the appsflyerExternalId
is not set. Refer to the Sending events via the RudderStack cloud mode section for more information on setting the appsflyerExternalId
.
Debugging
RudderStack sets the logLevel
in AppsFlyer based on the logLevel
set for the RudderClient
. If it is set to DEBUG
or more, RudderStack sets the logLevel
to VERBOSE
for AppsFlyer.
For anything below that, RudderStack sets the logLevel
to NONE
for AppsFlyer.
FAQ
Where do I get the AppsFlyer dev key?
You can find the AppsFlyer Dev Key by logging into your AppsFlyer account and navigating to the Apps Settings page in your dashboard. For more information, refer to this AppsFlyer Help Center page.
I get an error saying "Build input file cannot be found" for iOS device mode. What should I do?
The latest AppsFlyer SDK requires XCode 12. Make sure you meet this requirement. You may have to downgrade your AppsFlyer SDK to build with a lower version of XCode.
You can declare the pod
version in your Podfile
as shown:
pod 'Rudder-Appsflyer',' 1.0.0'
How do I get the AppsFlyer ID to send events from my mobile sources via the RudderStack cloud mode?
To send events to AppsFlyer via cloud mode, you first need to obtain the AppsFlyer ID generated by the Appsflyer SDK.
You can get this ID by either directly loading the native AppsFlyer SDK on your app, or loading it via RudderStack (device mode integration).
In case of a device mode integration, include the following code snippet (depending on your platform of integration) in your app to get the AppsFlyer ID:
#import <AppsFlyerLib/AppsFlyerLib.h>NSString *appsflyerId = [AppsFlyerLib shared].getAppsFlyerUID;
import com.appsflyer.AppsFlyerLib;String appsFlyerId = AppsFlyerLib.getInstance().getAppsFlyerUID(this);
import AppsFlyerIntegrationFactory from "@rudderstack/rudder-integration-appsflyer-react-native/src/bridge"const appsFlyerId = await AppsFlyerIntegrationFactory.getAppsFlyerId()
Once you obtain the AppsFlyer ID, you can send events via cloud mode by by including the externalId
key within your events' context
. For more information, refer to the Sending events via the RudderStack cloud mode section above.
Contact us
For more information on the topics covered on this page, email us or start a conversation in our Slack community.