Unified Analytics Strategy Across Platforms

Develop a cohesive analytics strategy that spans iOS, Android, web, and backend platforms, ensuring consistent measurement and cross-platform user journeys.

business7 min readBy Klivvr Engineering
Share:

Most companies do not have an analytics problem -- they have a consistency problem. The iOS team tracks "purchase_complete" while Android tracks "purchaseCompleted" and the web team tracks "checkout_success." Each platform has its own event taxonomy, property schemas, and user identification methods. When product managers try to answer cross-platform questions, they spend more time reconciling data than analyzing it.

A unified analytics strategy eliminates this fragmentation by establishing shared standards across every platform. This article outlines how to build that strategy, with KlivvrAnalyticsKit as the iOS implementation layer.

The Cost of Fragmented Analytics

Fragmented analytics costs organizations in tangible ways. Data engineers spend 30-40% of their time cleaning and reconciling inconsistent event data. Product managers make decisions based on platform-specific silos, missing the full user journey. Marketing teams cannot attribute conversions that span web and mobile. Engineering teams duplicate tracking work because there is no shared specification.

// The problem: inconsistent tracking across platforms
// iOS tracks:
KlivvrAnalytics.shared.track("purchase_complete", properties: [
    "product_id": "SKU123",
    "amount": 29.99,
    "currency": "USD"
])
 
// Android might track:
// analytics.track("purchaseCompleted", mapOf("productId" to "SKU123", "price" to 29.99))
 
// Web might track:
// analytics.track('checkout_success', { sku: 'SKU123', total: '$29.99' })
 
// Same event, three different names, three different property schemas

The solution is a shared event specification that all platforms implement consistently.

Building the Shared Event Specification

A unified analytics strategy starts with a shared event specification document. This is the single source of truth for what gets tracked, how it is named, and what properties it carries.

// Shared event specification implemented in Swift
// This mirrors the cross-platform specification exactly
 
enum UnifiedEvent {
    // Commerce events
    case productViewed(productId: String, productName: String, category: String, price: Decimal)
    case addedToCart(productId: String, quantity: Int, price: Decimal)
    case purchaseCompleted(orderId: String, products: [ProductInfo], totalAmount: Decimal, currency: String)
 
    // User lifecycle events
    case signUpStarted(method: SignUpMethod)
    case signUpCompleted(method: SignUpMethod, userId: String)
    case loginCompleted(method: LoginMethod)
 
    // Engagement events
    case screenViewed(screenName: String, screenClass: String)
    case featureUsed(featureName: String, action: String)
    case searchPerformed(query: String, resultCount: Int)
 
    var eventName: String {
        switch self {
        case .productViewed: return "product_viewed"
        case .addedToCart: return "added_to_cart"
        case .purchaseCompleted: return "purchase_completed"
        case .signUpStarted: return "sign_up_started"
        case .signUpCompleted: return "sign_up_completed"
        case .loginCompleted: return "login_completed"
        case .screenViewed: return "screen_viewed"
        case .featureUsed: return "feature_used"
        case .searchPerformed: return "search_performed"
        }
    }
 
    var properties: [String: Any] {
        switch self {
        case .productViewed(let productId, let productName, let category, let price):
            return [
                "product_id": productId,
                "product_name": productName,
                "category": category,
                "price": NSDecimalNumber(decimal: price).doubleValue
            ]
        case .purchaseCompleted(let orderId, let products, let totalAmount, let currency):
            return [
                "order_id": orderId,
                "products": products.map { $0.toDictionary() },
                "total_amount": NSDecimalNumber(decimal: totalAmount).doubleValue,
                "currency": currency
            ]
        default:
            return [:]  // Other cases handled similarly
        }
    }
}
 
enum SignUpMethod: String { case email, apple, google, facebook }
enum LoginMethod: String { case email, biometric, apple, google }
 
struct ProductInfo {
    let productId: String
    let productName: String
    let quantity: Int
    let price: Decimal
 
    func toDictionary() -> [String: Any] {
        [
            "product_id": productId,
            "product_name": productName,
            "quantity": quantity,
            "price": NSDecimalNumber(decimal: price).doubleValue
        ]
    }
}

The enum-based approach in Swift ensures compile-time correctness. The same event specification exists as TypeScript interfaces for web and Kotlin sealed classes for Android, all generated from the same source schema.

Cross-Platform User Identity

Users do not live on a single platform. They might browse on the web, add items to their cart on their phone, and complete the purchase on their tablet. Unifying the user identity across these touchpoints is essential for understanding the full journey.

// Cross-platform identity resolution
final class UnifiedIdentityManager {
    private let analytics: KlivvrAnalytics
    private var anonymousId: String
    private var userId: String?
 
    init(analytics: KlivvrAnalytics) {
        self.analytics = analytics
        self.anonymousId = Self.getOrCreateAnonymousId()
    }
 
