Swift
Installation
Add Swift Package
Add Phase Analytics to your project using Swift Package Manager:
- In Xcode, go to File → Add Package Dependencies
- Enter the repository URL:
- Select the latest version
- Add to your target
Or add to Package.swift:
dependencies: [
.package(url: "https://github.com/Phase-Analytics/Phase-Swift", from: "0.1.3")
]Requirements:
- iOS 15.0+ or macOS 12.0+
- Swift 6.0+
Get Your API Key
- Sign in to Phase Dashboard
- Create a new project or select an existing one
- Open API Keys tab
- Copy your API Key (starts with
phase_)
Setup
SwiftUI
Wrap your app with the Phase view to initialize the SDK:
import SwiftUI
import PhaseAnalytics
@main
struct MyApp: App {
var body: some Scene {
WindowGroup {
Phase(apiKey: "phase_xxx") {
ContentView()
}
}
}
}UIKit
Initialize the SDK in your AppDelegate:
import UIKit
import PhaseAnalytics
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
Task {
try await PhaseSDK.shared.initialize(apiKey: "phase_xxx")
}
return true
}
}The SDK initialization is asynchronous. You must call identify() before tracking events.
Configuration
The Phase view and initialize() method accept the following parameters:
Prop
Type
Usage
Identify User
Required: Call identify() before using any other methods. This registers the device and starts a session.
import SwiftUI
import PhaseAnalytics
struct ContentView: View {
var body: some View {
Text("Hello, World!")
.onAppear {
Task {
// Initialize analytics - no PII collected by default
await PhaseSDK.shared.identify()
}
}
}
}Privacy by default:
- No personal data is collected without explicit properties
- Device ID is auto-generated and stored locally
- Only technical metadata is collected (OS version, platform, locale)
Adding custom properties:
You can optionally attach user properties. Important: If you add PII (personally identifiable information), ensure you have proper user consent:
// After user login and consent
await PhaseSDK.shared.identify([
"user_id": "123",
"plan": "premium",
"beta_tester": true
])
// ⚠️ If adding PII, get consent first
let hasConsent = await customGetUserConsent()
if hasConsent {
await PhaseSDK.shared.identify([
"email": "[email protected]",
"name": "John Doe"
])
}Properties must be primitives: String, Int, Double, Bool, or nil.
Track Events
Track custom events with optional parameters. Note: identify() must be called first.
// Event without parameters
track("app_opened")
// Event with parameters
track("purchase_completed", [
"amount": 99.99,
"currency": "USD",
"product_id": "premium_plan"
])
// Using instance method
PhaseSDK.shared.track("button_clicked", params: ["button_id": "submit"])Event naming rules:
- Alphanumeric characters, underscores (
_), hyphens (-), periods (.), and forward slashes (/) - 1-256 characters
- Examples:
purchase,user.signup,payment/success
Event parameters:
- Must be primitives:
String,Int,Double,Bool, ornil
Screen Tracking
Use the .phaseScreen() modifier to automatically track screen views:
import SwiftUI
import PhaseAnalytics
struct ProfileView: View {
let userID: String
var body: some View {
VStack {
Text("Profile")
}
.phaseScreen("ProfileView", params: ["user_id": userID])
}
}How it works:
Tracks screen view when the view first appears. Screen names are normalized automatically (e.g., "ProfileView" → "/profile-view") with CamelCase converted to kebab-case. Supports optional parameters.
Manually track screens using trackScreen():
// Using global function
trackScreen("/profile", ["user_id": "123"])
// Using instance method
PhaseSDK.shared.trackScreen("/settings", params: nil)Type Reference
DeviceProperties
Custom user/device attributes passed to identify():
Prop
Type
EventParams
Event parameters passed to track():
Prop
Type
How It Works
Offline Support
Events are queued locally using UserDefaults when offline. The queue automatically syncs when connection is restored.
Privacy
- No personal data is collected by default
- Device IDs are generated locally and stored persistently
- Geolocation is resolved server-side from IP address (disable with properties)
- All data collection is optional via configuration
Performance
- Offline events are batched and sent asynchronously
- Network state is monitored automatically
- Failed requests retry with exponential backoff
- Maximum batch size: 1000 events
- Thread-safe with Swift 6 concurrency