SegOps AIDocs

Swift SDK

Thread-safe event client for iOS, macOS, watchOS, and tvOS. Automatically flushes when your app enters the background. Requires iOS 16+ / macOS 13+ / watchOS 9+ / tvOS 16+.

Installation (Swift Package Manager)#

Add the package via Xcode: File → Add Packages, then enter the URL:

text
https://github.com/segops/sdk-swift

Or add it to your Package.swift:

swift
.package(url: "https://github.com/segops/sdk-swift", from: "0.1.0")

Then add SegOps as a dependency of your target:

swift
.target(name: "MyApp", dependencies: ["SegOps"])

Quick Start#

swift
import SegOps

// AppDelegate or App struct — create once
let segops = SegOpsClient(options: .init(
    apiURL: URL(string: "https://api.segops.ai")!,
    apiKey: "sk_..."
))

// Track an event
segops.track(SegOpsEvent(
    userId: "user-123",
    eventType: "order_placed",
    payload: ["order_id": "ord-456", "total": 89.95]
))

// Identify a user
segops.identify(SegOpsContext(
    userId: "user-123",
    traits: ["email": "[email protected]", "plan": "starter"]
))

// Flush before the app goes to background (also happens automatically on iOS)
segops.flush()

App Lifecycle Integration#

The SDK automatically flushes on UIApplication.didEnterBackgroundNotification (iOS). For SwiftUI apps, you can also flush when the scene becomes inactive:

swift
import SwiftUI
import SegOps

@main
struct MyApp: App {
    let segops = SegOpsClient(options: .init(
        apiURL: URL(string: "https://api.segops.ai")!,
        apiKey: "sk_..."
    ))

    @Environment(\.scenePhase) private var scenePhase

    var body: some Scene {
        WindowGroup {
            ContentView()
        }
        .onChange(of: scenePhase) { phase in
            if phase == .background || phase == .inactive {
                segops.flush()
            }
        }
    }
}

Public keys (recommended for mobile apps)#

A secret key (sk_…) must never ship inside an app binary — anyone can extract it. Instead, create a public key (pk_…), which is safe to embed. When the apiKey starts with pk_, the SDK runs the session handshake: it exchanges the key for a short-lived JWT via POST /api/auth/session/, caches it, and re-mints on expiry/401 — all transparently.

To bind events to a logged-in user, sign the user_id on your backend (HMAC-SHA256 over "\(userId)|\(unixSeconds)" with the key's HMAC secret) and return it from userProvider:

swift
let segops = SegOpsClient(options: .init(
    apiURL: URL(string: "https://api.segops.ai")!,
    apiKey: "pk_...",
    userProvider: {
        SegOpsUserContext(
            userId: currentUser.id,
            userIdSig: signed.sig,   // from your backend
            userIdTs: signed.ts
        )
    }
))

For anonymous visitors, omit userProvider (or return SegOpsUserContext(anonymousId:)).

Tip
Enable "require signed user_id" on the public key so the server rejects unsigned or forged identities. Keys used by mobile apps should have an empty origin allowlist (mobile clients send no Origin header).

Constructor Options#

Pass a SegOpsOptions value to SegOpsClient(options:):

FieldTypeRequiredDescription
apiURLURLYesBase URL of your SegOps deployment
apiKeyStringYesPublic key (pk_…, recommended for apps) or secret key (sk_…, server-side only)
userProvider() -> SegOpsUserContextNoRequired with a pk_ key: returns the current user at mint time. Defaults to anonymous.
batchSizeIntNoMax events before auto-flush. Default: 20
flushIntervalTimeIntervalNoPeriodic flush interval in seconds. Default: 5.0
onError(Error) -> VoidNoCalled when a flush fails. Defaults to printing to stderr.

Methods#

track(_ event: SegOpsEvent)

Enqueue a user event. Thread-safe, non-blocking.

swift
segops.track(SegOpsEvent(
    userId: "user-123",
    eventType: "order_placed",
    occurredAt: Date(),       // optional, defaults to now
    payload: [
        "order_id": "ord-456",
        "total": 89.95
    ]
))

identify(_ context: SegOpsContext)

Record user traits as a context_identified event.

swift
segops.identify(SegOpsContext(
    userId: "user-123",
    traits: ["email": "[email protected]", "plan": "starter"]
))

flush()

Flush all buffered events immediately (fire-and-forget, runs on a background URLSession task).

swift
segops.flush()
Tip
On iOS the SDK flushes automatically on background. For macOS / pure-SwiftUI apps that don't use UIKit, call flush() manually when appropriate (e.g. in a .onChange(of: scenePhase) handler).

Types#

swift
public struct SegOpsEvent: Sendable {
    public let userId: String
    public let eventType: String
    public let occurredAt: Date?           // defaults to now
    public let payload: [String: any Sendable]
}

public struct SegOpsContext: Sendable {
    public let userId: String
    public let traits: [String: any Sendable]
}

// Supplied to userProvider when authenticating with a pk_ key.
public struct SegOpsUserContext: Sendable {
    public let userId: String?       // omit for anonymous visitors
    public let anonymousId: String?
    public let userIdSig: String?    // hex HMAC signature from your backend
    public let userIdTs: Int?        // unix-seconds paired with userIdSig
}