SDK documentation
One Swift package, no dependencies, for iOS, watchOS, macOS, tvOS, and visionOS. The whole integration is one line; everything else is optional.
1 · Install
Xcode → File → Add Package Dependencies… → paste:
https://github.com/LudyemAS/LudyemAnalytics
2 · Configure
Create your app in the dashboard, copy its write key from the Setup
tab, and call configure once, as early as possible:
import LudyemAnalytics
@main
struct MyApp: App {
init() {
Analytics.configure(apiKey: "lud_live_…")
}
var body: some Scene {
WindowGroup {
RootView()
.trackAppLifecycle() // sessions + the live "active now" heartbeat
}
}
}
Safe by default: Debug and Simulator builds never send anything. TestFlight events are tagged separately, so your production numbers stay clean. The write key only grants write access to your app's own stream — it can never read anything, which is why it's fine inside a shipped binary.
3 · Track anything
Analytics.track("paywall.viewed")
Analytics.track("workout.completed", metadata: ["type": "run"])
New signals appear in the dashboard's Events tab on their own — no schema, no setup.
Any signal can be charted from the Overview metric picker, used as a funnel step, or wired
to a push alert. The SDK also sends install exactly once per fresh install.
Never put personal data in signals or metadata.
API surface
| Call | What it does |
|---|---|
| Analytics.configure(apiKey:) | The whole hosted setup. Call once at launch. |
| Analytics.configure(_:) | Full-control variant taking an AnalyticsConfiguration (below). |
| Analytics.track(_:metadata:) | Record an event. Safe before configure (no-op). Metadata is [String: String]. |
| .trackAppLifecycle() | SwiftUI modifier for your root view: emits session.start whenever the app comes to the front after more than sessionTimeout away (a launch, or a return from the background), runs the foreground heartbeat that keeps the session alive, flushes on background. |
| .trackScreen(_:) | SwiftUI modifier: records screen.<name> each time the view appears — the quickest way to feed the Funnel panel. |
| Analytics.setActive(_:) | Manual foreground/background signal if you don't use the modifier (UIKit apps). |
| Analytics.flush() | Force-send queued events now. |
AnalyticsConfiguration options
| Option | Default |
|---|---|
| apiKey | required — your app's write key |
| appID | your bundle id |
| flushInterval | 10s — how long a partial batch waits |
| maxBatchSize | 20 — flush immediately at this many queued events |
| heartbeatInterval | 60s — powers "active right now"; heartbeats are never billable |
| sessionTimeout | 300s — away longer than this and coming back is a new session (session.start); the dashboard splits sessions on the same 5-minute gap |
| collectsCountry | true — the device region setting (a locale, never GPS or IP); false = empty map, same privacy labels |
| enabledEnvironments | [.appStore, .testFlight] — Simulator and Debug never send |
| isEnabled | true — master switch, e.g. behind your own user toggle |
Offline & delivery guarantees
Events are written to disk as they are tracked, batched, sent in slices of 100 and retried automatically, capped at 500 events oldest-out. Every event carries a client-generated id, so a batch that is re-sent after a lost response is stored once — retries never double-count. When the app leaves the foreground the SDK flushes under a task assertion, so the send completes before iOS suspends the process.
App Store privacy labels
Declare under "Data Not Linked to You": Identifiers → User ID (the
random install id) and Usage Data → Product Interaction, purpose
Analytics, tracking No. No ATT prompt is required. The dashboard's Setup
tab generates these answers next to your key, and the SDK ships its own
PrivacyInfo.xcprivacy. Details: privacy policy.
Webhook alerts (signed JSON)
Alerts can POST signed JSON to your own server. Verify the signature: compute
HMAC-SHA256 of the raw request body with the webhook's secret and compare it to the
X-Ludyem-Signature header (sha256=<hex>):
# Node.js
const expected = "sha256=" + crypto.createHmac("sha256", secret)
.update(rawBody).digest("hex");
const ok = crypto.timingSafeEqual(Buffer.from(expected),
Buffer.from(req.headers["x-ludyem-signature"]));
Self-hosting
The SDK also runs against your own Supabase project — events go straight from devices to your database, and nothing touches Ludyem's servers:
Analytics.configure(.init(
supabaseURL: URL(string: "https://YOUR-REF.supabase.co")!,
publishableKey: "sb_publishable_…",
appID: "com.you.app"
))
The schema and setup live in the repo:
github.com/LudyemAS/LudyemAnalytics
(supabase/schema.sql).