RakutenAdvertisingAttribution iOS SDK

Our attribution SDK enables you to track app activity, including installs and purchase events, within your affiliate program.

Important: We recommend reading through the entire SDK documentation before beginning your SDK integration to make sure everything is clear. Your Implementation Specialist is happy to answer any questions you may have. Engineering support is also available to you as needed.

PR Unit Tests RakutenAdvertisingAttribution GitHub Platform

Requirements

  • iOS 11.0+
  • Xcode 11+
  • Swift 5+

Import the attribution SDK into your iOS workspace

CocoaPods

Use CocoaPods to install attribution SDK as a pod. If you don’t have Cocoapods installed, follow this guide for intallations. If you have Cocopods already installed add the following lines in your Podfile:

source 'https://github.com/CocoaPods/Specs.git'
source 'https://github.com/Rakuten-Advertising-Developers/Specs.git'

target 'YOUR_TARGET_NAME' do

  use_frameworks!
  pod 'RakutenAdvertisingAttribution'

end

Run the following command from your project’s Podfile location

pod install --repo-update 
Swift Package Manager

Also you can use the Swift Package Manager as integration method. If you want to use the Swift Package Manager as integration method, either use Xcode to add the package dependency or add the following dependency to your Package.swift:

dependencies: [
    .package(name: "RakutenAdvertisingAttribution", 
             url: "https://github.com/Rakuten-Advertising-Developers/RakutenAdvertisingAttribution-iOS-SDK.git", 
             .upToNextMajor(from: "1.0.0"))
]

Creating public/private key pairs

To integrate the SDK into your application, you must generate public/private key pairs using the following commands.

openssl genrsa -out rad_rsa_private.pem 4096
openssl rsa -in rad_rsa_private.pem -outform PEM -pubout -out rad_rsa_public.pem

The above commands will create the following two files.

  1. rad_rsa_private.pem: Store this private key securely. This key is required by the SDK to report events to our attribution server in a secured manner. We recommend obfuscating the private key which is required during SDK initialization. To obfuscate the private key, follow the instructions the “Private Key Obfuscation steps” section.
  2. rad_rsa_public.pem: This file is required by our attribution server to verify the signature.

Note: Email the rad_ras_public.pem public key and your app bundle id details to ra-sdk-support@mail.rakuten.com

Setup attribution SDK initialization

Optionally you can obfuscate your key using the following guide

In your AppDelegate application:didFinishLaunchingWithOptions: initialize Configuration struct

let configuration = Configuration(key: PrivateKey.data(value: <Your Private Key>), 
                                  launchOptions: launchOptions)

Optionally you can provide another server information, for example for stage environment

let backendInfo = BackendInfo.stageConfiguration
let configuration = Configuration(key: PrivateKey.data(value: <Your Private Key>), 
                                  launchOptions: launchOptions, 
                                  backendURLProvider: backendInfo)

Then pass it to SDK

RakutenAdvertisingAttribution.setup(with: configuration)

According to User Privacy and Data Use SDK will ignore any events until user consent will be provided. To do this you have to provide next parameters

RakutenAdvertisingAttribution.shared.adSupport.isTrackingEnabled = true
RakutenAdvertisingAttribution.shared.adSupport.advertisingIdentifier = <IDFA_VALUE>

You can also retrive this value via ASIdentifierManager by yourself or using IDFAFetcher helper class which provided as part of SDK.

fetchIfAuthorized checks current user’s consent state and fetch values. It’s common practise to call this function along with SDK configuration code and provide needed IDFA values as soon as possible.

IDFAFetcher.fetchIfAuthorized {
    RakutenAdvertisingAttribution.shared.adSupport.isTrackingEnabled = $0
    RakutenAdvertisingAttribution.shared.adSupport.advertisingIdentifier = $1.uuidString
}

In case you haven’t ask user’s consent previously, call requestTracking function to do this, at an appropriate time in your app (SDK will ignore all events until receive consent from user)

IDFAFetcher.requestTracking {
    RakutenAdvertisingAttribution.shared.adSupport.isTrackingEnabled = $0
    RakutenAdvertisingAttribution.shared.adSupport.advertisingIdentifier = $1.uuidString
}

Don’t forget to add to Info.plist tracking usage description information

<key>NSUserTrackingUsageDescription</key>
<string>This identifier will be used to deliver personalized ads to you.</string>

Our attribution SDK provides a function (resolve) to capture app install events automatically. Simply call the RakutenAdvertisingAttribution.shared.linkResolver.resolve function in AppDeletgate foreground method. In your AppDelegate use:

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

    RakutenAdvertisingAttribution.shared.linkResolver.resolve(url: url)
    return true
}

func application(_ application: UIApplication,
                continue userActivity: NSUserActivity,
                restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {

    RakutenAdvertisingAttribution.shared.linkResolver.resolve(userActivity: userActivity)
    return true
}

Optionally you can use delegate property of linkResolver, to handle data from the response

class LinkResolveHandler {
    ...
}

extension LinkResolveHandler: LinkResolvableDelegate {

    func didResolveLink(response: ResolveLinkResponse) {

        DispatchQueue.main.async {
            // handle response
        }
    }

    func didFailedResolve(link: String, with error: Error) {

        DispatchQueue.main.async {
            // error case handling
        }
    }
}

...

var handler = LinkResolveHandler()

...

RakutenAdvertisingAttribution.shared.linkResolver.delegate = handler

When the app launches for the first time after installation, the resolve() method flags the session as the first session and our attribution server records the event as an INSTALL.

Important: When resolve() is called, our attribution server will attempt to attribute the event to an affiliate link referral. Please follow your business requirement on when to call resolve(). Any excluding logic is the individual developer’s responsibility; however, we have included the following sample code to illustrate how to call resolve() for specific traffic.

func shouldIgnoreLinkResolver(userActivity: NSUserActivity) -> Bool {
    guard userActivity.activityType == NSUserActivityTypeBrowsingWeb,
          let incomingURL = userActivity.webpageURL,
          let host = incomingURL.host else { return false }
    let excludedDomains: Set<String> = ["example.com", "excluded.com"]
    return excludedDomains.contains(host)
}

func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
    if !shouldIgnoreLinkResolver(userActivity: userActivity) {
            RakutenAdvertisingAttribution.shared.linkResolver.resolve(userActivity: userActivity)
        }
    return true
}

