A crash report answers "how many users dropped off" in your mobile app; product analytics answers "why are users dropping off, where do they get stuck, which cohort comes back." This article sets up the PostHog and Amplitude iOS SDKs using the current syntax from their official docs, sends the same event schema to both tools at once, and stays compliant with ATT/GDPR along the way.
💡 Pro Tip: Design your event taxonomy before you touch the SDK setup — writing code first and then trying to "clean up" event names afterward leaves you with thousands of inconsistent event names in production.
Table of Contents
- What product analytics measures, and how it differs from crash/performance analytics
- Event taxonomy: naming convention, properties, user/session identity
- Naming convention
- iOS SDK setup (PostHog iOS + Amplitude iOS)
- PostHog iOS setup
- Amplitude iOS setup
- How the same event schema is sent to both products
- Privacy: ATT, App Privacy labels, GDPR
- Which one when: hosting, pricing model, team size
- Verification: debug/live events view, test device filtering
- Common mistakes
- FAQ
- How do you design an event taxonomy for a mobile app?
- How do you set up the PostHog and Amplitude iOS SDKs?
- How do you set up product analytics to comply with ATT and KVKK/GDPR?
- Should I choose PostHog or Amplitude?
- Should my events be sent via autocapture or manually?
- Update (September 2026)
- Conclusion
- Sources
What product analytics measures, and how it differs from crash/performance analytics
Product analytics models user behavior through the events an app sends. In PostHog's own words, it answers "what people are actually doing in your product," building trend, funnel, retention, path, stickiness, and lifecycle insights on top of that. This is a different layer from what crash-reporting tools (Crashlytics, Sentry) focus on — "did the app crash, and with which stack trace" — crash analytics captures the error, product analytics captures the behavior.
These two layers complement each other, not replace one another: I covered crash analytics setup on iOS earlier in iOS Crash Reporting and Analytics, and for performance-side instrumentation see the iOS Performance Monitoring (in Turkish) guide. This article focuses only on the product/behavior layer.
Another distinction PostHog's docs emphasize is integration depth: "every number you look at is one click away from the session replay behind it, or the feature flag or experiment that triggered it" — the tool isn't just a standalone dashboard; it's a platform sharing the same event/user/property set with feature flags, A/B tests, and session replay. Similarly at Amplitude, events and user properties underpin the segmentation and cohort analyses built later. That's why "send the event first, fix the taxonomy later" gets expensive — taxonomy design has to come before setup.
Event taxonomy: naming convention, properties, user/session identity
Per Amplitude's official data-planning guide, an event taxonomy is built in three steps: define your business objectives, break them into key metrics, then optimize the events and properties feeding those metrics. Order matters — answering "which event should I send" before "which metric am I measuring" produces a useless event list.
Naming convention
Amplitude's guide recommends three consistency rules: consistent casing, consistent syntax (the recommended pattern is [Noun] + [Past-Tense Verb], e.g. "Purchase Completed"), and a consistent actor (always write event names from the user's perspective — like "Button Clicked" — describing what the user did, not what the system did).
- Event property: details specific to a single event instance, carried at that moment. In Amplitude's example, for the
Purchase Completedevent, the product purchased, the amount, and the payment method are each event properties. - User property: attributes that define the user and are automatically attached to all future events that user sends (like plan type or signup channel).
- User identity: PostHog's docs treat this as mandatory — after login, call
PostHogSDK.shared.identify("stable-user-id")with a stable identifier from your auth system; NEVER use a shared literal ID like "anonymous". - Session close: per PostHog's docs, call
PostHogSDK.shared.reset()on logout — otherwise the next user can inherit the previous person's identity on that device. - Version tag: the PostHog iOS SDK already auto-attaches
$app_versionand$app_buildto every event and person property (source: PostHog iOS SDK context implementation), so you rarely need a manual version property — just add fields the SDK doesn't send automatically, like platform.
When you collect the version and platform tag in a single helper, every developer on your team produces the same schema:
1func extraProductProperties() -> [String: Any] {2 return ["platform": "ios"]3}Add this function as a property to every manual event call and you can later answer "how many users used this flow on which version" with a segment breakdown inside a funnel — without it, you'd have to ship a new version and wait to answer that question again.
iOS SDK setup (PostHog iOS + Amplitude iOS)
PostHog iOS setup
According to PostHog's official documentation, the PostHog iOS SDK can be added via CocoaPods or as a Swift Package Manager dependency; configuration is done through the PostHogConfig object.
1import PostHog2 3let config = PostHogConfig(projectToken: "phc_your_project_token", host: "https://us.i.posthog.com")4// Note: older versions used the `apiKey:` label, which is now deprecated — use `projectToken:` in new code5 6PostHogSDK.shared.setup(config)7 8// identify the user after login9PostHogSDK.shared.identify("stable-user-id-from-your-auth-system")10 11// reset the identity on logout12PostHogSDK.shared.reset()One behavior to watch for: according to PostHog's docs, events are queued in the device's local storage while it's offline. This queue has an upper size limit controlled by maxQueueSize; when the queue fills up, the oldest event is dropped, and the queue is only flushed once the device is back online. So an event you test in airplane mode won't show up on the dashboard until the connection comes back — that's not a bug, it's by design.
Amplitude iOS setup
According to Amplitude's official iOS Swift SDK documentation, setup starts by adding the https://github.com/amplitude/Amplitude-Swift package via Swift Package Manager. The init call is made through the Configuration object, and the autocapture parameter determines which automatic events are collected:
1import AmplitudeSwift2 3let amplitude = Amplitude(4 configuration: Configuration(5 apiKey: AMPLITUDE_API_KEY,6 autocapture: [.sessions, .appLifecycles, .screenViews, .elementInteractions, .networkTracking, .frustrationInteractions]7 )8)According to Amplitude's documentation, starting from v1.8.0 the SDK can automatically capture Sessions, App lifecycles, Screen views, Element interactions, Frustration interactions (rage/dead click), and Network requests without manual instrumentation (frustration interactions require 1.15.0+). If you don't pass the autocapture parameter at all, the SDK keeps only .sessions enabled by default — so if you want to automatically see screen views or button taps, you need to explicitly specify this list.
Events can be sent in two ways; the official docs give a code example for both:
1let event = BaseEvent(eventType: "Button Clicked", eventProperties: ["button_name": "checkout"])2amplitude.track(event: event)3 4// or directly5amplitude.track(eventType: "Button Clicked", eventProperties: ["button_name": "checkout"])To assign a user property, the Identify() object is used:
1let identify = Identify()2identify.set(property: "plan_type", value: "pro")3amplitude.identify(identify: identify)According to Amplitude's docs, the SDK uploads events to the server every 30 seconds by default, or once 30 events accumulate — whichever happens first. If you want to see an event actually get sent instantly on a test device, you can call amplitude.flush() right after track() — this is only recommended for test/debug; calling flush after every single event in production needlessly increases battery and network usage.
Amplitude also offers a "Unified SDK" that combines the Analytics, Experiment, and Session Replay SDKs into a single interface; this SDK's init signature is Amplitude(apiKey:serverZone:instanceName:analyticsConfig:experimentConfig:sessionReplayConfig:logger:). The serverZone parameter comes into play here — if you want events to go to EU servers instead of US ones, Amplitude's docs recommend setting up your project inside Amplitude EU and initializing the SDK with the API key from Amplitude EU; this field isn't unique to the Unified SDK, it's also present in the standard Amplitude Swift Configuration.
How the same event schema is sent to both products
Once you've designed your taxonomy, you can send the same event to both SDKs in parallel — this is useful during migration periods or when comparison-testing the two tools side by side (see PostHog vs Amplitude comparison):
1func trackPurchaseCompleted(productId: String, amount: Double, method: String) {2 let properties: [String: Any] = [3 "product_id": productId,4 "amount": amount,5 "payment_method": method6 ]7 8 PostHogSDK.shared.capture("Purchase Completed", properties: properties)9 10 amplitude.track(eventType: "Purchase Completed", eventProperties: properties)11}PostHog's documentation recommends the [object] [verb] (noun + verb) format for event naming — with examples like project created, user signed up, invite sent. This is nearly identical logic to Amplitude's [Noun] + [Past-Tense Verb] convention; if you're using both tools in parallel, you just need one naming convention and to send the same string to both.
PostHog's autocapture also sends some events automatically in a similar way: Application Opened, Application Backgrounded, Application Installed, Application Updated, and, on UIKit-based screens, $screen, $autocapture, $rageclick. If you're using SwiftUI, some of these events (like TextField wrapped over UITextField) can still be captured through the underlying UIKit components, but the element metadata can end up incomplete — so in SwiftUI projects you need to rely more on manual capture() calls.
Privacy: ATT, App Privacy labels, GDPR
Privacy in mobile product analytics comes from two different frameworks: Apple's platform-level App Tracking Transparency (ATT) permission, and the tool-level opt-in/opt-out APIs.
In the PostHog iOS SDK, calling PostHogSDK.shared.optOut() opts a user out device-wide; this call stops all data collection, including autocapture, manual capture, and session replay — you can check the status with PostHogSDK.shared.isOptOut(). If you want to start users opted out by default, you can set the optOut field on PostHogConfig to true, then turn it on with PostHogSDK.shared.optIn() once consent is obtained. One warning: don't hide the SDK snippet behind the consent banner — otherwise you can't even count users who reject the banner; using the opt-out APIs is the correct way to do this.
Amplitude handles opt-out through the optOut parameter on the Configuration object (default false):
1let amplitude = Amplitude(2 configuration: Configuration(apiKey: AMPLITUDE_API_KEY, optOut: true)3)These two APIs do NOT replace Apple's ATT framework — they're separate layers. ATT is a distinct system permission for accessing out-of-app tracking data (like the IDFA); it's triggered with ATTrackingManager.requestTrackingAuthorization, and even if the user rejects it, you can keep sending events to PostHog/Amplitude as first-party analytics — rejecting ATT blocks third-party ad tracking, not first-party product analytics automatically. I covered ATT setup and App Privacy labels end to end earlier in iOS Privacy Compliance and ATT (in Turkish) and iOS Privacy Manifests and App Tracking 2026 (in Turkish), so I won't repeat that here.
On the GDPR side, both tools offer a "data region" option — to keep events on EU servers, select the EU host (https://eu.i.posthog.com) in PostHog, or serverZone: .EU in Amplitude. This overlaps practically with KVKK's sensitivity around cross-border data transfer, but neither tool carries an official "KVKK-compliant" certification — legal compliance remains your project's own assessment, and picking a tool alone doesn't guarantee it.
Which one when: hosting, pricing model, team size
Both tools are mature, but they appeal to different team profiles.
Pricing model (official pricing page, September 16, 2026): PostHog's "Free" plan needs no credit card, offering 1 project and 1 year of data retention. "Pay-as-you-go" offers unlimited usage, 6 projects, and 7 years of retention, with the first 1 million events free every month. For an early-stage app with unpredictable event volume, that's a low entry cost — a small team can start without a credit card.
Criterion | PostHog | Amplitude |
|---|---|---|
Free plan | No credit card, 1M analytics events/month, 1 project, 1 year retention | No credit card, 2 million events/month, unlimited seats |
EU data region | eu.i.posthog.com host selection | serverZone: .EU + EU region at account signup |
All-in-one | Analytics + feature flags + session replay + experiments | Analytics + Experiment + Session Replay (Unified SDK) |
Standout | Open source, self-host option | Enterprise data-planning discipline, AI analytics feature |
Team size and hosting: PostHog's open-source nature and self-host option suit engineering teams that want infrastructure under their own control. Amplitude has laid out its data-planning methodology (objective → metric → event/property) in detail in its official docs — a better fit for growing product teams institutionalizing taxonomy discipline. Since figures and plans change over time, always check the live PostHog vs Amplitude comparison page.
In practice, the decision comes down to three questions. First: whose servers do you want the data on — with self-hosting capacity, PostHog's open-source option keeps that door open (self-hosting is MIT-licensed and possible, though PostHog itself notes it isn't officially supported and recommends Cloud). Second: what else you'll run alongside analytics — wanting feature flags and session replay on one platform favors PostHog's single-SDK approach. Third: who owns data-planning discipline on your team — a large product/data team can lean on Amplitude's official playbook for a shared language; a small team can adapt that same playbook to PostHog's looser structure, just building the discipline itself.
Verification: debug/live events view, test device filtering
Don't ship to production without verifying that events are actually getting sent once setup is done.
According to Amplitude's official docs, for debugging you set logLevel: LogLevelEnum.debug in Configuration; you can watch the SDK logs in the Xcode console with the com.amplitude filter. On the dashboard side, you can find the user or device ID an event came from via the "User Lookup activity" screen and turn on "Live event updates" to see the event arrive live.
1let config = Configuration(apiKey: AMPLITUDE_API_KEY, logLevel: LogLevelEnum.debug)2let amplitude = Amplitude(configuration: config)On the PostHog side, the fastest way to verify is to send a test event right after setup and confirm it shows up in the PostHog dashboard's event stream within a few seconds. If you don't want test-device events mixing into your live metrics, PostHog's dashboard settings have an option to filter out your own user ID or test accounts. The most practical verification method is the same for both tools: send a test event nobody else has seen yet, confirm it appears on the dashboard, then ship to production.
Common mistakes
- Calling identify with a shared literal ID like "anonymous": PostHog's docs explicitly forbid this — it causes different users to merge under the same identity (identity-merge pollution). Always use the stable user ID from your auth system.
- Forgetting to call reset() on logout: the next user can "inherit" the previous person's session and properties on that device — this data pollution gets especially serious on shared devices (kiosks, test devices).
- Misunderstanding autocapture: in Amplitude, if the
autocaptureparameter isn't provided, only.sessionsis enabled; expecting screen views or taps to "come automatically" without specifying it in the configuration results in empty funnels on the dashboard. - Hiding the SDK snippet behind the consent banner: PostHog's own warning — you can't count people who reject the banner because the SDK never loaded. Always load the SDK and control it via the opt-in/opt-out APIs.
- Not separating test-device events from production metrics: dozens of test events fired during development can visibly distort funnel rates on a small user base.
- Mistaking the offline queue for "the event got lost": in PostHog, events queue locally while offline and flush once the device reconnects — before panicking over an airplane-mode test, connect to the internet.
GOLDEN TIP
The most valuable insight in this article
This tip holds the article's most important takeaway.
Easter Egg
You found a hidden gem!
There's a hidden detail in this section. Want to uncover it?
Reader Reward
Before you take a setup to production, I've put together a checklist you can walk through yourself — go through each line and you won't skip a step on taxonomy, setup, or privacy.
FAQ
How do you design an event taxonomy for a mobile app?
According to Amplitude's official data-planning guide, in three steps: first define your business objectives, then break those objectives down into the key metrics that will measure them, and finally optimize the events and properties that will feed those metrics. In naming, stick to consistent casing, a [Noun]+[Past-Tense Verb] syntax, and naming from the user's perspective.
How do you set up the PostHog and Amplitude iOS SDKs?
PostHog is initialized with PostHogConfig(projectToken:host:), then PostHogSDK.shared.setup(config) is called; to send an event you use capture("event_name", properties: [...]). Amplitude is initialized with Amplitude(configuration: Configuration(apiKey:autocapture:)), and to send an event you use track(eventType:eventProperties:) or BaseEvent + track(event:). Both SDKs are added via Swift Package Manager.
How do you set up product analytics to comply with ATT and KVKK/GDPR?
Since ATT is a separate permission specifically for third-party tracking, it doesn't automatically block first-party product analytics; you still need correct App Privacy labels (see iOS Privacy Compliance and ATT (in Turkish)). For GDPR/KVKK, keep event data on EU servers by selecting the EU host in PostHog or serverZone: .EU in Amplitude — practical, but not an official KVKK certification; set a pre-consent opt-out default via PostHogConfig.optOut = true in PostHog, or optOut: true in Amplitude.
Should I choose PostHog or Amplitude?
There's no definitive "better" — PostHog suits teams wanting infrastructure control via open source and self-hosting, while Amplitude fits growing teams prioritizing enterprise data-planning discipline. Pricing and plans change often, so check the current PostHog vs Amplitude comparison before deciding.
Should my events be sent via autocapture or manually?
The two aren't mutually exclusive. Leave general lifecycle events like app open/background to autocapture, and always send business-logic-specific events (purchase completed, payment failed, and the like) with an explicit manual capture/track call — autocapture's element metadata, especially in SwiftUI, may not be reliable enough to base a business decision on.
Update (September 2026)
What changed in September 2026: developments on the ATT and platform side, plus SDK version updates.
- Apple officially released iOS 27 on September 14, 2026; the ATT prompt flow remains in effect in this version too, and it's recommended you test your setup examples and minimum deployment target against iOS 27 (source: 9to5mac, September 9, 2026 announcement).
- Following an investigation by Germany's competition authority, Apple announced on August 17, 2026 that it voluntarily agreed to 8 changes to the ATT prompt (such as the buttons becoming "Allow/Reject," a full-page prompt, and the ability to add a GDPR information page); these changes currently apply only within the EU/Germany, and an exact effective date hasn't been finalized. See iOS Privacy Compliance and ATT (in Turkish) for details.
- posthog-ios 3.74.0 (September 11, 2026) added
sessionReplayConfig.captureTouches, which turns off recording touch coordinates in session replay; 3.76.0 (September 15, 2026) addedpersistOptOutfor SDKs wrapping consent management (source: github.com/PostHog/posthog-ios CHANGELOG.md).
Conclusion
The most critical step in setting up product analytics for a mobile app isn't the SDK integration — it's the taxonomy design. PostHog's and Amplitude's iOS SDKs can be set up with a few lines of code, but inconsistent event names and missing properties make the dashboard unusable. First settle on a noun+verb naming convention, manage user identity correctly across the login/logout cycle, embed the privacy APIs in your code rather than behind the consent banner, and only then do the setup.
For complementary instrumentation on the crash and performance side, see iOS Crash Reporting and Analytics and iOS Performance Monitoring (in Turkish); to go deeper on privacy, see iOS Privacy Compliance and ATT (in Turkish) and iOS Privacy Manifests and App Tracking 2026 (in Turkish); and when you're setting up feature flags and experimentation infrastructure, see iOS Feature Flags Strategy (in Turkish). To compare the two tools side by side in a table that's kept up to date, check the PostHog vs Amplitude comparison page.
Sources
- PostHog Product Analytics documentation — the scope of product analytics and its integration with other PostHog products.
- PostHog iOS SDK setup documentation — CocoaPods/SPM setup,
PostHogConfig, the identify/reset contract, offline queue behavior. - PostHog iOS SDK usage documentation — the
capture()function, the autocapture event list, screen-view capture. - PostHog privacy and data collection documentation — opt-out/opt-in APIs, the consent banner integration warning.
- PostHog pricing page — Free and Pay-as-you-go plan details (as of September 16, 2026).
- Amplitude pricing page — Free plan: no credit card, 2 million events/month, unlimited seats (as of September 16, 2026).
- Amplitude data planning guide — taxonomy design steps, event/user property definitions, naming convention.
- Amplitude iOS Swift SDK documentation — init, track, identify, flush, autocapture, optOut, debug log code examples.
- Amplitude Unified SDK documentation — the combined Analytics/Experiment/Session Replay interface, the serverZone parameter.
- 9to5mac — Apple confirms iOS 27 release date — the September 14, 2026 release date.
- 9to5mac — ATT prompt changes in Germany — Apple's 8 EU-specific ATT changes.
- Apple App Tracking Transparency documentation —
ATTrackingManager.requestTrackingAuthorizationand the scope of ATT. - PostHog self-host documentation — the warning that self-hosting isn't officially supported and that PostHog Cloud is recommended.
- posthog-ios CHANGELOG.md — the 3.74.0
sessionReplayConfig.captureTouchesand 3.76.0persistOptOutchanges.

