Quickstart

Four steps from an empty project to a dashboard that says Connected. Requires iOS 18+, iPadOS 18+ or macOS 15+, and a Swift 6.2 toolchain.

1. Add the package

.package(url: "https://github.com/awizemann/swift-stats.git", from: "0.2.0")

.target(name: "MyApp", dependencies: [
    .product(name: "Stats", package: "swift-stats"),
    .product(name: "StatsCloudflare", package: "swift-stats")
])

2. Configure once at launch

Constructing a client does no disk I/O, so this is safe on the main actor during launch. CloudflareEndpoint validates the URL and is HTTPS-only, so it throws.

import Stats
import StatsCloudflare

func makeStats(writeKey: String) throws -> StatsClient {
    StatsClient(configuration: StatsConfiguration(
        appId: "com.example.MyApp",
        projectId: "myapp",
        installIdSalt: "a-constant-per-app-string",
        sink: CloudflareSink(
            endpoint: try CloudflareEndpoint(string: "https://api.swiftstats.co"),
            writeKey: writeKey
        ),
        flushAt: 20,
        flushInterval: .seconds(30),
        autoEvents: [.appOpen, .appBackground, .sessions]
    ))
}

3. Drive the lifecycle

The SDK installs no AppKit or UIKit observers — a library that silently hooks your app lifecycle isn't auditable. Two calls from scenePhase give you app open, app background and the flush on background.

.onChange(of: scenePhase) { _, phase in
    Task {
        switch phase {
        case .active:     await stats.applicationDidBecomeActive()
        case .background: await stats.applicationDidEnterBackground()
        default: break
        }
    }
}

4. Track

Names are snake_case. Properties are flat and must never carry user text. track() returns once the event is on disk, not once it is sent.

await stats.track("project_opened", props: ["section": "analytics", "cached": true])
Pick an installIdSalt and never change it. It is not a secret and grants nothing; its only job is to stop the same random UUID being correlatable across apps. Changing it re-identifies every install as new.