Skip to main content

iOS: In-App Tracking and Attribution

BillyPix iOS SDK in app tracking and attribution

Lily Mineur avatar
Written by Lily Mineur
Updated over 2 months ago

This is a paid beta feature that only certain customers can access. If you are not part of the beta program and you would like try it as well, then contact us through support.

Latest release: 0.0.11

The BillyPixSDK takes care of in native iOS in app tracking for your Billy Grace account. Do please take a good look at the implementations details as this does need to be setup correctly for it to fully work with work AI Marketing Optimisation Software.


Introduction to In-App Tracking

In-app tracking in Billy Grace allows to measure conversions that happen inside your app and link them back to the marketing efforts that drove users there.

What’s possible?

  • Track in-app conversions that result directly from marketing campaigns.

  • Attribute those conversions to the specific marketing channel or campaign that contained a direct call-to-action button opening the app, provided the app is already installed on the user’s device when they click the ad or link.

What’s not possible?

  • Measuring app installs.

  • Stitching together web and app user journeys.

  • Attributing conversions that happen after an App Store redirect (for example, when the app needs to be installed before being opened). In these cases, the UTM parameters are lost. On iOS this happens consistently, on Android it depends on the setup.

Scenario 1

App install
Youtube view > Meta click > Google click > App interaction > Conversion
In this scenario, we are able to attribute the conversion value to Youtube, Meta & Google

Scenario 2

App not yet installed
Youtube view > Meta click > Google click > App Interaction (install) > Conversion
In this scenario, we are not able to attribute any value to Youtube, Meta or Google. However, we are able to measure the conversion.

Why it’s valuable?

Adding in-app conversions to your tracking gives you a more complete picture of your marketing performance. Instead of seeing only web-based conversions, you’ll also understand the impact of campaigns driving users directly into your app. This helps you:

  • Accurately measure all your online conversions: web and app combined.

  • See which marketing channels work best for each platform, so you can optimise campaigns specifically for app traffic or web traffic.

  • Reduce unattributed conversions, making ROI calculations more reliable.

  • Spot opportunities where app experiences lead to higher conversion rates or better customer retention.

How will you see this data in Billy Grace?

Currently, all your web and app data is combined in one view. While you cannot yet separate the two, this helps reduce the number of unattributed orders or conversions.
In the future, we will include web and app in our filtered views, allowing you to distinguish between app and web conversions, as well as the journeys leading to them.


Installation

Installation is supported both through:

A) Pod Installation

B) SPM Installation

Potential downside of doing the SPM installation in terms of a new feature we want to add late on: automated pageview tracking. The issue:

  • Swift packages don’t allow for mixed code with objective-c yet (see open issue).

  • In the near future we will be looking at adding swizzling to support (which you can optionally turn on), to automatically track pageviews, which will be written in Objective-C.

A) Pod Installation

You need to add our repo as a source url and then you can use our BillyPixSDK pod. You need to specify a version in your pod.

See here an example:

source 'https://github.com/Billy-Grace/BillyPixSDK-Podspecs.git'

target 'SampleiOSApp' do
# Comment the next line if you don't want to use dynamic frameworks
use_frameworks!

pod 'BillyPixSDK', '~> 0.0.10'

end

Then make sure to run your update or installation the --repo-update flag, so a roundtrip is made to our repo to get the latest PodSpec.

For example:

pod install --repo-update

B) SPM Installation

To install our sdk through Swift Package manager, simply use the following repo to add it to your xcode project:

Simply add the url, and choose the right version for your project.

Configuration

First make sure to copy over your own tracking id from the pixel page in the web application. It should like something like: ID-12-34567.

Then the initialization code at the first thing when your app opens need to be called. For example in the appDelegate:

import UIKit
import BillyPixSDK

@main
class AppDelegate: UIResponder, UIApplicationDelegate {

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Initialize the tracking library, as the first thing when the app starts
BillyPix.configure(trackingId: "ID-XXX-IOS")

return true
}

..............................

Other configuration options

You have multiple configuration options, you can use like for example:

countryCode

Billy grace accounts are generally scoped to 1 country while an App is mostly deployed to multiple countries. So to help differentiate between which account and country that the traffic needs to be routed to, we want to include the countryCode.

If you do not set this, then the SDK will grab the internal Locale's regioncode (so which region the user has set in their Iphone settings).

