iOS SDK

CohorlySwift is a standalone Swift Package for Cohorly, supporting iOS 15+ and macOS 12+. It uses URLSession for transport, batches events, and persists its queue to UserDefaults by default.

Install

CohorlySwift is distributed as a Swift Package - add it from the Cohorly package repository.

Xcode

File > Add Package Dependencies..., enter the repo URL, pick a version rule, and add the Cohorly library product to your app target.

Package.swift

swift
dependencies: [
.package(url: "https://github.com/Gitarcitano/cohorly-swift", from: "0.1.0"),
],
targets: [
.target(
name: "YourApp",
dependencies: [.product(name: "Cohorly", package: "cohorly-swift")]
),
]

Initialize

Call Cohorly.initialize once near app launch. It configures and returns the shared instance (Cohorly.shared). token is optional - omit it if you don't use per-project tokens.

swift
import Cohorly
​
let cohorly = Cohorly.initialize(token: "YOUR_PROJECT_TOKEN")
​
cohorly.register(["app_version": "1.2.0"])
cohorly.track("Screen Viewed", properties: ["screen": "Home"])
​
cohorly.identify("user_123")
cohorly.people.set(["plan": "pro"])
​
// Manually flush (also happens automatically every 5s or every 20 events).
await cohorly.flush()

API

MemberNotes
Cohorly.initialize(apiHost:token:...)Configures and returns Cohorly.shared. Also accepts transport, storage, flushInterval, flushAt.
track(_:properties:)Queue an event.
identify(_:)Set the distinct id. On the first call after being anonymous, also posts /alias linking the previous anonymous id (best effort, not retried). No-op if the id is unchanged.
reset()Clears identity, super properties, and un-flushed events. Call this on logout - see Identity.
register(_:) / unregister(_:)Super properties merged into every event.
people.set / setOnce / increment / unset / deleteUserProfile updates sent to /engage.
flush() asyncManually flush; resolves once any auto-triggered flush completes.
currentDistinctId: StringCurrent distinct id.
getFeatureFlag(_:fallback:) / isFeatureEnabled(_:fallback:)Read a flag's variant/enabled value; never hits the network.
getFeatureFlagDetails(_:fallback:)The value plus source (network / persistence / fallback) and cache metadata.
reloadFeatureFlags() async / onFeatureFlags(_:)Re-evaluate flags / subscribe to updates.

Feature flags

Flags are evaluated on initialize (opt out with loadFeatureFlags: false), on identify() and on reset(), and cached in storage scoped by distinct id; reads never hit the network.

flagPersistence (default .persistenceUntilNetworkSuccess) controls how reads resolve against the persisted cache:

PolicyBehavior
.networkOnlyNever reads nor writes the cache on the serving path (identity changes still remove it - that is hygiene, not serving). Flags come only from network responses this session; a failed evaluation serves the fallback.
.networkFirstPrefers the network, but reads are synchronous, so a valid cache (inside the TTL) is served immediately like .persistenceUntilNetworkSuccess. Strict about freshness: a cache past the TTL is dropped, never served.
.persistenceUntilNetworkSuccessServes a valid cache immediately, so startup doesn't flicker; the first network success takes over and re-persists. A failed evaluation keeps the cache serving. Trades freshness for offline availability: an expired cache still serves while inside Cohorly.flagCacheMaxStale (7 days).

The cache carries a stored_at timestamp and expires after flagCacheTTL (default 24 hours - Cohorly.defaultFlagCacheTTL, the Mixpanel reference default shared by every Cohorly SDK). A legacy cache with no timestamp cannot be dated, so it is served indefinitely rather than expired - the graceful-upgrade path preserving the pre-TTL behavior - until the next successful reload rewrites it in the stamped format. identify() and reset() clear the previous identity's flags before fetching the new identity's, so values never leak across users - onFeatureFlags listeners are notified of the clear with an empty map, then again when the new identity's flags land.

swift
let variant = cohorly.getFeatureFlag("checkout-copy", fallback: "control")
let details = cohorly.getFeatureFlagDetails("checkout-copy")
// details.source: .network | .persistence | .fallback
// details.enabled / details.payload; a fallback result reports
// enabled = truthiness of the fallback and payload = nil
// details.persistedAt / details.ttlMs when source == .persistence

A read that resolves to the fallback reports no exposure. Reads of known flags emit $feature_flag_called once per (key, value) per identity, stamped with $feature_flag_source ("network" or "persistence") plus $feature_flag_persisted_at and $feature_flag_ttl_ms for persistence reads; the same value served first from persistence and then from the network is reported once.

Auto-captured properties

Every event includes:

  • $lib = "ios"
  • $os, $os_version, $model
  • $screen_width / $screen_height (via UIKit where available - skipped on macOS/watchOS)

Events and profile updates are queued in memory and persisted to storage (UserDefaults by default) so nothing is lost across relaunch. All mutable state is confined to a private serial DispatchQueue, so the client is safe to call from any thread.

PreviousReact Native
NextAndroid