Getting AppsFlyer mobile data into Heap

  • 8 September 2023
  • 1 reply
  • 267 views

Badge +1

AppsFlyer is a powerful tool for tracking install attribution and deep links. Many of our mobile customers use AppsFlyer and have asked about getting this data into Heap but, at this time, Heap does not support an official integration with AppsFlyer. That said, there are still ways to grab data from AppsFlyer and pass that data into Heap using our event/user properties and track APIs.

The below code samples are all written for the Android platform, but I’ll add links to the AppsFlyer iOS docs where necessary to get you started on iOS targets as well.

Conversion Data and Install Attribution

First up is install attribution and conversion tracking. On Android, when initializing the AppsFlyer client, we have the opportunity to pass in an AppsFlyerConversionListener. This listener provides a few callbacks, some for unrelated behaviors, but there’s one in particular that we care about in this situation, onConversionDataSucess. This callback provides a map of properties with information related to the type of install, if it’s the first launch, and other account specific properties based on your app’s specific AppsFlyer configuration.

class ExampleApplication : Application() {

override fun onCreate() {
super.onCreate()

// Start recording with Heap so that we can use track/property APIs.
Heap.startRecording(this, "<YOUR_HEAP_ENV_ID>")

// Initializing AppsFlyer with an AppsFlyerConversionListener.
AppsFlyerLib.getInstance().init(
"<YOUR_APPSFLYER_DEV_KEY>",
object : AppsFlyerConversionListener {
override fun onConversionDataSuccess(conversionProps: MutableMap<String, Any>?) {
conversionProps?.let {
// The type of install (organic/non-organic)
val installType = it["af_status"] as? String ?: ""

// If this is the first app launch.
val firstLaunch = it["is_first_launch"] as? Boolean ?: false

// Other properties might be available based on your AppsFlyer setup.
// Consider properties such as `campaign` or `media_source` if they're
// used in your app.

// OPTION 1: Track a custom event to indicate an AppsFlyer install.
Heap.track(
"AppsFlyer Install Event",
mapOf(
"appsflyer_install_type" to installType,
"appsflyer_is_first_launch" to firstLaunch
)
)

// OPTION 2: If this is the first install, add this data as event or
// user properties.
if(firstLaunch) {
// Alternatively, Heap.addEventProperties
Heap.addUserProperties(
mapOf(
"appsflyer_install_type" to installType
)
)
}
}
}

override fun onConversionDataFail(p0: String?) { }
override fun onAppOpenAttribution(p0: MutableMap<String, String>?) { }
override fun onAttributionFailure(p0: String?) { }
},
this
)

// Debug logging allows you to see conversion properties in Logcat.
AppsFlyerLib.getInstance().setDebugLog(true)
AppsFlyerLib.getInstance().start(this)
}
}

This same data is available on iOS, though you get it in a slightly different way. Instead of setting a listener at initialization time, AppsFlyerLibDelegate provides callbacks specifically for conversion data. Inside the onConversionDataSuccess callback, you would extract the same properties from the provided NSDictionary and pass them to Heap using the same API methods.

Deep Link Tracking

In addition to conversion data, AppsFlyer provides a couple different ways to handle deep links and access their related properties. The cleanest way to do this is to implement an AppsFlyer DeepLinkListener and use it to subscribe to deep links. Deep link properties can then be pulled out and passed into Heap. In this case, a custom track event is probably the best way to send this data into Heap but, depending on the use-case, you can also send this in as user properties.