Handling Purchase Events

Our attribution SDK provides a function RakutenAdvertisingAttribution.shared.eventSender to capture in-app purchase events. Upon successfully completing the order processing routine, call the RakutenAdvertisingAttribution.shared.eventSender function passing details about the purchase.

Sample purchase event reporting code:

// Item level details (item1)
let content1: EventContentItem = [.price: 100,
                                  .quantity: 1,
                                  .sku: "788672541568328428",
                                  .productName: "First Product Name"]
// Item level details (item2)
let content2: EventContentItem = [.price: 150,
                                  .quantity: 2,
                                  .sku: "788672541527138674",
                                  .productName: "Second Product Name"]
// if you have more items continue with content3, content4 and so on and include in the Event() as below
// Order details 
let eventData = EventData(transactionId: "12345",
                                         currency: "USD",
                                         revenue: 415,
                                         shipping: 15,
                                         tax: 7)                                
let event = Event(name: "PURCHASE",
                  eventData: eventData,
                  contentItems: [content1, content2])
RakutenAdvertisingAttribution.shared.eventSender.send(event: event)

Similarly, you can use delegate property of eventSender, to track status of sending events

class EventSenderHandler {
    ...
}

extension EventSenderHandler: EventSenderableDelegate {

    func didSend(eventName: String, resultMessage: String) {

        DispatchQueue.main.async {
            // handle result
        }
    }

    func didFailedSend(eventName: String, with error: Error) {

        DispatchQueue.main.async {
            // error case handling
        }
    }
}

...

var handler = EventSenderHandler()

...

RakutenAdvertisingAttribution.shared.eventSender.delegate = handler

Debugging

For debugging enable the logger as below:

RakutenAdvertisingAttribution.shared.logger.enabled = true

Once the logging flag enabled, you will be able to see resolve() and sendEvent() request and response payloads in the debug console.

Sample debug log:

RakutenAdvertisingAttribution.Logger 
----->
POST https://attribution-sdk-endpoint-z7j3tzzl4q-uc.a.run.app/v2/resolve-link-rak
HEADERS: {
  "Content-Type" : "application\/json",
  "Authorization" : "Bearer eyJ0eX <...> EuY"
}
BODY: {
  "device_data" : {
    "is_simulator" : true,
    "os" : "iOS",
    "device_id" : "DA128118-C52B-4EAA-9F65-4C6A6F686F66",
    "screen_width" : 414,
    "model" : "iPhone",
    "os_version" : "14.0",
    "screen_height" : 896,
    "ios_vendor_id" : "DA128118-C52B-4EAA-9F65-4C6A6F686F66",
    "fingerprint" : "{\"userAgent\":\"Mozilla\/5.0 (iPhone; CPU iPhone OS 14_0 like Mac OS X) AppleWebKit\/605.1.15 (KHTML, like Gecko) Mobile\/15E148\",\"webdriver\":false,\"language\":\"en-us\",\"colorDepth\":32,\"deviceMemory\":\"not available\",\"pixelRatio\":2,\"hardwareConcurrency\":\"not available\",\"screenResolution\":[896,414],\"availableScreenResolution\":[896,414],\"timezoneOffset\":-180,\"timezone\":\"Europe\/Kiev\",\"sessionStorage\":true,\"localStorage\":true,\"indexedDb\":true,\"addBehavior\":false,\"openDatabase\":false,\"cpuClass\":\"not available\",\"platform\":\"iPhone\",\"doNotTrack\":\"not available\",\"webglVendorAndRenderer\":\"Apple Inc.~Apple GPU\",\"adBlock\":false,\"hasLiedLanguages\":false,\"hasLiedResolution\":false,\"hasLiedOs\":false,\"hasLiedBrowser\":false,\"touchSupport\":[5,true,true],\"fontsFlash\":\"swf object not loaded\",\"audio\":\"35.10892752557993\",\"ip\":\"192.168.1.2\"}",
    "hardware_id_type" : "vendor_id"
  },
  "universal_link_url" : "",
  "first_session" : false,
  "user_data" : {
    "sdk_version" : "1.0.0",
    "bundle_identifier" : "com.rakutenadvertising.RADAttribution-Example",
    "app_version" : "1.0.0"
  }
}
----->

RakutenAdvertisingAttribution.Logger 
<-----
POST https://attribution-sdk-endpoint-z7j3tzzl4q-uc.a.run.app/v2/resolve-link-rak
CODE: 200
RESPONSE: {
  "session_id" : "5f6c7374421aa900012733c4",
  "link" : "",
  "click_timestamp" : 0,
  "device_fingerprint_id" : "5f6c7374421aa9000127343f"
}
<-----

IMPORTANT: We recommend disabling debugging in the production build.

Demo app

We provide a sample app that demonstrate the use of the Rakuten Advertising attribution SDK. You can find the open source application at this Git Repsitory

Example

To run the example project, clone the repo, and run pod install from the Example directory first.

Usage

All examples require import RakutenAdvertisingAttribution somewhere in the source file.

Documentation

Author

Rakuten Advertising

License

RakutenAdvertisingAttribution iOS SDK is available under the MIT license. See the LICENSE file for more info.