Skip to main content
The Swift SDK tracks events and structured logs from your Apple apps. It’s a client SDK — you configure a singleton once at launch, and it handles device IDs, sessions, and delivery automatically. Events called before initialization completes are queued and replayed. Your app never blocks on network I/O.

Installation

Add the package in Xcode: File > Add Package Dependencies and enter:
https://github.com/tell-rs/sdk-swift.git
Or in your Package.swift:
dependencies: [
    .package(url: "https://github.com/tell-rs/sdk-swift.git", from: "1.0.0")
]
Requires iOS 16.0+, macOS 13.0+, or visionOS 1.0+, with Swift 6.0+ and Xcode 16.0+.

Quick start

import Tell

// Configure once at app startup
Tell.shared.configure(apiKey: "a1b2c3d4e5f60718293a4b5c6d7e8f90", preset: .production)

// Track events
Tell.shared.track(.pageViewed, properties: ["url": "/home"])

// Identify users
Tell.shared.identify("user_123", traits: ["name": "Jane", "plan": "pro"])
That’s it. The SDK generates a device ID, starts a session, collects device context, and batches events over TCP. Events fired before configure completes are queued (up to 1,000) and sent once ready.

Configuration

Use a preset for one-line setup, or pass individual parameters.
// Production — collect.tell.rs:50000, batch 100, flush 10s
Tell.shared.configure(apiKey: "YOUR_API_KEY", preset: .production)

// Development — localhost:50000, batch 10, flush 2s
Tell.shared.configure(apiKey: "YOUR_API_KEY", preset: .development)
For fire-and-forget initialization (returns immediately, connects in the background):
Tell.shared.configureAsync(
    apiKey: "YOUR_API_KEY",
    endpoint: "collect.tell.rs:50000",
    batchSize: 100,
    flushInterval: 10,
    logLevel: .debug
)
For async initialization with error handling:
try await Tell.shared.configure(
    apiKey: "YOUR_API_KEY",
    sessionTimeout: 30 * 60,
    defaultOptOut: false,
    onError: { error in print("Tell: \(error)") }
)
The API key must be a 32-character hex string.

Tracking events

No user ID needed — the SDK tracks the current user automatically (anonymous until you call identify).
// Typed event names
Tell.shared.track(.featureUsed, properties: [
    "feature": "dark_mode",
    "enabled": true
])

// String event names
Tell.shared.track("Custom Event", properties: ["key": "value"])

// No properties
Tell.shared.track(.pageViewed)

Standard event names

The SDK provides strongly typed constants for common events:
Tell.shared.track(.pageViewed, properties: ["url": "/pricing"])
Tell.shared.track(.userSignedUp, properties: ["source": "organic"])
Tell.shared.track(.orderCompleted, properties: ["total": 99.00])
Tell.shared.track(.featureUsed, properties: ["feature": "export"])
Tell.shared.track(.subscriptionStarted, properties: ["plan": "pro"])
Constants cover user lifecycle, revenue, subscriptions, trials, shopping, engagement, communication, and session events. Custom string names always work too.

Revenue

Track purchases with typed currency codes:
Tell.shared.revenue(
    amount: 49.99,
    currency: .usd,
    orderID: "order_456",
    properties: ["product": "annual_plan"]
)
The SDK includes constants for 60+ currencies (.usd, .eur, .gbp, .jpy, .btc, etc.) and accepts custom currency strings via Currency("XYZ").

User identity

// Identify a known user — stores the ID for all subsequent events
Tell.shared.identify("user_123", traits: [
    "name": "Jane",
    "email": "[email protected]",
    "plan": "pro"
])

// Associate user with a group
Tell.shared.group("company_456", properties: [
    "name": "Acme Corp",
    "plan": "enterprise"
])

// Link two identities
Tell.shared.alias("anon_visitor_abc", userId: "user_123")

Super properties

Register properties that get merged into every track, group, and revenue call:
Tell.shared.register(["app_version": "2.1.0", "env": "production"])

// This track call automatically includes app_version and env
Tell.shared.track(.featureUsed, properties: ["feature": "export"])

// Remove a super property
Tell.shared.unregister("env")
Event-specific properties override super properties when keys conflict.

Structured logging

Send logs alongside events through the same pipeline:
Tell.shared.logError("Payment failed", service: "billing", data: [
    "error": "card_declined",
    "amount": 9.99
])

Tell.shared.logInfo("User signed in", service: "auth", data: [
    "method": "oauth"
])

Tell.shared.logWarning("High memory usage", service: "app")
The service parameter defaults to "app". Convenience methods are available for all nine RFC 5424 levels: logEmergency, logAlert, logCritical, logError, logWarning, logNotice, logInfo, logDebug, and logTrace.

Sessions

Sessions are managed automatically. The SDK:
  1. Generates a persistent device ID (stored in UserDefaults)
  2. Creates a new session on launch with a device context snapshot
  3. Tracks app background/foreground transitions
  4. Starts a new session if the app was backgrounded longer than sessionTimeout (default: 30 minutes)
Device context collected automatically includes device model, OS version, app version, screen dimensions, locale, timezone, and battery state (iOS).

Privacy

// Stop all data collection — events are dropped locally
Tell.shared.optOut()

// Resume data collection
Tell.shared.optIn()

// Check current state
if Tell.shared.isOptedOut() {
    // Show consent prompt
}
Opt-out state is persisted across sessions. For privacy-first apps, set defaultOptOut: true during configuration so new users start opted out. When opted out, all tracking and logging calls silently drop. flush() and close() still work.

Lifecycle

// Force-send all queued events
try await Tell.shared.flush()

// Reset user — generates new anonymous ID, clears super properties
Tell.shared.reset()

// Graceful shutdown
try await Tell.shared.close()
Call reset() on logout to start a fresh anonymous session for the next user.

Advanced

Configuration reference

ParameterDefaultDescription
endpointcollect.tell.rs:50000TCP collector address
batchSize100Events per batch before auto-flush
flushInterval10sTime between auto-flushes
sessionTimeout30 minBackground time before new session
defaultOptOutfalseInitial opt-out state for new users
generateEventIdsfalseClient-side event deduplication IDs
logLevel.infoSDK internal log verbosity

Validation rules

FieldRule
API key32-character hex string
Event name1–256 characters
Log message1–65,536 characters
User IDNon-empty
Group IDNon-empty
Order IDNon-empty
Revenue amountPositive number

Pre-initialization queue

Events called before configure completes are buffered (up to 1,000 items). On overflow, the oldest event is dropped. Once initialization succeeds, all queued events are replayed in order.