Swift SDK
The Oddlytics Swift package records events in your app and sends them to your Worker. It has no dependencies and works on iOS 15 or later and macOS 12 or later.
Add the Package
In Xcode:
- Choose File > Add Package Dependencies...
- Enter
https://github.com/OddOmens/Oddlytics. - Add the Oddlytics library to your app target.
In a Package.swift:
dependencies: [
.package(url: "https://github.com/OddOmens/Oddlytics", from: "1.0.0")
]Then add "Oddlytics" to your target's dependencies.
Configure at Launch
Call Analytics.configure once, as early as possible. Events tracked before it are dropped with a warning in the console.
SwiftUI:
import SwiftUI
import Oddlytics
@main
struct MyApp: App {
init() {
Analytics.configure(
endpoint: "https://oddlytics-worker.<your-subdomain>.workers.dev",
apiKey: "your-auth-key",
appId: "MyApp",
debugMode: true // false for release builds
)
}
var body: some Scene {
WindowGroup {
ContentView()
}
}
}UIKit:
import UIKit
import Oddlytics
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
Analytics.configure(
endpoint: "https://oddlytics-worker.<your-subdomain>.workers.dev",
apiKey: "your-auth-key",
appId: "MyApp"
)
Analytics.track("app_launched")
return true
}
}Every parameter is described in Configuration.
Track Events
Analytics.track("button_tapped")The event name is any string up to 255 characters. Names like screen_view or purchase_completed work well, and the dashboard can show them as "Screen View" with the Pretty Format Event Names setting.
Metadata
Attach string key-value pairs to an event:
Analytics.track("purchase_completed", metadata: [
"item_id": "prod_123",
"amount": "9.99",
"currency": "USD"
])Values are strings. Convert numbers and booleans yourself ("true", "9.99"). The whole metadata dictionary must stay under 10 KB, or the Worker rejects the batch it's in.
A common pattern is tracking screens:
HomeView()
.onAppear {
Analytics.track("screen_view", metadata: ["screen": "Home"])
}Groups
Give related events a group, and the app's dashboard page gets a section for that group:
Analytics.track("Melatonin", group: "Sleep Aids")
Analytics.track("Magnesium", group: "Sleep Aids", metadata: ["dosage": "5mg"])The group is stored in the metadata under the key group. If you also pass a group key in metadata, the group: parameter replaces it.
Sessions
Each app launch gets a random session ID (a UUID). Every event carries it, and the dashboard counts distinct session IDs as sessions. The session ID doesn't change when the app goes to the background; it changes when the app is launched again or when you call:
Analytics.resetSession()Call it at moments that should start a new session, such as when someone signs out.
Batching and Retries
Events are not sent one at a time. The package keeps a queue in memory and sends it:
- every
batchIntervalseconds (default 5), - as soon as
batchSizeevents are waiting (default 10), - when the app is about to become inactive (iOS only), and
- whenever you call
Analytics.flush().
Analytics.flush()What happens to a batch depends on the Worker's answer:
| Response | What the package does |
|---|---|
| 2xx | Done. |
| 4xx other than 429 (for example a wrong API key or an invalid event) | Drops the batch. |
| 429, 5xx, or no network | Puts the events back at the front of the queue and tries again with the next send. |
Re-queued events stay only while there are fewer than 1,000 events waiting; past that, failed batches are dropped.
WARNING
The queue lives in memory only. Events that haven't been sent when the app is terminated are lost, and nothing is saved to disk for later. A long time offline can also grow the queue past 100 events, which the Worker rejects in one request, so those events are dropped once the network returns.
What Is Collected Automatically
Every event sends these fields along with the name and metadata you give it:
| Field | Value |
|---|---|
app_id | The appId you passed to configure. |
platform | Always "iOS", also on macOS. |
session_id | A random UUID per launch (see Sessions). |
user_id | On iOS, the device's identifier for vendor (UIDevice.current.identifierForVendor). On macOS, or if that isn't available, a random UUID saved in UserDefaults under oddlytics_user_id. |
device_id | On iOS, the identifier for vendor again. Not sent on macOS. The Worker doesn't store this field. |
timestamp | When the event was tracked, in seconds since 1970. |
The package doesn't read the device model, OS version, locale, location, advertising identifier or any personal data. It sends nothing until you call track.
TIP
The identifier for vendor is the same for every app from the same developer account on a device. If several of your apps use one Oddlytics server, the dashboard can see that one person uses more than one of them. It resets when all of your apps are removed from the device.
Letting People Opt Out
The package has no opt-out switch. If you want one, keep the person's choice in your app and skip Analytics.track calls when they've opted out.
macOS
The package builds for macOS 12 or later, with two differences:
user_idis a random UUID kept inUserDefaults, and nodevice_idis sent.- There is no automatic send when the app goes to the background. Call
Analytics.flush()yourself, for example when the app is about to quit.
API Reference
All public API is on the Analytics enum.
configure(endpoint:apiKey:appId:batchSize:batchInterval:debugMode:)
static func configure(
endpoint: String,
apiKey: String,
appId: String,
batchSize: Int = 10,
batchInterval: TimeInterval = 5.0,
debugMode: Bool = false
)Sets up the package, starts the send timer and, on iOS, the send-on-inactive observer. Call it once. With debugMode, it prints the endpoint, session ID, user ID and device ID.
track(_:group:metadata:)
static func track(_ eventName: String, group: String? = nil, metadata: [String: String] = [:])Adds an event to the queue. Does nothing (and prints a warning) if configure hasn't been called.
flush()
static func flush()Sends everything in the queue now.
resetSession()
static func resetSession()Starts a new session ID for the events that follow.
Configuration
A public struct holding the same settings as configure. No public method takes it, so use configure instead. Note that its own initializer defaults differ (batchSize: 20, batchInterval: 10.0); configure passes its own defaults of 10 and 5.0.