class ExampleApplication : Application() {

override fun onCreate() {
super.onCreate()

// Start recording with Heap to enable custom event tracking.
Heap.startRecording(this, "<YOUR_HEAP_ENV_ID>")

AppsFlyerLib.getInstance().init(
"<YOUR_APPSFLYER_DEV_KEY>",
null, // This can be the conversion listener from the first example.
this
)

// Subscribe to deep links.
AppsFlyerLib.getInstance().subscribeForDeepLink { deepLinkResult ->

// Indicates whether or not AppsFlyer deep link data is found.
if(deepLinkResult.status != DeepLinkResult.Status.FOUND) {
// Early out if the deep link data isn't available.
return@subscribeForDeepLink
}

// Deep link is nullable. Check that it exists before accessing.
deepLinkResult.deepLink.let { deepLink ->
// The value of the deep link contained in the AppsFlyer OneLink URL.
val deepLinkValue = deepLink.deepLinkValue ?: ""

// Whether this deep link was deferred until first app launch.
val deferred = deepLink.isDeferred ?: false

// The HTTP referrer as determined by AppsFlyer.
val referrer = deepLink.clickHttpReferrer ?: ""

// Track a custom event to indicate that an AppsFlyer deep link was handled.
Heap.track(
"AppsFlyer Deep Link Handled",
mapOf(
"appsflyer_deep_link_value" to deepLinkValue,
"appsflyer_is_deferred_deep_link" to deferred,
"appsflyer_deep_link_referrer" to referrer
)
)
}
}

// Enable debug logs to see deep link data in Logcat.
AppsFlyerLib.getInstance().setDebugLog(true)
AppsFlyerLib.getInstance().start(this)
}
}

Again, just like with the previous example, a similar implementation is available on iOS using another AppsFlyer delegate. This time you’ll want to look at the DeepLinkDelegate and the didResolveDeepLink function found here.

I hope this helps form the basis for many of you to start getting your AppsFlyer data into Heap. Feel free to reach out here with any additional questions and I’ll try to answer them as best as I can.

Cheers!


1 reply

Badge

Building on what Michael posted, here are some examples of the same in Swift.

Conversion Data and Install Attribution (Swift)

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, AppsFlyerLibDelegate {

    var window:UIWindow?

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        AppsFlyerLib.shared().appsFlyerDevKey = "<>"
        AppsFlyerLib.shared().appleAppID = "<>"
        AppsFlyerLib.shared().delegate = self

        Heap.shared.startRecording("<>")
        return true
    }

    func applicationDidBecomeActive(_ application: UIApplication) {
        AppsFlyerLib.shared().isDebug = true
        AppsFlyerLib.shared().start()
    }

    func onConversionDataSuccess(_ conversionInfo: [AnyHashable: Any]) {

        guard let installType = conversionInfo["af_status"] as? String,
              let isFirstLaunch = conversionInfo["is_first_launch"] as? Bool else {
            return
        }

        // OPTION 1: Track a custom event to indicate an AppsFlyer install
        Heap.shared.track("AppsFlyer Install Event", properties: [
            "appsflyer_install_type": installType,
            "appsflyer_is_first_launch": isFirstLaunch
        ])

        // OPTION 2: If this is the first install, add this data as event or user properties
        if isFirstLaunch {
            // Alternatively, Heap.addEventProperties
            Heap.shared.addUserProperties([
                "appsflyer_install_type": installType
            ])
        }
    }

    func onConversionDataFail(_ error: Error) {
        // ...
    }
}


Deep Link Tracking (Swift)

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, DeepLinkDelegate {

    var window:UIWindow?

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        AppsFlyerLib.shared().appsFlyerDevKey = "<>"
        AppsFlyerLib.shared().appleAppID = "<>"
        AppsFlyerLib.shared().deepLinkDelegate = self
        Heap.shared.startRecording("<>")
        return true
    }

    func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
      AppsFlyerLib.shared().handleOpen(url, options: options)
      return true
    }

    func didResolveDeepLink(_ result: DeepLinkResult) {
        guard result.status == .found, let deepLink = result.deepLink else { return }

        let deepLinkValue = deepLink.deeplinkValue ?? ""
        let isDeferred = deepLink.isDeferred
        let referrer = deepLink.clickHTTPReferrer ?? ""

        Heap.shared.track("AppsFlyer Deep Link Handled", properties: [
            "appsflyer_deep_link_value": deepLinkValue,
            "appsflyer_is_deferred_deep_link": isDeferred,
            "appsflyer_deep_link_referrer": referrer
        ])
    }
}

 

Reply