feat: anonymous analytics with PostHog (#3)

This commit is contained in:
Owen Gretzinger
2025-07-13 20:38:18 -04:00
committed by GitHub
parent 73945cba0f
commit 2e57871793
7 changed files with 51 additions and 3 deletions
+17
View File
@@ -9,6 +9,7 @@
/* Begin PBXBuildFile section */ /* Begin PBXBuildFile section */
CC5718382E2020490042BA88 /* OpenAI in Frameworks */ = {isa = PBXBuildFile; productRef = CC5718372E2020490042BA88 /* OpenAI */; }; CC5718382E2020490042BA88 /* OpenAI in Frameworks */ = {isa = PBXBuildFile; productRef = CC5718372E2020490042BA88 /* OpenAI */; };
CCBA53E72E212F1C00469D84 /* Sparkle in Frameworks */ = {isa = PBXBuildFile; productRef = CCBA53E62E212F1C00469D84 /* Sparkle */; }; CCBA53E72E212F1C00469D84 /* Sparkle in Frameworks */ = {isa = PBXBuildFile; productRef = CCBA53E62E212F1C00469D84 /* Sparkle */; };
CCC33F812E236B6F00EDE382 /* PostHog in Frameworks */ = {isa = PBXBuildFile; productRef = CCC33F802E236B6F00EDE382 /* PostHog */; };
/* End PBXBuildFile section */ /* End PBXBuildFile section */
/* Begin PBXFileReference section */ /* Begin PBXFileReference section */
@@ -28,6 +29,7 @@
isa = PBXFrameworksBuildPhase; isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
CCC33F812E236B6F00EDE382 /* PostHog in Frameworks */,
CC5718382E2020490042BA88 /* OpenAI in Frameworks */, CC5718382E2020490042BA88 /* OpenAI in Frameworks */,
CCBA53E72E212F1C00469D84 /* Sparkle in Frameworks */, CCBA53E72E212F1C00469D84 /* Sparkle in Frameworks */,
); );
@@ -82,6 +84,7 @@
packageProductDependencies = ( packageProductDependencies = (
CC5718372E2020490042BA88 /* OpenAI */, CC5718372E2020490042BA88 /* OpenAI */,
CCBA53E62E212F1C00469D84 /* Sparkle */, CCBA53E62E212F1C00469D84 /* Sparkle */,
CCC33F802E236B6F00EDE382 /* PostHog */,
); );
productName = Meetingnotes; productName = Meetingnotes;
productReference = CC5718182E201D8D0042BA88 /* Meetingnotes.app */; productReference = CC5718182E201D8D0042BA88 /* Meetingnotes.app */;
@@ -114,6 +117,7 @@
packageReferences = ( packageReferences = (
CC5718362E2020490042BA88 /* XCRemoteSwiftPackageReference "OpenAI" */, CC5718362E2020490042BA88 /* XCRemoteSwiftPackageReference "OpenAI" */,
CCBA53E52E212F1C00469D84 /* XCRemoteSwiftPackageReference "Sparkle" */, CCBA53E52E212F1C00469D84 /* XCRemoteSwiftPackageReference "Sparkle" */,
CCC33F7F2E236B6F00EDE382 /* XCRemoteSwiftPackageReference "posthog-ios" */,
); );
preferredProjectObjectVersion = 77; preferredProjectObjectVersion = 77;
productRefGroup = CC5718192E201D8D0042BA88 /* Products */; productRefGroup = CC5718192E201D8D0042BA88 /* Products */;
@@ -373,6 +377,14 @@
minimumVersion = 2.7.1; minimumVersion = 2.7.1;
}; };
}; };
CCC33F7F2E236B6F00EDE382 /* XCRemoteSwiftPackageReference "posthog-ios" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/PostHog/posthog-ios.git";
requirement = {
kind = upToNextMajorVersion;
minimumVersion = 3.28.2;
};
};
/* End XCRemoteSwiftPackageReference section */ /* End XCRemoteSwiftPackageReference section */
/* Begin XCSwiftPackageProductDependency section */ /* Begin XCSwiftPackageProductDependency section */
@@ -386,6 +398,11 @@
package = CCBA53E52E212F1C00469D84 /* XCRemoteSwiftPackageReference "Sparkle" */; package = CCBA53E52E212F1C00469D84 /* XCRemoteSwiftPackageReference "Sparkle" */;
productName = Sparkle; productName = Sparkle;
}; };
CCC33F802E236B6F00EDE382 /* PostHog */ = {
isa = XCSwiftPackageProductDependency;
package = CCC33F7F2E236B6F00EDE382 /* XCRemoteSwiftPackageReference "posthog-ios" */;
productName = PostHog;
};
/* End XCSwiftPackageProductDependency section */ /* End XCSwiftPackageProductDependency section */
}; };
rootObject = CC5718102E201D8D0042BA88 /* Project object */; rootObject = CC5718102E201D8D0042BA88 /* Project object */;
@@ -1,5 +1,5 @@
{ {
"originHash" : "e8774f1c4a54f0b9bb959e13d276fae95c54472a479606f1fd28800bfbcb6da5", "originHash" : "55d8e28deb3208ddf2aa2ec08d05566b9cae31d15d7c0ac6f9194b6eea1a9a74",
"pins" : [ "pins" : [
{ {
"identity" : "openai", "identity" : "openai",
@@ -10,6 +10,15 @@
"version" : "0.4.4" "version" : "0.4.4"
} }
}, },
{
"identity" : "posthog-ios",
"kind" : "remoteSourceControl",
"location" : "https://github.com/PostHog/posthog-ios.git",
"state" : {
"revision" : "784145ddd2f7de3a6d6fcce0e50c04f29d33b338",
"version" : "3.28.2"
}
},
{ {
"identity" : "sparkle", "identity" : "sparkle",
"kind" : "remoteSourceControl", "kind" : "remoteSourceControl",
+2 -1
View File
@@ -20,10 +20,11 @@ Implemented:
- Auto updates - Auto updates
- Text formatting - Text formatting
- Different note templates - Different note templates
- Integrate with Posthog for anonymous analytics (installs, opens, meetings created)
Todo: Todo:
- Integrate with Posthog for anonymous analytics - Onboarding screen to enable settings and set API key
Later: Later:
+17
View File
@@ -7,6 +7,7 @@
import SwiftUI import SwiftUI
import Sparkle import Sparkle
import PostHog
@main @main
struct MeetingnotesApp: App { struct MeetingnotesApp: App {
@@ -14,6 +15,22 @@ struct MeetingnotesApp: App {
init() { init() {
updaterController = SPUStandardUpdaterController(updaterDelegate: nil, userDriverDelegate: nil) updaterController = SPUStandardUpdaterController(updaterDelegate: nil, userDriverDelegate: nil)
// Setup PostHog analytics for anonymous tracking
let posthogAPIKey = "phc_Wt8sWUzUF7YPF50aQ0B1qbfA5SJWWR341zmXCaIaIRJ"
let posthogHost = "https://us.i.posthog.com"
let config = PostHogConfig(apiKey: posthogAPIKey, host: posthogHost)
// Only capture anonymous events
config.personProfiles = .never
// Enable lifecycle and screen view autocapture
config.captureApplicationLifecycleEvents = true
config.captureScreenViews = true
PostHogSDK.shared.setup(config)
// Register environment as a super property
#if DEBUG
PostHogSDK.shared.register(["environment": "dev"] )
#else
PostHogSDK.shared.register(["environment": "prod"] )
#endif
} }
var body: some Scene { var body: some Scene {
@@ -1,6 +1,7 @@
import Foundation import Foundation
import SwiftUI import SwiftUI
import Combine import Combine
import PostHog
@MainActor @MainActor
class MeetingListViewModel: ObservableObject { class MeetingListViewModel: ObservableObject {
@@ -69,6 +70,8 @@ class MeetingListViewModel: ObservableObject {
let newMeeting = Meeting() let newMeeting = Meeting()
meetings.insert(newMeeting, at: 0) meetings.insert(newMeeting, at: 0)
_ = LocalStorageManager.shared.saveMeeting(newMeeting) _ = LocalStorageManager.shared.saveMeeting(newMeeting)
// Track meeting creation event
PostHogSDK.shared.capture("meeting_created")
return newMeeting return newMeeting
} }
} }
@@ -1,6 +1,7 @@
import Foundation import Foundation
import SwiftUI import SwiftUI
import Combine import Combine
import PostHog
// Add notification name for meeting saved events // Add notification name for meeting saved events
extension Notification.Name { extension Notification.Name {
+1 -1
View File
@@ -80,7 +80,7 @@ struct OnboardingView: View {
.font(.title2) .font(.title2)
.fontWeight(.semibold) .fontWeight(.semibold)
Text("Please review and accept the terms of service and privacy policy.") Text("Of note, I am tracking a few basic anonymous metrics (installs, opens, meetings created) using PostHog, because I'm trying to gauge interest in the app and whether it's worth it to pay for an Apple Developer License & domain name. Everything is completely anonymous (feel free to check the source code). If you have any concerns, please reach out.")
.font(.body) .font(.body)
.foregroundColor(.secondary) .foregroundColor(.secondary)
} }