> ## Documentation Index
> Fetch the complete documentation index at: https://docs.tell.rs/llms.txt
> Use this file to discover all available pages before exploring further.

# Swift SDK

> Track events and logs from iOS, macOS, and visionOS apps.

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/tell-swift.git
```

Or in your `Package.swift`:

```swift theme={null}
dependencies: [
    .package(url: "https://github.com/tell-rs/tell-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

```swift theme={null}
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.

```swift theme={null}
// 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):

```swift theme={null}
Tell.shared.configureAsync(
    apiKey: "YOUR_API_KEY",
    endpoint: "collect.tell.rs:50000",
    batchSize: 100,
    flushInterval: 10,
    logLevel: .debug
)
```

For async initialization with error handling:

```swift theme={null}
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`).

```swift theme={null}
// 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:

```swift theme={null}
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:

```swift theme={null}
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

```swift theme={null}
// Identify a known user — stores the ID for all subsequent events
Tell.shared.identify("user_123", traits: [
    "name": "Jane",
    "email": "jane@example.com",
    "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:

```swift theme={null}
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:

```swift theme={null}
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

```swift theme={null}
// 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

```swift theme={null}
// 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

| Parameter | Default | Description |
| - | - | - |
| `endpoint` | `collect.tell.rs:50000` | TCP collector address |
| `batchSize` | 100 | Events per batch before auto-flush |
| `flushInterval` | 10s | Time between auto-flushes |
| `sessionTimeout` | 30 min | Background time before new session |
| `defaultOptOut` | false | Initial opt-out state for new users |
| `generateEventIds` | false | Client-side event deduplication IDs |
| `logLevel` | `.info` | SDK internal log verbosity |

### Validation rules

| Field | Rule |
| - | - |
| API key | 32-character hex string |
| Event name | 1–256 characters |
| Log message | 1–65,536 characters |
| User ID | Non-empty |
| Group ID | Non-empty |
| Order ID | Non-empty |
| Revenue amount | Positive 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.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.