Analytics

Every screen fires through one AnalyticsTracker protocol via @Environment(\.analytics) — available to any view, not just DeliciousKit's own onboarding/paywall/settings views. DeliciousKit ships ConsoleAnalytics (prints to the console), NoopAnalytics (drops everything), and CompositeAnalytics (fans out to several trackers at once — e.g. PostHog + console in debug).

Event vocabulary

AnalyticsEvent is the base vocabulary every app inherits for free — onboarding funnel, paywall, purchases, sign-in/account lifecycle, permission prompts, and settings actions. Use .custom(name:params:) for app-specific events: keep names short, snake_case, and params flat with low cardinality (no raw IDs or free text) so events stay aggregable.

PostHog

import DeliciousKitPostHog:

.environment(\.analytics, PostHogAnalyticsTracker(apiKey: "phc_xxx"))

Every AnalyticsEvent case maps to a flat snake_case event name (e.g. .onboardingCompleted"onboarding_completed", .purchaseFailed(reason:)"purchase_failed" with a reason property). .custom(name:params:) passes through as-is.

Mixpanel

import DeliciousKitMixpanel — same event-name mapping as PostHog, so switching backends (or running both via CompositeAnalytics) doesn't change what shows up in either dashboard:

.environment(\.analytics, MixpanelAnalyticsTracker(token: "your-mixpanel-token"))

Firebase Analytics & Crashlytics

import DeliciousKitFirebaseAnalytics ships two separate trackers — combine them with CompositeAnalytics if you want both:

.environment(\.analytics, CompositeAnalytics([
    FirebaseAnalyticsTracker(),
    FirebaseCrashlyticsTracker(),
]))

FirebaseCrashlyticsTracker doesn't send events to a dashboard — it logs each AnalyticsEvent as a Crashlytics breadcrumb, so your event trail is visible on the timeline of any crash report.

Running more than one backend

.environment(\.analytics, CompositeAnalytics([
    PostHogAnalyticsTracker(apiKey: "phc_xxx"),
    ConsoleAnalytics(),   // handy while developing
]))