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?