iOS SDK

The Kixo iOS SDK supports Swift 5.9+ and iOS 14+. Distributed via Swift Package Manager. Auto-tracks screens, taps, sessions, crashes, network requests, push notifications, and lifecycle events with a single Kixo.start call.

Installation

Swift Package Manager

In Xcode, go to File → Add Package Dependencies and enter:

text
https://github.com/kixo/kixo-ios-sdk

Configure

Initialise Kixo in your SwiftUI App struct orAppDelegate:

swift
import Kixo

@main
struct MyApp: App {
    init() {
        Kixo.start(writeKey: "YOUR_PROJECT_ID")
    }

    var body: some Scene {
        WindowGroup { ContentView() }
    }
}

Note

One line is enough — the SDK auto-detects your environment (Simulator / DEBUG → development; TestFlight → staging; App Store → production), picks the matching ingest host, and turns on every auto-tracker. Override individual flags with ConfigurationOptions(...) only when you need to.

Configuration options

swift
Kixo.start(
    writeKey: "YOUR_PROJECT_ID",
    options: ConfigurationOptions(
        autoTrackScreens:   true,
        autoTrackTaps:      true,
        autoTrackNetwork:   true,
        autoTrackCrashes:   true,
        autoTrackSessions:  true,
        autoTrackPush:      true,
        sessionTimeout:     30,
        flushInterval:      30,
        flushAt:            20,
        maxBufferSize:      200,
        // apiHost:    nil  → resolved from environment
        // debug:      nil  → true in DEBUG, false otherwise
        // environment: nil → auto-detected
    )
)

Note

Server-controlled config.Every per-tracker flag can also be flipped from your dashboard'sSettings → Data Collection page. Server values override local defaults; project preferences override admin globals.

Auto-tracked events

  • screen_view — UIKit view-controller appearances + SwiftUI navigation
  • session_start / session_end
  • tap — button taps and gesture recognisers
  • error / crash — uncaught exceptions, signals, NSException
  • network — HTTP request performance via URLSession swizzle
  • push_received / push_open / push_dismissed / push_silent / push_action — full push lifecycle
  • push_permission / push_token_invalidated
  • lifecycle — foreground / background / app-launch transitions

Custom events

swift
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 recognises 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.

swift
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.

swift
Kixo.identify(userId: "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.

swift
// 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.

KeyTypeDescription
$emailstringPrimary email, often the merge key for identity stitching.
$phonestringE.164 phone number.
$namestringFull display name.
$first_namestringGiven name.
$last_namestringFamily name.
$avatar_urlstringFull URL to the user's avatar image.

Geo

Geographic context.

KeyTypeDescription
$countrystringISO 3166 country code.
$citystringCity name.
$regionstringState or province.
$timezonestringIANA zone like America/Los_Angeles.
$languagestringIETF tag like en or ru-RU.
$localestringFull locale identifier.

Lifecycle

When did we see them.

KeyTypeDescription
$createdISO8601Signup or account creation time.
$last_seenISO8601Last engagement time.

Subscription

Set if your product has plans.

KeyTypeDescription
$planstringTier slug — free, pro, enterprise.
$subscription_statusstringactive / trial / cancelled / past_due.
$trial_endsISO8601When the current trial expires.
$mrrnumberMonthly recurring revenue in account currency.
$subscription_startedISO8601When the current subscription began.

E-commerce

Set if you sell products.

KeyTypeDescription
$lifetime_ordersnumberCount of completed orders.
$lifetime_revenuenumberTotal spend.
$aovnumberAverage order value.
$last_purchaseISO8601Most recent successful purchase.
$first_purchaseISO8601First successful purchase.
$cart_abandoned_countnumberLifetime count of cart abandonments.

Media

Set if you publish content.

KeyTypeDescription
$content_tierstringfree / premium / paid.
$subscribed_categoriesCSV string or arrayCategories the user follows.
$watch_time_totalnumberLifetime watch time in seconds.
$last_playedISO8601Most recent playback start.

Marketplace

Set if you're a two-sided platform.

KeyTypeDescription
$seller_tierstringSeller-side tier slug.
$buyer_tierstringBuyer-side tier slug.
$listings_countnumberActive listings the user owns.
$reviews_countnumberReviews the user has received.
$verifiedbooleanKYC status.

Loyalty

Set for engagement and rewards programs.

KeyTypeDescription
$loyalty_pointsnumberCurrent redeemable points balance.
$vip_levelstringVIP tier slug.
$referral_countnumberSuccessful 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 flavour, opted-in feature flags. Persisted in UserDefaults across launches; cleared on reset(). Per-event properties on track always win on collision.

swift
Kixo.setSuperProperty("build_flavour", 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_flavour")
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:

swift
struct HomeView: View {
    var body: some View {
        VStack { Text("Welcome") }
            .kixoScreen("HomeView")
    }
}

Push notifications

The SDK installs a runtime AppDelegate proxy on Kixo.start — 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:

swift
func application(
    _ application: UIApplication,
    didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data
) {
    let token = deviceToken.map { String(format: "%02x", $0) }.joined()
    Kixo.setPushToken(token)
}

Feature flags

swift
let variant = Kixo.getFeatureFlag("new_checkout")

if variant == "enabled" {
    showNewCheckout()
}

Resilience model

The SDK ships with a four-stage state machine that makes it safe to embed in production iOS apps:

  • initialising — set the moment Kixo.start runs. Events that auto-trackers fire before the first config response are dropped on the floor (the server may say paused: truefor the project or this SDK version, and we shouldn't buffer events for a session we're about to silence).
  • running — first config response succeeds. Events flow normally. Failed batches retry on a 5 / 10 / 20 / 30 / 60 s schedule; 10 consecutive failures move to a 60 s heartbeat; 30 failures move to a 30-minute cooldown.
  • recovering — instead of hammering the batch endpoint forever during cooldown, the SDK pauses and re-fetches /api/sdk/init. If the server returns paused: true mid-outage, the SDK transitions to pausedByServer.
  • pausedByServer — events drop at enqueue time. The SDK polls config periodically and resumes on un-pause.

The local queue caps at 200 events with FIFO drop-oldest, so a long offline window can never exhaust process memory. Retry delays carry ±25 % jitter to spread reconnects across the fleet.

Diagnostics

Read-only health snapshot. Useful in debug screens or smoke tests — answers "why aren't my events flowing?" without a debugger.

swift
let diag = Kixo.diagnostics()
print(diag.queue.bufferedEventCount)  // events waiting to flush
print(diag.queue.retryTier)            // healthy | rapid | slow | cooldown
print(diag.paused)                     // server kill-switch state
print(diag.environment)                // resolved env
print(diag.apiHost)                    // resolved ingest host

Force 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.

swift
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.

swift
Kixo.reset()