iOS SDK
The Kixo iOS SDK supports Swift 5.9+ and iOS 16+ for analytics, attribution, push, lifecycle tracking, and session replay. Replay uses project-level capture switches and conservative defaults for its heavier pipelines; it does not impose a separate OS or device-model floor beyond the package's iOS 16 deployment target. Distributed via Swift Package Manager, the SDK auto-tracks screens, taps, sessions, crashes, push notifications, and lifecycle events with a single Kixo.configure call. Network request tracking is opt-in.
Installation
Swift Package Manager
In Xcode, go to File → Add Package Dependencies and enter:
https://github.com/kixoio/kixo-ios-sdkIf you manage dependencies in Package.swift, use the binary release package and product:
dependencies: [
.package(
url: "https://github.com/kixoio/kixo-ios-sdk",
from: "1.0.19"
),
],
targets: [
.target(
name: "YourApp",
dependencies: [
.product(name: "Kixo", package: "kixo-ios-sdk"),
]
)
]Configure
Initialize Kixo in your SwiftUI App struct orAppDelegate:
import Kixo
@main
struct MyApp: App {
init() {
Kixo.configure(
projectId: "YOUR_PROJECT_ID",
apiKey: "YOUR_API_KEY"
)
}
var body: some Scene {
WindowGroup { ContentView() }
}
}Note
One line is enough. The SDK uses the production environment by default, uses the managed ingest host, and turns on the standard auto-trackers. Override individual flags with ConfigurationOptions(...) only when you need to.
Configuration options
Kixo.configure(
projectId: "YOUR_PROJECT_ID",
apiKey: "YOUR_API_KEY",
options: ConfigurationOptions(
autoTrackScreens: true,
autoTrackTaps: true,
autoTrackNetwork: false,
autoTrackCrashes: true,
autoTrackSessions: true,
autoTrackPush: true,
sessionTimeout: 30,
flushInterval: 30,
flushAt: 20,
maxBufferSize: 200,
// apiHost: nil → managed Kixo ingest host
// debug: nil → true in DEBUG, false otherwise
// environment: nil → production
)
)Note
Server-controlled config. Every per-tracker flag can also be flipped from your dashboard's Settings → Data Collection page. Project settings can override local defaults.
Auto-tracked events
screen_view— immediate UIKit view-controller appearances + SwiftUI navigationscreen_visit— a structured visit closed on navigation/background with dwell, engagement counts, screen identity, and flow metadatasession_start/session_endtap— button taps and gesture recognizerscrash— captured crash and exception diagnosticsnetwork— optional sanitized request aggregates and route diagnosticspush_received/push_open/push_dismissed/push_silent/push_action— full push lifecyclepush_permission/push_token_invalidatedlifecycle— foreground / background / app-launch transitions
Custom events
Kixo.track("purchase_completed", properties: [
"product_id": "SKU-123",
"amount": 49.99,
"currency": "USD",
])Typed event helpers
Sugar over Kixo.track for the events Kixo recognizes by name (purchase, signup,subscribe_start, trial_start,cancel, upgrade, activation,share, invite). Compile-time validation of property shape, single source of truth on key names — backend's standard-event detector matches verbatim.
Kixo.trackPurchase(
amount: 49.99,
currency: "USD",
productId: "pro_yearly"
)
Kixo.trackSubscriptionStart(
plan: "pro",
amount: 9.99,
currency: "USD",
interval: .month
)
Kixo.trackSignup(method: "google")
Kixo.trackTrialStart(plan: "pro", days: 14)
Kixo.trackCancel(plan: "pro", reason: "too_expensive")
Kixo.trackUpgrade(fromPlan: "free", toPlan: "pro")
Kixo.trackActivation(event: "first_post_published")
Kixo.trackShare(channel: "twitter", contentId: "post_123")
Kixo.trackInvite(channel: "email", recipientCount: 5)Identify users
Reserved standard property keys carry a $-prefix (Mixpanel convention) so they namespace away from your own custom traits and promote to the dashboard's profile columns. Use the typed StandardProperty enum or the raw $-prefixed string — see the Standard property catalog below for the full 37-key list.
Kixo.identify("user_123", traits: [
"$email": "jane@example.com", // identity
"$name": "Jane Doe", // identity
"$plan": "pro", // subscription pack
"$lifetime_orders": 12, // e-commerce pack
"signup_source": "twitter_ad" // custom trait
])Tag a user for segmentation
Use setUserProperty with a boolean value to attach a simple yes/no tag to the user. The tag persists across sessions and powers segments, email campaigns, and chat queries — no setup beyond the SDK call.
// Tag a user as subscribed — segments + campaigns can target this
Kixo.setUserProperty("subscribe", value: true)
// VIP membership
Kixo.setUserProperty("vip", value: true)
// String + numeric values work too
Kixo.setUserProperty("plan_tier", value: "enterprise")
Kixo.setUserProperty("lifetime_orders", value: 42)
// Bulk-set
Kixo.setUserProperties([
"subscribe": true,
"plan_tier": "enterprise",
])Properties persist in UserDefaults across launches and auto-attach to every outbound event. In chat say things like "send a welcome email to users where subscribe is true" — Kixo builds the segment and drafts the template for you. Cleared on Kixo.reset().
Standard property catalog
Reserved property keys carry a $ prefix so they namespace away from your custom traits. Kixo's catalog covers 37 keys across 3 universal packs (identity, geo, lifecycle) and 5 B2B vertical packs (subscription, e-commerce, media, marketplace, loyalty). Set whichever apply to your product — the dashboard adapts and renders only the packs you populate.
Identity
Always relevant. Sets the profile header columns.
| Key | Type | Description |
|---|---|---|
$email | string | Primary email, often the merge key for identity stitching. |
$phone | string | E.164 phone number. |
$name | string | Full display name. |
$first_name | string | Given name. |
$last_name | string | Family name. |
$avatar_url | string | Full URL to the user's avatar image. |
Geo
Geographic context.
| Key | Type | Description |
|---|---|---|
$country | string | ISO 3166 country code. |
$city | string | City name. |
$region | string | State or province. |
$timezone | string | IANA zone like America/Los_Angeles. |
$language | string | IETF tag like en or ru-RU. |
$locale | string | Full locale identifier. |
Lifecycle
When did we see them.
| Key | Type | Description |
|---|---|---|
$created | ISO8601 | Signup or account creation time. |
$last_seen | ISO8601 | Last engagement time. |
Subscription
Set if your product has plans.
| Key | Type | Description |
|---|---|---|
$plan | string | Tier slug — free, pro, enterprise. |
$subscription_status | string | active / trial / cancelled / past_due. |
$trial_ends | ISO8601 | When the current trial expires. |
$mrr | number | Monthly recurring revenue in account currency. |
$subscription_started | ISO8601 | When the current subscription began. |
E-commerce
Set if you sell products.
| Key | Type | Description |
|---|---|---|
$lifetime_orders | number | Count of completed orders. |
$lifetime_revenue | number | Total spend. |
$aov | number | Average order value. |
$last_purchase | ISO8601 | Most recent successful purchase. |
$first_purchase | ISO8601 | First successful purchase. |
$cart_abandoned_count | number | Lifetime count of cart abandonments. |
Media
Set if you publish content.
| Key | Type | Description |
|---|---|---|
$content_tier | string | free / premium / paid. |
$subscribed_categories | CSV string or array | Categories the user follows. |
$watch_time_total | number | Lifetime watch time in seconds. |
$last_played | ISO8601 | Most recent playback start. |
Marketplace
Set if you're a two-sided platform.
| Key | Type | Description |
|---|---|---|
$seller_tier | string | Seller-side tier slug. |
$buyer_tier | string | Buyer-side tier slug. |
$listings_count | number | Active listings the user owns. |
$reviews_count | number | Reviews the user has received. |
$verified | boolean | KYC status. |
Loyalty
Set for engagement and rewards programs.
| Key | Type | Description |
|---|---|---|
$loyalty_points | number | Current redeemable points balance. |
$vip_level | string | VIP tier slug. |
$referral_count | number | Successful referrals attributed to this user. |
Tip
Don't see your pattern? Use bare keys for custom traits. They surface in the dashboard's Custom Traits panel without polluting the profile columns. The 5 vertical packs above are opinionated guesses at the most common B2B shapes — customer-specific terminology (e.g. shipping_plan) stays bare.
Super-properties
Per-session key/value pairs auto-attached to every outbound event. Different from identify traits (which describe identity); super-properties describe session context — active A/B variant, build flavor, opted-in feature flags. Persisted in UserDefaults across launches; cleared on reset(). Per-event properties on track always win on collision.
Kixo.setSuperProperty("build_flavor", value: "beta")
Kixo.setSuperProperties([
"ab_variant": "B",
"referrer_campaign": "autumn-launch",
])
// Sugar for A/B tracking — keys as 'experiment_<id>'.
Kixo.setExperimentVariant("checkout_v2", variant: "variant_a")
Kixo.unsetSuperProperty("build_flavor")
Kixo.clearSuperProperties()SwiftUI screen tracking
SwiftUI screen views are auto-tracked when the SDK can resolve a view name. For finer control or custom names use the.kixoScreen() view modifier:
struct HomeView: View {
var body: some View {
VStack { Text("Welcome") }
.kixoScreen("HomeView")
}
}Session replay
Replay reconstructs what the user actually saw — the SDK captures pixel frames of the screen (HEIC-encoded) together with a structural snapshot of the view hierarchy, and the dashboard player stitches them into scrubbable playback next to the event timeline. Configure replay for the project in Dashboard → Settings → Session replay; the SDK reads that policy automatically and refreshes it while the app is running.
Kixo.configure(
projectId: "YOUR_PROJECT_ID",
apiKey: "YOUR_API_KEY"
)The dashboard controls whether replay is enabled, masking, capture modes, and whether native replay may upload over cellular. With cellular upload disabled, frames can still capture into a bounded on-device buffer; upload waits for an allowed network.
The SDK captures the data enabled in your project and the events and properties your application sends.
Masking and privacy
Because replay captures pixels, redaction happens on-device before a frame is ever encoded. Password and other sensitive fields are auto-detected and redacted, and text captured into the structural snapshot passes through a PII filter. To redact anything custom — a private message thread, an account balance, a draft screen — set kxRedact on the view. Kixo rasterizes a solid rect over that view's bounds before HEIC encoding, so its pixels never leave the device.
balanceLabel.kxRedact = true
cardNumberField.kxRedact = trueTip
Taps captured on replayed screens also feed the dashboard's mobile heatmap, so you can see where users touch each screen without any extra SDK setup. Replay is subject to your project plan; when frame capture is unavailable, the SDK still records session metadata without uploading the frame stream.
Push notifications
The SDK installs a runtime AppDelegate proxy on Kixo.configure — silent pushes (content-available: 1) and background-delivered visible pushes are captured automatically. No code in your AppDelegate is required. ExistingUNUserNotificationCenterDelegate implementations continue to fire normally; Kixo wraps them.
Register the device token via the standarddidRegisterForRemoteNotificationsWithDeviceToken:
func application(
_ application: UIApplication,
didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data
) {
let token = deviceToken.map { String(format: "%02x", $0) }.joined()
Kixo.setPushToken(token)
}If the app uses Firebase Messaging, pass its registration token with provider: .firebase. Kixo stores that provider and delivers through FCM HTTP v1; configure the app's Firebase service account in Kixo before sending campaigns.
func messaging(_ messaging: Messaging, didReceiveRegistrationToken token: String?) {
guard let token else { return }
Kixo.setPushToken(token, provider: .firebase)
}Delivery and offline behavior
The SDK queues events locally, sends them in batches, and retries transient failures with backoff. If collection is paused from project settings, new events are not sent until collection is enabled again.
Diagnostics
Read-only health snapshot. Useful in debug screens or smoke tests — answers "why aren't my events flowing?" without a debugger.
let diag = Kixo.diagnostics()
print(diag.queue.bufferedEventCount) // events waiting to flush
print(diag.paused) // collection paused state
print(diag.environment) // configured environment
print(diag.apiHost) // configured ingest hostForce flush (for tests)
Synchronous overload that blocks up to timeout seconds on a flush completing. Designed for XCTest fixtures — never call from the main thread.
func testEventLanded() {
Kixo.track("test_event")
let landed = Kixo.flush(timeout: 5.0)
XCTAssertTrue(landed)
}Reset
Clear identity, super-properties, and the persisted queue. Call on logout so subsequent events aren't attributed to the previous user.
Kixo.reset()