From 3dcba927922e0eba9f5f7fe44395b60a6dd4eef3 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Sun, 22 Feb 2026 16:45:43 +0000 Subject: [PATCH] fix(ios): configure analytics for proper active users (DAU) counting MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add $lib, $platform, $device_type to all events so PostHog can segment iOS users - Add $anon_distinct_id to identify call for proper merge of anonymous → identified users - Add $platform and $lib to person properties on identify for dashboard filtering - Fallback to default PostHog key when build variable is not substituted (xcconfig) - Guard against unsubstituted $(VAR) values in analytics payload sends Co-authored-by: Luiz Henrique <7henrique18@gmail.com> --- .../Plotwist/Services/AnalyticsService.swift | 25 ++++++++++++++----- .../Plotwist/Plotwist/Utils/Environment.swift | 2 +- 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/apps/ios/Plotwist/Plotwist/Services/AnalyticsService.swift b/apps/ios/Plotwist/Plotwist/Services/AnalyticsService.swift index 6076c373..08ea4c95 100644 --- a/apps/ios/Plotwist/Plotwist/Services/AnalyticsService.swift +++ b/apps/ios/Plotwist/Plotwist/Services/AnalyticsService.swift @@ -172,11 +172,12 @@ class AnalyticsService { } func identify(userId: String, properties: [String: Any] = [:]) { + let previousId = UserDefaults.standard.string(forKey: "analyticsDeviceId") UserDefaults.standard.set(userId, forKey: "analyticsUserId") #if DEBUG print("📊 Analytics: Identified user \(userId)") #endif - sendIdentify(userId: userId, properties: properties) + sendIdentify(userId: userId, previousAnonymousId: previousId, properties: properties) } func reset() { @@ -194,26 +195,38 @@ class AnalyticsService { // MARK: - Private private func sendEvent(name: String, properties: [String: Any]) { - guard !apiKey.isEmpty else { return } + guard !apiKey.isEmpty, !apiKey.contains("$(") else { return } + var allProperties = properties + allProperties["$lib"] = "ios" + allProperties["$lib_version"] = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String ?? "1.0" + allProperties["$platform"] = "iOS" + allProperties["$device_type"] = "Mobile" Task { await sendToPostHog(payload: [ "api_key": apiKey, "event": name, "distinct_id": distinctId, - "properties": properties, + "properties": allProperties, "timestamp": ISO8601DateFormatter().string(from: Date()), ]) } } - private func sendIdentify(userId: String, properties: [String: Any]) { - guard !apiKey.isEmpty else { return } + private func sendIdentify(userId: String, previousAnonymousId: String?, properties: [String: Any]) { + guard !apiKey.isEmpty, !apiKey.contains("$(") else { return } + var personProperties = properties + personProperties["$platform"] = "iOS" + personProperties["$lib"] = "ios" + var identifyProperties: [String: Any] = ["$set": personProperties] + if let previousId = previousAnonymousId, previousId != userId { + identifyProperties["$anon_distinct_id"] = previousId + } Task { await sendToPostHog(payload: [ "api_key": apiKey, "event": "$identify", "distinct_id": userId, - "properties": ["$set": properties], + "properties": identifyProperties, "timestamp": ISO8601DateFormatter().string(from: Date()), ]) } diff --git a/apps/ios/Plotwist/Plotwist/Utils/Environment.swift b/apps/ios/Plotwist/Plotwist/Utils/Environment.swift index e61b0207..0fede88e 100644 --- a/apps/ios/Plotwist/Plotwist/Utils/Environment.swift +++ b/apps/ios/Plotwist/Plotwist/Utils/Environment.swift @@ -7,7 +7,7 @@ import Foundation enum Env { static func value(for key: String, fallback: String? = nil) -> String { - if let value = Bundle.main.infoDictionary?[key] as? String, !value.isEmpty { + if let value = Bundle.main.infoDictionary?[key] as? String, !value.isEmpty, !value.contains("$(") { return value.trimmingCharacters(in: .whitespacesAndNewlines) } print("⚠️ [Env] Missing key: '\(key)' in Info.plist")