Skip to documentation

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:

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

If you manage dependencies in Package.swift, use the binary release package and product:

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

swift
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

swift
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 navigation
  • screen_visit — a structured visit closed on navigation/background with dwell, engagement counts, screen identity, and flow metadata
  • session_start / session_end
  • tap — button taps and gesture recognizers
  • crash — captured crash and exception diagnostics
  • network — optional sanitized request aggregates and route diagnostics
  • 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 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.

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("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 flavor, 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_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:

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

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

swift
balanceLabel.kxRedact = true
cardNumberField.kxRedact = true

Tip

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:

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

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

swift
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 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()