Tracking in iOS Applications

This guide explains how to integrate Roivenue Tracking into your iOS app to measure key user actions such as page views and conversions (e.g., purchases or custom goals).

Prerequisites

Xcode 15+

Swift 5.9+

Network permissions (internet access)

A valid Roivenue propertyId (UUID)

What the Tracking API Expects

The Roivenue endpoint accepts events in JSON format. Each event represents a user interaction and includes basic context (timestamp, device info, URL, etc.) plus optional conversion data.

{
  "propertyId": "adbfb3aa-xxxx-xxxx-xxxx-xxxxxxxx",
  "type": "pageview",
  "timestamp": "2024-10-30T07:50:40",
  "url": "https://example.com/?utm_source=facebook",
  "deviceId": "20904e-f1e3-79f2-b5b7-00d6a7bfe57e",
  "userId": "someUserHashed",
  "referer": "$direct",
  "screenWidth": 1170,
  "screenHeight": 2532,
  "utmSource": "facebook",
  "utmMedium": "cpc",
  "utmCampaign": "autumn_sale",
  "conversionType": "purchase",
  "conversionId": "ORD-001",
  "conversionValue": 149.99,
  "currencyCode": "EUR"
}

Implementation Overview

You’ll build a single reusable RoivenueTracker Swift class:

  • Automatically collects device metadata

  • Sends pageview events when views appear

  • Sends conversion events with purchase details

Capturing and Managing UTM Parameters

When the app is opened via a universal link or deep link, UTM parameters can be passed in the URL. Roivenue tracking uses these UTMs to attribute events to the correct marketing source.

Step 1 — Create the UTM Manager

Create a helper class to extract, store, and clear UTM parameters. (You might already have something similar).

import Foundation

class UTMManager {
    static let shared = UTMManager()

    private let utmKeys = [
        "utm_source",
        "utm_medium",
        "utm_campaign",
        "utm_content",
        "utm_term"
        // and more parameters like gclid
    ]

    private var sessionUTMs: [String: String] = [:]

    // Capture UTMs from the initial app open URL
    func store(from url: URL) {
        guard let components = URLComponents(url: url, resolvingAgainstBaseURL: false),
              let queryItems = components.queryItems else { return }

        var result: [String: String] = [:]
        for key in utmKeys {
            if let value = queryItems.first(where: { $0.name == key })?.value {
                result[key] = value
            }
        }

        if !result.isEmpty {
            sessionUTMs = result
        }
    }

    // Retrieve UTMs for event enrichment
    func allUTMs() -> [String: String] {
        sessionUTMs
    }

    // Reset UTMs on app cold start
    func clear() {
        sessionUTMs.removeAll()
    }
}

Step 2 — Hook into App Lifecycle

Reset UTMs on cold start, and store new ones when a deep link contains them.

import UIKit

@main
class AppDelegate: UIResponder, UIApplicationDelegate {
    func application(_ application: UIApplication,
                     didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        UTMManager.shared.clear() // reset on fresh launch
        return true
    }

    func application(_ application: UIApplication,
                     continue userActivity: NSUserActivity,
                     restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
        if let url = userActivity.webpageURL {
            UTMManager.shared.store(from: url)
        }
        return true
    }
}

Step 3 — Create the Tracker Class

import Foundation
import UIKit

struct RoivenueEvent: Codable {
    let propertyId: String
    let type: String
    let timestamp: String
    let url: String?
    let deviceId: String
    let userId: String?
    let screenWidth: Int
    let screenHeight: Int
    let conversionType: String?
    let conversionId: String?
    let conversionValue: Double?
    let currencyCode: String?
    let utmSource: String?
    let utmMedium: String?
    let utmCampaign: String?
    let utmContent: String?
    let utmKeyword: String?
}

class RoivenueTracker {
    static let shared = RoivenueTracker()

    private let endpoint = URL(string: "https://tr.roivenue.com/c")!
    private let propertyId = "adbfb3aa-xxxx-xxxx-xxxx-xxxxxxxx"
    private let deviceId = UIDevice.current.identifierForVendor?.uuidString ?? UUID().uuidString

    func trackEvent(
        type: String,
        url: String? = nil,
        userId: String? = nil,
        conversionType: String? = nil,
        conversionId: String? = nil,
        conversionValue: Double? = nil,
        currencyCode: String? = nil
    ) {
        let utms = UTMManager.shared.allUTMs()
        let event = RoivenueEvent(
            propertyId: propertyId,
            type: type,
            timestamp: ISO8601DateFormatter().string(from: Date()),
            url: url,
            deviceId: deviceId,
            userId: userId,
            screenWidth: Int(UIScreen.main.bounds.width),
            screenHeight: Int(UIScreen.main.bounds.height),
            conversionType: conversionType,
            conversionId: conversionId,
            conversionValue: conversionValue,
            currencyCode: currencyCode,
            utmSource: utms["utm_source"] ?? "$direct",
            utmMedium: utms["utm_medium"],
            utmCampaign: utms["utm_campaign"],
            utmContent: utms["utm_content"],
            utmKeyword: utms["utm_term"]
        )

        send(event)
    }

    private func send(_ event: RoivenueEvent) {
        guard let body = try? JSONEncoder().encode(event) else { return }

        var request = URLRequest(url: endpoint)
        request.httpMethod = "POST"
        request.setValue("application/json", forHTTPHeaderField: "Content-Type")
        request.httpBody = body

        URLSession.shared.dataTask(with: request).resume()
    }
}

Step 4 — Track Page Views

import SwiftUI

struct HomeView: View {
    var body: some View {
        VStack {
            Text("Home")
        }
        .onAppear {
            RoivenueTracker.shared.trackEvent(
                type: "pageview",
                url: "app://home"
            )
        }
    }
}

Step 5 — Track Conversions

RoivenueTracker.shared.trackEvent(
    type: "conversion",
    conversionType: "purchase",
    conversionId: "ORDER-001",
    conversionValue: 249.99,
    currencyCode: "EUR"
)

Last updated

Was this helpful?