    // Called when a user logs in -- links anonymous activity to known identity
    func identify(userId: String, traits: [String: Any] = [:]) {
        let previousAnonymousId = anonymousId
        self.userId = userId
 
        // Send alias event to link anonymous and known identities
        analytics.track("identity_alias", properties: [
            "user_id": userId,
            "anonymous_id": previousAnonymousId,
            "platform": "ios"
        ])
 
        // Set user identity on all future events
        analytics.identify(userId: userId, traits: traits.merging([
            "platform": "ios",
            "identified_at": ISO8601DateFormatter().string(from: Date())
        ]) { _, new in new })
    }
 
    // Called on logout
    func reset() {
        userId = nil
        anonymousId = UUID().uuidString
        UserDefaults.standard.set(anonymousId, forKey: "klivvr_anonymous_id")
        analytics.reset()
    }
 
    private static func getOrCreateAnonymousId() -> String {
        if let existing = UserDefaults.standard.string(forKey: "klivvr_anonymous_id") {
            return existing
        }
        let newId = UUID().uuidString
        UserDefaults.standard.set(newId, forKey: "klivvr_anonymous_id")
        return newId
    }
 
    // Enrich every event with identity context
    func enrichEvent(_ event: inout AnalyticsEvent) {
        event.properties["anonymous_id"] = anonymousId
        event.properties["platform"] = "ios"
        if let userId {
            event.properties["user_id"] = userId
        }
    }
}

The key concept is the alias event. When a previously anonymous user logs in, the alias event tells the analytics backend to merge the anonymous browsing history with the authenticated user profile. This enables cross-platform journey analysis.

Governance and Tracking Plan Management

A unified analytics strategy requires governance. Without it, the shared specification degrades within months as teams add ad-hoc events without coordination.

// Tracking plan validation ensures compliance
struct TrackingPlan {
    let version: String
    let events: [EventDefinition]
 
    struct EventDefinition {
        let name: String
        let description: String
        let requiredProperties: [PropertyDefinition]
        let optionalProperties: [PropertyDefinition]
        let platforms: Set<Platform>
    }
 
    struct PropertyDefinition {
        let name: String
        let type: PropertyType
        let description: String
        let allowedValues: [String]?
    }
 
    enum Platform: String {
        case ios, android, web, backend
    }
 
    enum PropertyType: String {
        case string, integer, decimal, boolean, array, object
    }
 
    // Validate an event against the tracking plan
    func validate(_ event: AnalyticsEvent) -> [ValidationIssue] {
        var issues: [ValidationIssue] = []
 
        guard let definition = events.first(where: { $0.name == event.name }) else {
            issues.append(.undefinedEvent(event.name))
            return issues
        }
 
        // Check required properties
        for required in definition.requiredProperties {
            if event.properties[required.name] == nil {
                issues.append(.missingRequiredProperty(
                    event: event.name,
                    property: required.name
                ))
            }
        }
 
        return issues
    }
 
    enum ValidationIssue {
        case undefinedEvent(String)
        case missingRequiredProperty(event: String, property: String)
        case invalidPropertyType(event: String, property: String, expected: PropertyType)
    }
}

The tracking plan should be version-controlled alongside your code. Changes to the tracking plan go through the same review process as code changes, with sign-off from engineering, product, and data teams.

Measuring Success of Unified Analytics

How do you know your unified analytics strategy is working? Track meta-metrics about your analytics data itself.

// Analytics quality dashboard metrics
struct AnalyticsQualityMetrics {
    // Schema compliance rate: percentage of events that match the tracking plan
    let schemaComplianceRate: Double
 
    // Cross-platform coverage: percentage of defined events implemented on all platforms
    let crossPlatformCoverage: Double
 
    // Identity resolution rate: percentage of events with a resolved user identity
    let identityResolutionRate: Double
 
    // Data freshness: median time from event creation to warehouse availability
    let dataFreshnessP50: TimeInterval
 
    // Event delivery rate: percentage of created events that reach the warehouse
    let eventDeliveryRate: Double
 
    var isHealthy: Bool {
        schemaComplianceRate > 0.95 &&
        crossPlatformCoverage > 0.90 &&
        identityResolutionRate > 0.80 &&
        eventDeliveryRate > 0.99
    }
}

Practical Tips

Start your unified analytics strategy by auditing what each platform currently tracks. Map existing events to a shared taxonomy and identify gaps. Use code generation to produce platform-specific event definitions from a shared schema, preventing drift. Assign an analytics owner on each platform team who participates in cross-platform tracking plan reviews. Set up automated tests that verify critical events fire correctly on each platform. Build a data quality dashboard that surfaces compliance issues before they compound into data debt.

Conclusion

A unified analytics strategy is the foundation for data-driven product development. By establishing shared event specifications, consistent naming conventions, cross-platform identity resolution, and governance processes, you transform fragmented platform silos into a coherent picture of user behavior. KlivvrAnalyticsKit provides the iOS implementation layer that enforces these standards through type-safe event definitions and validation, ensuring that the iOS contribution to your analytics data is clean, consistent, and trustworthy.

Related Articles

business

Ensuring Data Quality in Mobile Analytics

Establish data quality practices for mobile analytics, including validation, monitoring, testing, and governance to maintain trustworthy analytics data.

7 min read