If you want to control this setting yourself, then we highly recommend you set this yourself, as it will overwrite the default we use. You set this once on BillyPix.configure, and will then be included into each event being send for that user.

BillyPix.configure(trackingId: "ID-XXX-IOS", countryCode: "NL")

BillyLogLevel

This determines from which level and up you want to see logs for, the default for this is INFO. The hierarchy for the log levels works like this:

  • VERBOSE

  • DEBUG

  • INFO

  • WARN

  • ERROR

  • NONE

So for example the following code with BillyLogLevel.debug:

BillyPix.configure(trackingId: "ID-XXX-IOS", logLevel: BillyLogLevel.debug)

Will output all the log levels from INFO and up which are: INFO, WARN and ERROR.

Attribution in app

We highly recommend you take this step as well, as we can’t run any attribution algorithms as the url the app was opened with contains the url parameters needed for attribution.

In your appdelegate or scenedelegate, add the following line of code so the tracking library can parse the url parameters:

BillyPix.handleURLOpen(url)

For example your didfinishLaunchingOptions in your app delegate will then look something like this:

import UIKit
import BillyPixSDK

@main
class AppDelegate: UIResponder, UIApplicationDelegate {

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Initialize the tracking library, as the first thing when the app starts
BillyPix.configure(trackingId: "ID-XXX-IOS")

// Check if the app was launched from a URL
if let url = launchOptions?[UIApplication.LaunchOptionsKey.url] as? URL {
BillyPix.handleURLOpen(url)
}

return true
}

If you are using another SDK that can supply you with the install url or the url the app was opened with, we still recommend you to call our sdk as well. For example:

import UIKit
import BillyPixSDK

class ViewController: BillyPixTrackingViewController {

override func viewDidLoad() {
super.viewDidLoad()

// Get the url from another sdk
let appOpenUrl = SomeOtherSdk.getOpenUrl()

// Pass it to the billy sdk
BillyPix.handleURLOpen(appOpenUrl)
}
}

Tracking events

We recommend that you send us the following events (if applicable):

  • .pageload

  • .addToCart

  • .purchaseStarted

  • .purchase

You can define the name of event as a string or you can use the build in event name identifiers for common events (recommended).

For example using the build in event name identifiers:

BillyPix.sendEvent(.purchaseStarted, parameters: [
BgEventKey.transactionId: "123"
])

Send an event we don’t have an identifier for (so as string):

BillyPix.sendEvent("custom_event_name", parameters: [
BgEventKey.transactionId: "123"
])

The keys of the parameters for each event also have a list of predefined options we recommend you use, you can us the BgEventKey object for this. Furthermore, in this case you can also still define parameter keys as strings.

For example, this works as well:

BillyPix.sendEvent(.purchaseStarted, parameters: [
BgEventKey.transactionId: "123",
"custom_key": "some_val"
])

Pageload events

As of right now we haven’t implemented automatic pageload tracking for each page that gets opened in the app, this will soon be implemented as optional functionality by using method swizzling.

For now we are asking you to send the .pageload at each screen that gets loaded. For example when using ViewControllers you could subclass them with a another base viewcontroller that calls the tracking code.

import UIKit
import BillyPixSDK

// Subclassing you regular viewcontroller
class ViewController: BillyPixTrackingViewController {

override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
}

// Create a new class or add the code to your extisting base class
class BillyPixTrackingViewController: UIViewController {
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)

// Adding the parameters are optional, also for the 'pageload' event
let viewControllerName = String(describing: type(of: self))
BillyPix.sendEvent(.pageload, parameters: [
BgEventKey.pageName: viewControllerName
])
}
}

Do note that other tracking libraries might use different names to track the same event like pageview or page_load, but for the BillyPix tracking we always expect the event to be called pageload. So if you want to define this event as string, then please do so correctly.

Other events

Tracking any other event is pretty straightforward:

  • Make sure to import BillyPixSDK

  • The parameters can be optionally added if needed. For example events like .purchase or .addToCart you might want to make sure to use the same BgEventKey.transactionId.

Below are a few examples:

Event: Purchase

BillyPix.sendEvent(.purchase, parameters: [
BgEventKey.value: 57,
BgEventKey.transactionId: "xe3x",
])

Event: Form submission

BillyPix.sendEvent("form_submitted")

Did this answer your question?