Mobile SDK

Track conversions in your Android/iOS application.

Overview

Tradedoubler's mobile Software Development Kit (SDK) optimises your Performance Marketing app activity. Whether your traffic comes from mobile web or in-app the SDK allows you to:

  • Drive mobile engagement and optimise app activity.
  • Maximise ROI with CPA/CPL models - only pay for results.
  • Increase conversion by directing traffic to transactional apps.
  • Drive app installs and in-app activities.
  • Attract quality users and identify your best publishers.

The mobile SDK supports the Android and iOS platforms with 32-bit and 64-bit support for iOS. They include all the benefits of Tradedoubler's accurate and secure tracking with mobile specific additions.


Do not have an affiliate program with Tradedoubler? Contact us

Android SDK installation

To install library you need to add Tradedoubler Maven Repository to your project build.gradle file:

allprojects {
   repositories {
       maven { 
        url 'https://pkgs.dev.azure.com/tradedoubler-sdk/tradedoubler-android-sdk/_packaging/release-repo/maven/v1'
        name 'release-repo' 
    }
   }
}

The next step is adding the library as the application dependency:

android {
   defaultConfig {
       minSdkVersion 21
   }
}

The SDK uses Install Referrer library services to securely retrieve referral content from Google Play. It’s required to retrieve the TDUID(Tradedoubler's Unique Identifier) from the application install URL. https://developer.android.com/google/play/installreferrer/library

To utilize tracking features your app needs to have access to the internet. To achieve that, you must add permissions to the Android Manifest file of your project.

<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>

Android SDK initialization

Enable the Tradedoubler SDK in your Application’s onCreate() method. In addition, you need to initialize the library with parameters organizationId and secretCode provided by Tradedoubler.

class App : Application() {

	override fun onCreate() {
		super.onCreate()

		TradeDoublerSdk.create(applicationContext)
		TradeDoublerSdk.getInstance().organizationId = "your_organization_id"
		TradeDoublerSdk.getInstance().secretCode = "you_secret_code"
	}
}
						

Identify User

Hashed unique ID

To enhance the tracking between multiple browsers, apps and devices you may anonymously identify the user using a hash value calculated using their email address. By default, all identifiers are not used directly. SDK is working with SHA-256 digest of provided identifiers.

If a user is logged in, you can set the user email as an additional identifier by using userEmail property.

TradeDoublerSdk.getInstance().userEmail = "email@test.com"

Please remember to clear this value after user logout.

TradeDoublerSdk.getInstance().userEmail = null

Tradedoubler Unique ID

To provide proper sale and advertising tracking from affiliate links we need to provide TDUID retrieved from advertising URLs. There are two main types of advertising URLs that can be used.

Installation URL
SDK uses Install Referrer library services to securely retrieve referral content from Google Play. It’s required to retrieve TDUID from the application install URL.

Caution Referrer URL used to install app needs to have specific format:
https://play.google.com/store/apps/details?id=your.packagename&referrer=tduid%3Dtduid_value
Only referrer parameter parts from query params are available for the application. In most cases it contains encoded nested query string, so in given example SDK will have access to referral URL with value tduid=tduid_value. By default retrieving TDUID from the installation URL is enabled, you can disable it by using useInstallReferrer property. This can be helpful if your app install links are different than default ones or you need to provide different extraction of TDUID parameters.

class App : Application() {

   override fun onCreate() {
       super.onCreate()

       TradeDoublerSdk.create(applicationContext)
	//setup here
//...
       TradeDoublerSdk.getInstance().useInstallReferrer = false
   }
 }
 

In such a case you can extract and provide TDUID value directly to the SDK instance.

private fun setTduid(){
    TradeDoublerSdk.getInstance().tduid = "tduid_value"
}
 

To learn more about testing installation referrers, check the Testing and Troubleshooting section.

Open App URL or Intent
https://developer.android.com/training/app-links
On Android we have few possibilities to open the app with additional parameters using URLs, custom schema or deeplinks. As flow for each option could be different, SDK contains a set of methods that can help with TDUID retrieval. Each method from this set will try to retrieve TDUID from a given parameter. If TDUID is found, it is saved inside SDK storage. In most cases methods should be used in your start Activity or in Activity that is set as a target component for opening app links. TDUID is expected to be one of the query parameters of your app open URL.

class MainViewActivity: AppCompatActivity() {

   override fun onCreate(savedInstanceState: Bundle?) {
       super.onCreate(savedInstanceState)
       TradeDoublerSdk.getInstance().retrieveAndSetTduidFromIntent(intent)
    //or
    TradeDoublerSdk.getInstance().retrieveAndSetTduidFromUri(intent.data)
   }
}
 

By default TDUID is extracted from query parameter of URL:

https://www.your.domain.com?tduid=3e28242cd1c67ca5d9b19d2395e52941

In case of non standardized URL, it is developer responsibility to extract TDUID and set it to SDK instance. To learn more about app links, check the Testing and Troubleshooting section.

Usage

Tracking App Installation

Name Description Required
appInstallEventId Id of installation event in Tradedoubler system Yes

SDK provides a method to track installation. It should be invoked in the onCreate method of the Application class after configuring the SDK instance. No additional check is required as the framework is aware about connectivity and only one install event will be sent. To track installation you need to provide an identifier of the event used to track installation on Tradedoubler side.

class App : Application() {

   override fun onCreate() {
       super.onCreate()

       TradeDoublerSdk.create(applicationContext,initClient())
       //setup here
       //...

       TradeDoublerSdk.getInstance().trackInstall("install_app_event_id")
   }
}
 

Tracking Leads

Name Description Required
leadEventId Id of event in Tradedoubler system Yes
leadId Advertiser's unique Id of the lead Yes

SDK provides a method for tracking leads:

TradeDoublerSdk.getInstance().trackLead("lead_event_id", "lead_id")
 

Tracking Sales

Name Description Required
saleEventId Id of event in Tradedoubler system Yes
orderNumber Advertiser's unique Id of the sale Yes
orderValue Value of the order Yes
currency Currency of the order (ISO-4217) No
voucherCode Voucher code used with the sale No
reportInfo Info about basket. Each entry is: ({product_id}, {product_name}, {product_value}, {product_quantity}) No

SDK provides a method for tracking sales:

fun trackSale(){
   val orderNumber = "order_id"
   val reportInfo = ReportInfo(
       listOf(
           ReportEntry("25","bike", 21.0,3),
           ReportEntry("453","doll", 3.5,12)
       )
   )
   val price = reportInfo.getOrderValue()
   TradeDoublerSdk.getInstance().trackSale(saleEventId, orderNumber, price, "PLN","13131313", reportInfo)
}

Tracking Product Level Tracking Sales

Name Description Required
saleEventId Id of event in Tradedoubler system, default 51 Yes
orderNumber Advertiser's unique Id of the sale Yes
currency Currency of the order (ISO-4217) No
voucherCode Voucher code used with the sale No
reportInfo Info about basket. Each entry is: ({product_group_id}, {product_id}, {product_name}, {product_value}, {product_quantity}) Yes

SDK provides a method for product level sales tracking:

fun trackSalePlt(){
   val orderNumber = "order_number"
   val basketInfo = BasketInfo(
       listOf(
           BasketEntry("3408","1323","cookies", 23.0,5),
           BasketEntry("3168","5389","milk", 3.0,25)
       )
   )
   TradeDoublerSdk.getInstance().trackSalePlt(saleEventId, orderNumber, "PLN","13131313", basketInfo)
}

Testing and Troubleshooting


Disable Tracking

In some cases, like testing the development version of an application, we may not want to track anything. In that case we may use property isTrackingEnabled to switch off and on tracking events in application:

class App : Application() {

   override fun onCreate() {
       super.onCreate()

       TradeDoublerSdk.create(applicationContext)
	//setup here
//...
       TradeDoublerSdk.getInstance().isTrackingEnabled = false
   }
}
 

Enable Logs

By default, SDK prints only error messages like missing parameters or exceptions. In case of problems there is possibility to enable more detailed logs by changing value of isLoggingEnabled property:

class App : Application() {

   override fun onCreate() {
       super.onCreate()
       TradeDoublerSdk.create(applicationContext)
	//setup here
//...
       TradeDoublerSdk.getInstance().isLoggingEnabled = true
   }
}
 

Installing the Application from Advertising URL

The app uses Google Play install referrer library to track referral URL https://developer.android.com/google/play/installreferrer.

Known limitations:

  • Referral URL is only available if a user installs an app from Google Play app. Installing an advertising URL from a web page will not provide a proper referrer URL to the app.
  • Referrer tracking for G Suite accounts (work/school) doesn’t work by design.
  • Referrer tracking information may be available up to 90 days.

You can test referral tracking for you application using Google Play beta program: https://support.google.com/googleplay/android-developer/answer/9845334?hl=en.

To install app you need to provide advertising URL with parameter referrer:

https://play.google.com/store/apps/details?id=your.packagename&referrer=tduid%3Dtduid_value¶m2=1

Only referrer parameter parts from query params are available for the application. In most cases it contains encoded nested query string, so in a given example SDK will have access to a referral URL with value tduid=tduid_value.
SDK expects to have a TDUID parameter inside the referral URL. In case your referral URL has another format you can always extract TDUID manually and set it to the SDK instance.


Opening the Application from Advertising URL

https://developer.android.com/training/app-links
https://developer.android.com/studio/write/app-link-indexing
https://developer.android.com/training/app-links/deep-linking

As Android provides a lot of flexibility using aplinks, creating custom schemas and providing different target components for different actions, there is no way for SDK to handle retrieving TDUID form app open URL in a fully automatic way.

For the basic usage you need to follow examples for Android documentation and create an intent filter for activity that should be opened after handling the URL by your app. In this particular example we will register activity to handle link from www.your.domain.com:

<activity android:name="com.tradedoubler.MainViewActivity">
   <intent-filter>
       <action android:name="android.intent.action.VIEW" />
       <category android:name="android.intent.category.DEFAULT" />
       <category android:name="android.intent.category.BROWSABLE" />
       <data android:scheme="https" android:host="www.your.domain.com" android:pathPattern=".*"/>
   </intent-filter>
</activity>

In the next step you should handle extracting parameters from intent that will start your activity.

In the following example we will use retrieveAndSetTduidFromIntent that extracts TDUID from intent and sets its value to SDK instance for further use. Also, we use retrieved value to show information toast with extracted TDUID value:

class MainViewActivity: AppCompatActivity() {

   override fun onCreate(savedInstanceState: Bundle?) {
       super.onCreate(savedInstanceState)

       TradeDoublerSdk.getInstance().retrieveAndSetTduidFromIntent(intent)?.also {
           Toast.makeText(this@MainViewActivity, "new tduid: $it",Toast.LENGTH_LONG).show()
       }
   }
}

If the setup is correct you should now be able to simulate opening the URL from the terminal.

adb shell am start -W -a android.intent.action.VIEW -d "https://www.your.domain.com?tduid=3e28242cd1c67ca5d9b19d2395e52941"

By default you should see a prompt about opening the URL in your browser or application.

If you don’t see a prompt and the URL is always opened in the browser, something may be misconfigured or your browser may be set as the default app for this type of URLs. In this case please check default app settings.

iOS SDK installation

Framework installation is possible using Carthage dependency manager. If you've never done that before please use Carthage official documentation, it's really helpful: https://github.com/Carthage/Carthage.

Especially, if you are working on Xcode 13.0 or newer, you should carefully read informations about necessary workaround: https://github.com/Carthage/Carthage/blob/master/Documentation/Xcode12Workaround.md.

If carthage is already installed then to add framework to your project please add this line in your Cartfile:

github "https://github.com/tradedoubler/tradedoubler-ios-sdk.git" ~> 2.1.0

After downloading the repository from Carthage you need to configure dependencies manually in build phases of your project.

Min SDK Version

Repository works with iOS version 13.0 and newer.

Additional Configuration

Opening the URLs on iOS. To get TDUID it's necessary to handle URLs coming from web browsers or other apps. In order to open a normal URL with https scheme (only option for redirecting from a web browser) it will be necessary to add Associated Domains capability. This Apple documentation page may help you to do it correctly: https://developer.apple.com/documentation/safariservices/supporting_associated_domains.

Another option is to create an URL with a custom scheme to be opened from another app. For example: tduid://www.your.domain.com/?tduid=3e28242cd1c67ca5d9b19d2395e52941.

In this case you need to add custom scheme to your app, like shown on this site: https://coderwall.com/p/mtjaeq/ios-custom-url-scheme.

Additionally, in case of handling custom schemes you need to add following lines to your Info.plist dictionary (open as a source code):

<key>LSApplicationQueriesSchemes</key>

<array>

	<string>tduid</string>

</array>

Remember that if you have SceneDelegate in your project then you should make sure to handle URL not only in AppDelegate but also there. In many cases AppDelegate won’t be even notified of URL if SceneDelegate is present. Also: your app will try to open all URLs with your scheme (or your domain) and it's developer’s responsibility to check if parameters received from URL are present and in correct format (for example check their length). Setting the URL scheme offers a potential attack vector into your app.

iOS SDK initialization

If there is SceneDelegate in the project (iOS 13.0 or later, as long as SceneDelegate has not been removed from the project), the method below:

func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {

        TDSDKInterface.shared.configure({ORGANIZATION_ID}, {SECRET_CODE})

        TDSDKInterface.shared.isTrackingEnabled = true

        TDSDKInterface.shared.isLoggingEnabled = true

    }
						

is the suggested location for configuring the framework. Otherwise you need to fall back to the old AppDelegate method:

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        
        TDSDKInterface.shared.configure({ORGANIZATION_ID}, {SECRET_CODE})

        TDSDKInterface.shared.isTrackingEnabled = true

        TDSDKInterface.shared.isLoggingEnabled = true   

        return true

    }

