From a08d0d33c05f834e2f4d34ad5f793b0ed918dcaf Mon Sep 17 00:00:00 2001 From: Trey t Date: Tue, 10 Feb 2026 13:57:30 -0600 Subject: [PATCH] Add PostHog analytics to replace removed Firebase Wire PostHog iOS SDK into existing EventLogger pattern so all 60+ call sites flow to self-hosted PostHog instance with zero changes. Sets subscription person properties for segmentation on foreground. Co-Authored-By: Claude Opus 4.6 --- Feels.xcodeproj/project.pbxproj | 15 ++++++++ .../xcshareddata/swiftpm/Package.resolved | 11 +++++- Shared/EventLogger.swift | 9 +++-- Shared/FeelsApp.swift | 38 +++++++++++++++++++ 4 files changed, 69 insertions(+), 4 deletions(-) diff --git a/Feels.xcodeproj/project.pbxproj b/Feels.xcodeproj/project.pbxproj index 58ae3a4..4c382f2 100644 --- a/Feels.xcodeproj/project.pbxproj +++ b/Feels.xcodeproj/project.pbxproj @@ -291,6 +291,7 @@ name = "Feels (iOS)"; packageProductDependencies = ( 1C9566432EF8F5F70032E68F /* Algorithms */, + 1CA00002300000000000002A /* PostHog */, ); productName = "Feels (iOS)"; productReference = 1CD90AF5278C7DE0001C4FEA /* Feels.app */; @@ -442,6 +443,7 @@ mainGroup = 1CD90AE5278C7DDF001C4FEA; packageReferences = ( 1C9566402EF8F4D30032E68F /* XCRemoteSwiftPackageReference "swift-algorithms" */, + 1CA00001300000000000001A /* XCRemoteSwiftPackageReference "posthog-ios" */, ); productRefGroup = 1CD90AF6278C7DE0001C4FEA /* Products */; projectDirPath = ""; @@ -1126,6 +1128,14 @@ version = 0.2.1; }; }; + 1CA00001300000000000001A /* XCRemoteSwiftPackageReference "posthog-ios" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/PostHog/posthog-ios"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 3.0.0; + }; + }; /* End XCRemoteSwiftPackageReference section */ /* Begin XCSwiftPackageProductDependency section */ @@ -1134,6 +1144,11 @@ package = 1C9566402EF8F4D30032E68F /* XCRemoteSwiftPackageReference "swift-algorithms" */; productName = Algorithms; }; + 1CA00002300000000000002A /* PostHog */ = { + isa = XCSwiftPackageProductDependency; + package = 1CA00001300000000000001A /* XCRemoteSwiftPackageReference "posthog-ios" */; + productName = PostHog; + }; /* End XCSwiftPackageProductDependency section */ }; rootObject = 1CD90AE6278C7DDF001C4FEA /* Project object */; diff --git a/Feels.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Feels.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index c5e3a4b..dfbcc7e 100644 --- a/Feels.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/Feels.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -1,6 +1,15 @@ { - "originHash" : "86635982bfc3fdf16c7186cd33e77b4dc10a24ff9127aaee5f4f0a3676ae2966", + "originHash" : "c78c8a80b7804fd247bd921ed90ce6861b540454e98acbc02c5827d66a4d2288", "pins" : [ + { + "identity" : "posthog-ios", + "kind" : "remoteSourceControl", + "location" : "https://github.com/PostHog/posthog-ios", + "state" : { + "revision" : "5afb749442ecf7798a725ccd30342d94abb5e57f", + "version" : "3.41.0" + } + }, { "identity" : "swift-algorithms", "kind" : "remoteSourceControl", diff --git a/Shared/EventLogger.swift b/Shared/EventLogger.swift index 17586e0..6ba7748 100644 --- a/Shared/EventLogger.swift +++ b/Shared/EventLogger.swift @@ -6,14 +6,17 @@ // import Foundation -// import Firebase // Firebase removed +#if canImport(PostHog) +import PostHog +#endif class EventLogger { static func log(event: String, withData data: [String: Any]? = nil) { - // Firebase Analytics disabled - // Analytics.logEvent(event, parameters: data) #if DEBUG print("[EventLogger] \(event)", data ?? "") #endif + #if canImport(PostHog) + PostHogSDK.shared.capture(event, properties: data) + #endif } } diff --git a/Shared/FeelsApp.swift b/Shared/FeelsApp.swift index 8f82203..5ccbecc 100644 --- a/Shared/FeelsApp.swift +++ b/Shared/FeelsApp.swift @@ -9,6 +9,7 @@ import SwiftUI import SwiftData import BackgroundTasks import WidgetKit +import PostHog @main struct FeelsApp: App { @@ -23,6 +24,13 @@ struct FeelsApp: App { @State private var showSubscriptionFromWidget = false init() { + // Initialize PostHog analytics + let posthogConfig = PostHogConfig(apiKey: "phc_3GsB3oqNft8Ykg2bJfE9MaJktzLAwr2EPMXQgwEFzAs", host: "https://analytics.88oakapps.com") + #if DEBUG + posthogConfig.debug = true + #endif + PostHogSDK.shared.setup(posthogConfig) + BGTaskScheduler.shared.cancelAllTaskRequests() BGTaskScheduler.shared.register(forTaskWithIdentifier: BGTask.updateDBMissingID, using: nil) { (task) in BGTask.runFillInMissingDatesTask(task: task as! BGProcessingTask) @@ -115,6 +123,36 @@ struct FeelsApp: App { // Check subscription status (network call) - throttled Task.detached(priority: .background) { await iapManager.checkSubscriptionStatus() + + // Set PostHog person properties for subscription segmentation + let state = await iapManager.state + let subscriptionStatus: String + let subscriptionType: String + + switch state { + case .subscribed: + subscriptionStatus = "subscribed" + subscriptionType = await iapManager.currentProduct?.id.contains("yearly") == true ? "yearly" : "monthly" + case .inTrial: + subscriptionStatus = "trial" + subscriptionType = "none" + case .trialExpired: + subscriptionStatus = "trial_expired" + subscriptionType = "none" + case .expired: + subscriptionStatus = "expired" + subscriptionType = "none" + case .unknown: + subscriptionStatus = "unknown" + subscriptionType = "none" + } + + PostHogSDK.shared.capture("$set", properties: [ + "$set": [ + "subscription_status": subscriptionStatus, + "subscription_type": subscriptionType + ] + ]) } } }