Kotlin Multiplatform
Contents
The PostHog Kotlin Multiplatform (KMP) SDK lets you capture analytics from shared Kotlin code that runs on Android, iOS, and the web. It's a thin wrapper that delegates to the official native PostHog SDKs on each target – Android, iOS, and JavaScript – so you get native batching, queueing, and session replay behind a single common API.
Early access: This SDK is currently in a
0.xpre-release. The API may change between minor versions until it stabilizes. We'd love your feedback on GitHub.
Installation
Add the dependency to your shared module's commonMain source set:
You can find the latest version on Maven Central.
Configure the SDK
Initialize PostHog once, early in your app's lifecycle, by calling PostHog.setup() with a PostHogConfig and a platform PostHogContext:
You can find your project token and host in your project settings. For convenience, PostHogConfig.HOST_US and PostHogConfig.HOST_EU are provided as constants for the two PostHog Cloud hosts.
Platform-specific setup
The only platform difference is how you build PostHogContext. Everything else – event capture, feature flags, config – is shared code.
Android
Android requires the Application instance, so pass it to PostHogContext:
iOS
On iOS, use the no-argument PostHogContext():
Web
On the web, use the no-argument PostHogContext():
Capturing events
You can send custom events using capture:
You can add properties to any event by passing a properties map:
To attach group context or a custom timestamp to a single event, pass CaptureOptions:
Note: Properties with
nullvalues are dropped before the event is sent, so every platform receives the same event shape.
Identifying users
Identifying users is required. Call
posthog.identify('your-user-id')after login to link events to a known user. This is what connects frontend event captures, session replays, LLM traces, and error tracking to the same person — and lets backend events link back too.See our guide on identifying users for how to set this up.
Use identify to associate events with a specific user and, optionally, set person properties:
userPropertiesSetOnce works just like userProperties, except it only sets a property if the user doesn't already have it:
Anonymous and identified events
PostHog captures two types of events: anonymous and identified
Identified events enable you to attribute events to specific users, and attach person properties. They're best suited for logged-in users.
Scenarios where you want to capture identified events are:
- Tracking logged-in users in B2B and B2C SaaS apps
- Doing user segmented product analysis
- Growth and marketing teams wanting to analyze the complete conversion lifecycle
Anonymous events are events without individually identifiable data. They're best suited for web analytics or apps where users aren't logged in.
Scenarios where you want to capture anonymous events are:
- Tracking a marketing website
- Content-focused sites
- B2C apps where users don't sign up or log in
Under the hood, the key difference between identified and anonymous events is that for identified events we create a person profile for the user, whereas for anonymous events we do not.
Important: Due to the reduced cost of processing them, anonymous events can be up to 4x cheaper than identified ones, so we recommended you only capture identified events when needed.
Get the current user's distinct ID
You may find it helpful to get the current user's distinct ID – for example, to check whether you've already called identify for a user. Call getDistinctId(), which returns either the ID automatically generated by PostHog or the one passed to identify():
Alias
Sometimes you want to assign multiple distinct IDs to a single user. This is helpful when your primary distinct ID is inaccessible – for example, if a distinct ID used on the frontend isn't available in your backend. Use alias to assign another distinct ID to the same user:
We strongly recommend reading our docs on alias to best understand how to correctly use this method.
Setting person properties
Besides setting properties during identify, you can set person properties directly with setPersonProperties:
Super properties
Super properties are properties you set once and then send with every subsequent capture call. They're set with PostHog.register, which takes a key and value, and they persist across sessions:
The call above ensures every event sent by the user includes "team_id": 22.
Note: This stores properties against the user's events, not against the user profile itself. To store properties against the person, use
identifyorsetPersonProperties.
To stop sending a super property with events, use unregister:
If you're doing this as part of a user logging out, you can instead call PostHog.reset(), which clears all stored super properties and more.
Feature flags
PostHog's feature flags enable you to safely deploy and roll back new features as well as target specific users and groups with them.
By default, flags are preloaded on setup (preloadFeatureFlags = true). Check whether a flag is enabled:
Get the value of a multivariate flag:
Get a detailed result, including the flag's payload:
Get every evaluated flag at once as a map of FeatureFlagResult:
Feature flags are fetched on setup and cached. If a user's properties change (for example, after identify), reload them so they reflect the latest state:
Experiments (A/B tests)
Since experiments use feature flags, running one is very similar to the feature flag code above:
It's also possible to run experiments without using feature flags.
Group analytics
Group analytics lets you associate a user's events with a group (for example, a company, team, or organization). Read the group analytics guide for more information.
Note: This is a paid feature and is not available on the free plan. Learn more on the pricing page.
Associate the current user's events with a group:
Associate with a group and update that group's properties at the same time:
The name is a special property used in the PostHog UI for the group's name. If you don't specify it, the group key is used instead.
Screen views
Capture a screen view with screen:
You can add properties too:
To automatically capture screen views on Android, set captureScreenViews = true in your config.
Error tracking
Capture handled exceptions with their stack traces so they show up in error tracking:
Session replay
Session replay is available on Android and iOS. To enable it, turn on "Record user sessions" in your project settings and pass a SessionRecordingConfig:
You can also enable experimental screenshot mode instead of the default wireframe recording:
Warning: Screenshots may contain sensitive information. Make sure masking is configured appropriately before enabling screenshot mode.
Opt out of data capture
You can opt users out of data capture in two ways.
Opt users out by default by setting optOut to true in your config:
Or opt a user out (and back in) at runtime:
Check whether a user is currently opted out:
Session management
Access the identifiers PostHog uses for the current session:
Flush
You can configure how many events queue before flushing with flushAt.
Setting this to 1 will send events immediately and will use more battery. The default is 20.
You can also manually flush the queue to start sending events immediately instead of waiting for the next batch:
Flushing is best-effort and asynchronous – it starts sending queued events in the background but doesn't wait for the request to finish, so it isn't a delivery guarantee.
Reset after logout
To reset the user's ID and anonymous ID, call reset. Usually you'd do this right after the user logs out:
Close
To flush queued events and release resources during a clean shutdown, call close:
Debug mode
If you're not seeing the events, feature flags, or session replay behavior you expect, enable debug mode to see verbose logs about what the SDK is doing:
All configuration options
Pass these to PostHogConfig when calling setup.
| Option | Type | Default | Description |
|---|---|---|---|
apiKey | String | Required | Your PostHog project token. |
host | String | HOST_US | PostHog instance URL. Use PostHogConfig.HOST_US (https://us.i.posthog.com) or PostHogConfig.HOST_EU (https://eu.i.posthog.com). |
debug | Boolean | false | Enables verbose SDK logging. |
captureApplicationLifecycleEvents | Boolean | true | Captures app open/close lifecycle events (mobile). |
captureScreenViews | Boolean | false | Automatically captures $screen events (Android). |
captureDeepLinks | Boolean | true | Captures deep link opens (Android). |
sendFeatureFlagEvent | Boolean | true | Sends $feature_flag_called when a flag is evaluated. |
preloadFeatureFlags | Boolean | true | Fetches feature flags automatically during setup. |
flushAt | Int | 20 | Number of queued events that triggers a flush. |
flushIntervalSeconds | Int | 30 | Maximum delay before queued events are flushed. |
maxQueueSize | Int | 1000 | Maximum number of events kept in the queue. |
maxBatchSize | Int | 50 | Maximum number of events sent in one batch. |
optOut | Boolean | false | Starts with analytics opted out. |
personProfiles | PersonProfiles | IDENTIFIED_ONLY | When person profiles are created: IDENTIFIED_ONLY, ALWAYS, or NEVER. |
sessionRecording | SessionRecordingConfig? | null | Enables and configures session replay (Android and iOS). |
autocapture | Boolean | false | Enables automatic event capture where the native platform supports it. |
Session recording options
Pass a SessionRecordingConfig to PostHogConfig.sessionRecording. Defaults match the native Android and iOS SDKs.
| Option | Type | Default | Description |
|---|---|---|---|
enabled | Boolean | true | Enables session recording. |
maskAllTextInputs | Boolean | true | Masks all text input values. |
maskAllImages | Boolean | true | Masks all images. |
captureNetworkTelemetry | Boolean | true | Includes network requests in the recording. |
captureLogs | Boolean | false | Captures console and system logs (iOS and web). |
screenshot | Boolean | false | Uses screenshots instead of wireframes (experimental, Android and iOS). |
captureLogcat | Boolean | true | Captures Android logcat output (Android only). |
debouncerDelayMs | Long | 1000 | Touch event debounce delay in milliseconds (Android only). |
Platform support
| Platform | Status | Backed by |
|---|---|---|
| Android | ✅ | PostHog Android (native) |
| iOS | ✅ | PostHog iOS (native, via a Swift bridge) |
| Web | ✅ | PostHog.js |
Because the SDK delegates to the native library on each platform, feature availability and behavior follow the underlying SDK. Session replay is available on Android and iOS; the web target inherits PostHog.js behavior.
FAQ
Which platforms does the KMP SDK support?
Android, iOS, and web. The SDK is designed for Kotlin Multiplatform projects – including Compose Multiplatform – that share business logic across these targets.
Is this different from the Android SDK?
Yes. The Android SDK is for native Android apps. The KMP SDK is for shared Kotlin code targeting multiple platforms, and it wraps the native Android, iOS, and web SDKs so you can call one common API from commonMain.
Why don't I see surveys or logs?
The KMP wrapper currently exposes event capture, identification, feature flags, group analytics, screen tracking, session replay, and error tracking. Surveys and logs aren't wrapped yet. Follow along or request them on GitHub.