Parameters {ORGANIZATION_ID} and {SECRET_CODE} are obligatory for the framework to work - first one in all cases of tracking, second one for all sales. You should obtain your values of these parameters from Tradedoubler. They’re stored only in the app memory, so after each launch of the app you need to call configure(). Please remember that if your project must handle iOS before 13.0 and SceneDelegate is also there, you have to implement appropriate methods in both classes.


Identify User

Hashed unique ID

To enhance the tracking between multiple browsers, apps and devices you may anonymously identify the user using a hash value calculated using their email address. By default, all identifiers are not used directly. SDK is working with SHA-256 digest of provided identifiers.

If a user is logged in, you can set the user email as an additional identifier by using userEmail property.

TDSDKInterface.shared.email = "test012345678@example.com"

SHA256 will be counted internally.

Please remember to clear this value after user logout.

TDSDKInterface.shared.email = nil

or use a convenience method:

TDSDKInterface.shared.logout()

Tradedoubler Unique ID

To bind identifiers passed to the framework in the previous paragraph we need to obtain TDUID from Tradedoubler. In iOS it may be very hard to obtain the installation URL from the Apple App Analytics. It may be possible using some 3rd parties APIs or just plainly impossible on the Apple ecosystem.

Second option is to get TDUID from the redirection URL. It’s also possible to simulate a click redirecting to the TDUID. By default TDUID is extracted from query parameter of URL:

https://www.your.domain.com?tduid=3e28242cd1c67ca5d9b19d2395e52941
In case of non standardized URL, it is the developer's responsibility to extract TDUID and set it to the SDK instance. When intercepting from the default URL obtained on the app opening two methods are important.


First is SceneDelegate’s

func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {

        configureFramework()

        for context in connectionOptions.urlContexts {

            let url = context.url

            if TDSDKInterface.shared.handleTduidUrl(url: url) {

                // now you have tduid set in framework, debug or ignore

                break

            } else {

                //failed setting tduid. Not default URL structure or no tduid parameter obtained

            }

        }

    }

Second being AppDelegate’s

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {

        if let url = launchOptions?[UIApplication.LaunchOptionsKey.url] as? URL {

            if TDSDKInterface.shared.handleTduidUrl(url: url) {

                // now you have tduid set in framework

            } else {

                //failed setting tduid. Not default URL structure or no tduid parameter obtained

            }

        }

Also, when app has been already open the methods of interest are:

func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {

        for context in URLContexts {

            let url = context.url

            if tradeDoubler.handleTduidUrl(url: url) {

                // now you have tduid set in framework, debug or ignore

                break

            } else {

                //failed setting tduid. Not default URL structure or no tduid parameter obtained

            }

        }

    }

And

func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {

        if TDSDKInterface.shared.handleTduidUrl(url: url) {

            // now you have tduid set in framework

        } else {

            //failed setting tduid. Not default URL structure or no tduid parameter obtained

        }

        return true

    }

Also remember that on devices with iOS 14.0 and later AppDelegate method directly above won’t get called. Convenience method handleTduidUrl(url:) may be used only for default URL structure. If a custom URL was used tduid should be set directly using

TDSDKInterface.shared.tduid = "tduid_obtained_from_a_custom_url"

Usage

Tracking App Installation

Name Description Required
appInstallEventId Id of installation event in Tradedoubler system Yes

For tracking app installation in iOS we have prepared the following method:

@discardableResult public func trackInstall(appInstallEventId: String) -> Bool 
 

It’s usage is limited. App Store does not offer any API to retrieve installation referrer URL or pass any parameters to installed app. Having users email address set in framework on app’s first run might increase the accuracy of app install tracking. Otherwise iOS installation tracking is relying on probabilistic tracking approach.

The only parameter is trackInstall event identifier, obtained from Tradedoubler.

Returned flag informs if the URL(s) were created (disabled tracking, trying to run this method more than once after installation or not having user identifiers set in the app will take effect in returning false). For the majority of use cases return should be ignored.

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {

        //configure framework here, including retrieving TDUID

        TDSDKInterface.shared.trackInstall(appInstallEventId: sdk_app_install)

Tracking Leads

Name Description Required
leadEventId Id of event in Tradedoubler system Yes
leadId Advertiser's unique Id of the lead Yes

SDK provides a method for tracking leads. Returned flag is signalling if the URL(s) was / were created and may be safely discarded.

func sdkLead() {

        TDSDKInterface.shared.trackLead(leadEventId: sdk_lead, leadId: "1234")

    }

Tracking Sales

Name Description Required
saleEventId Id of event in Tradedoubler system Yes
orderNumber Advertiser's unique Id of the sale Yes
orderValue Value of the order Yes
currency Currency of the order (ISO-4217) No
voucherCode Voucher code used with the sale No
reportInfo Info about basket. No

SDK provides a method for tracking sales. As in every other tracking methods - returned flag is discardable and is true if URL(s) was / were created.

func sdkSale() {

        let reportInfo = ReportInfo(entries: 
		[ReportEntry(id: "123", productName: "milk", price: 2.15, quantity: 3),
        	ReportEntry(id: "456", productName: "tea", price: 1.00, quantity: 3)])

        TDSDKInterface.shared.trackSale(saleEventId: sdk_sale_2, orderNumber: "14", orderValue: reportInfo.orderValue, currency: "EUR", voucherCode: nil, reportInfo: reportInfo)

    }

Tracking Product Level Tracking Sales

Name Description Required
saleEventId Id of event in Tradedoubler system, default 51 Yes
orderNumber Advertiser's unique Id of the sale Yes
currency Currency of the order (ISO-4217) No
voucherCode Voucher code used with the sale No
reportInfo Info about basket. Yes

SDK provides a method for product level sales tracking. As in every other tracking methods - returned flag is discardable and is true if URL(s) was / were created.

func sdkSalePLT() {

        let reportInfo = BasketInfo(entries: 

    		[BasketEntry.init(group: sdk_group_1, id: "123", productName: "milk", price: 2.15, quantity: 3),

    		BasketEntry.init(group: sdk_group_2, id: "456", productName: "tea", price: 1.00, quantity: 3)]) 

        TDSDKInterface.shared.trackSalePlt(orderNumber: "28", currency: "EUR", voucherCode: nil, reportInfo: reportInfo)

        //or if you have custom event identifier (not 51)

        //TDSDKInterface.shared.trackSalePlt(saleEventId: custom_value, orderNumber: "28", currency: "EUR", voucherCode: nil, reportInfo: reportInfo)

 }

Testing and Troubleshooting


Disable Tracking

In some cases, like testing the development version of an application, we may not want to track requests (although it effectively disables every feature you may expect from our framework). In this case property isTrackingEnabled TDSDKInterface singleton object allows us to make an appropriate setting.

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {

        (...)

        TDSDKInterface.shared.isTrackingEnabled = false

        return true

    }
 

Enable Logs

In some cases, like testing the development version of an application, we may not log everything happening inside the framework into the console. Flag isLoggingEnabled inside TDSDKInterface singleton object allows to mute almost all logs (except for errors).

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { 

      (...)

        TDSDKInterface.shared.isLoggingEnabled = false

        return true

    }