Repository navigation
chore!: adopt posthog-android 4.0, core 7.0 and posthog-ios 4.0 - #108
turnipdabeets wants to merge 34 commits into
Conversation
|
f370e9e to
1f3982e
Compare
posthog-android 4.0 and posthog-ios 4.0 always record masked screenshots, so the flag no longer selects anything. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
There was a problem hiding this comment.
PostHog Review · Standard · reviewed 2ab12cc: 1 Must fix, 1 Should fix.
This is the only automatic review while this pull request is a draft. Comment @posthog review to review new changes sooner. Otherwise, a review of the new changes runs when you mark it ready for review.
See this review and its findings in PostHog Review. Comment @posthog review --deep for a Deep review. A Deep review takes longer and looks deeper than a Standard review.
Capture v1 strips `$lib`/`$lib_version` from event properties and reads them from the PostHog-Sdk-Info header, so the `$lib` stamping in beforeSend no longer reaches PostHog. Set the native SDK name and version before setup instead (PostHog/posthog-ios#1027), drop the stamping, and only install the native beforeSend when the app configures callbacks. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
posthog-android 4.0 removed the defaultValue parameter from getFeatureFlag (PostHog/posthog-android#917), so the native call now receives two arguments. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Ran :sample:integrateLinkagePackage. Package.resolved and .swiftpm-locks still pin 3.64.1: they can only be re-resolved once posthog-ios 4.0.0 is tagged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
List the native 4.0 changes KMP apps inherit that the changeset missed: Xcode 26, empty-name and oversized-ID drops, the stricter redirect rule, iOS/macOS lifecycle events losing version/build, and the new $app_language. Drop the $lib bullet: posthog-android#942 and posthog-ios#1036 keep $lib/$lib_version on capture v1 events, so they behave as in 0.10. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Match the native SDKs' name for the replay snapshot throttle and apply it on iOS too. debouncerDelayMs stays as a deprecated alias, including as a named constructor argument. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
749bd17 to
87763cb
Compare
Proxies set up from PostHog's proxy guides before 29 October 2026 drop the Authorization header, so capture v1 gets a 401 and the events are dropped. The managed reverse proxy needs no change.
Pass PostHogFeatureFlagsLoaded to the reloadFeatureFlags callback and call it before setup on every platform. Add onFeatureFlags, person and group properties for flags, and PostHogConfig.evaluationContexts. Use the iOS 4.0 isFeatureEnabled with defaultValue, and read an empty variant as disabled on every platform.
|
Two items in the description are stale: #115 already merged into this branch, and Apple |
posthog-js calls the handlers it snapshotted before an unsubscribe, so a listener removed by another listener mid-notification still ran. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…g on JS and Wasm The posthog-js facade enables person processing before it stores the overrides, and drops them with person_profiles 'never'. Call the feature flags extension directly, like Android, JVM, iOS and macOS. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ation guide - a beforeSend that sets or removes a registered $process_person_profile keeps identify(), alias(), group() and setPersonProperties() working - a $process_person_profile passed to capture() is new in 0.11 and wins over NEVER - a registered $session_id replaces the SDK's session ID - PostHog keeps a personless $set event and only skips the person update Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
@eli-r-ph Right, 0.11 doesn't expose capture |
883184d to
b6b4b21
Compare
There was a problem hiding this comment.
PostHog Review · Standard · reviewed 883184d: 1 Must fix. This pull request is large, so the review ran in 4 parts with less depth than usual.
This is review round 3 on this pull request. When findings keep coming back in the same code, the approach is usually the problem. Before the next fix, check whether a different design would remove the whole class of findings.
|
Hey @turnipdabeets
🤔 as long as it isn't writing to |
|
Correction to my earlier note: 0.11 does write to
Does 0.11 publish the same day as the native 4.0 SDKs? |
…ve-4.0 # Conflicts: # gradle/libs.versions.toml
|
Updated the description: #115 is marked merged, and the flags row says Apple |
* feat: add event options, registerOptions and captureAi Expose the capture v1 options posthog-android 4.0 and posthog-ios 4.0 take: - PostHogEventOptions (processPersonProfile, cookielessMode, disableSkewCorrection, productTourId), passed through CaptureOptions.eventOptions and a new eventOptions parameter on screen, identify, alias, group, setPersonProperties and captureException - PostHog.registerOptions/unregisterOptions, backed by the native wrapper option registry - PostHogEvent.options, so beforeSend can read and change them; option keys KMP doesn't know are kept - PostHog.captureAi, returning the event UUID posthog-js has no options, so JS and Wasm send the known ones as their legacy $ properties on capture, screen and captureException, drop them on the identity calls, and make captureAi a no-op that returns null. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix: keep native options when beforeSend returns a constructed event A callback that built a new PostHogEvent got the default empty options, which cleared the SDK's process_person_profile = false and turned person processing on for anonymous events. PostHogEvent.options is now nullable, and null keeps the options of the event the callback was given, as on posthog-android. Also corrects the registerOptions KDoc: on JS and Wasm, posthog-js merges registered properties before before_send runs. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix: keep options an earlier beforeSend callback set when a later one drops them Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat!: send event options as a map and add captureAi lane config Match the capture v1 contract in sdk-specs#146: - Event options are a Map<String, Any?> sent as given, so keys the SDK doesn't know pass through. PostHogEventOptions becomes the four key constants. beforeSend reads and changes the native options map. - PostHogConfig gains captureAiCompression, captureAiMaxQueueSize, captureAiTimeout and captureAiMaxEventBytes, forwarded to the native SDKs. - A throwing beforeSend callback's debug log names the event and the exception type. - The migration guide sets these through options. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs: cover #119's binary breaks, the AI endpoint and web registerOptions in the 0.11 migration guide Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs: say beforeSend options are null on web and stored numbers are Long on Apple On iOS and macOS, values that go through native storage, such as register() properties and registerOptions() options, reach beforeSend as Long, while Android keeps Int. Verified on the iOS simulator. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs: point the process_person_profile migration rows only at event options Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test: cover beforeSend clearing options with emptyMap and keeping them with null Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix: leave unset captureAi settings to the native SDK defaults Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs: say a registered process_person_profile skips identity events Matches posthog-ios#1067 and posthog-android#979: a registered value no longer reaches identify, alias, group and setPersonProperties events; a value passed on the call still applies. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
The reference generator from #123 stops on any PostHog member that docs/capabilities.json doesn't map, so the release's reference step would fail on captureAi, onFeatureFlags, registerOptions, unregisterOptions, setAppLanguage and the four *PropertiesForFlags functions. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
posthog-ios 4.0 schedules replay captures from the run loop (posthog-ios#896, shipped in 3.94.0), so iOS now records Compose Multiplatform screens, which the pinned 3.64.1 never did. Masking still walks UIKit views, so text fields, text and images that Compose draws aren't masked. Verified on the iOS simulator: a Compose TextField was readable in the frames with default masking, and a ph-no-capture tag on the Compose view masked the whole view. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Important
This is the posthog-kmp 0.11 integration PR. Don't merge it until posthog-android 4.0.0 (+ core 7.0.0) and posthog-ios 4.0.0 are published. Merging releases 0.11.0. CI fails until then, only because the pinned versions don't exist yet (
iOS Build: "no versions of 'posthog-ios' match the requirement 4.0.0"). As of 2026-11-13, PostHog/posthog-android#871 and PostHog/posthog-ios#873 are both still open (latest releases: android 3.77.1, iOS 3.97.0). All stacked 0.11 PRs are merged into this branch, andmainis merged in up to #123.💡 Motivation and Context
posthog-kmp 0.11 adopts the native 4.0 majors (PostHog/posthog-android#871, PostHog/posthog-ios#873). KMP has no HTTP code of its own, so Android, JVM, iOS and macOS move to capture v1 with them. JS and Wasm stay on posthog-js.
/i/v1/analytics/events), and the newcaptureAisends AI events to/i/v1/ai/events.CaptureOptions.eventOptions,registerOptions(),PostHogEvent.options) and the native property precedence.PostHogFeatureFlagsLoadedin the reload callback,onFeatureFlags(), flag properties,evaluationContexts.SessionRecordingConfig.screenshotis gone, andthrottleDelayMsreplacesdebouncerDelayMs.The upgrade guide is
MIGRATION.md(0.10 → 0.11). From #123, the release also publishes it as the generated migration page.Docs and onboarding that ship with this release (merge once 0.11.0 is on Maven Central):
captureAi, flags, app language, upgrade checklist).screenshot,throttleDelayMs, requires 0.11.0). It also carries React Native plugin 3.0 changes; split those out if the two releases don't ship together.What gets released
com.posthog:posthog-kmpadopt-native-4-0,drop-replay-screenshot-option,replay-throttle-delay,feature-flags-native-parity,v1-event-options.Apps that also pull in
posthog-serverneed 2.25.0 or later, and apps that useposthog-android-surveys-composedeclareposthog-android4.0.0 alongside it. Core 7.0 isn't binary compatible with artifacts built against core 6.x. The changeset and the guide cover both.Merged into this branch
throttleDelayMsandprojectTokenin the native mappings; Apple reportsposthog-kmpthroughPostHogSDK.setSdkNameinstead of stamping$libinbeforeSend; regenerated sample linkage packageSessionRecordingConfig.screenshotthrottleDelayMs, deprecatedebouncerDelayMs, apply it on iOS too481ea99and follow-upsPostHogFeatureFlagsLoaded,onFeatureFlags(),set/reset{Person,Group}PropertiesForFlags,evaluationContexts, AppleisFeatureEnabledwithdefaultValue, empty variant reads as disabled everywherePostHog.setAppLanguage(), BCP 47$localeon JVMerrorsLoadingreplay,beforeSendperson-processing noteregisterOptions()/unregisterOptions()(through the native wrapper-option APIs, PostHog/posthog-android#954 and PostHog/posthog-ios#1045),PostHogEvent.options,captureAi()and its four config optionsmainRelease review changes in this PR (2026-11-13)
main(docs: generate the SDK reference as Markdown with Dokka #123) and mapped the newPostHogmembers indocs/capabilities.json(7304360). docs: generate the SDK reference as Markdown with Dokka #123's generator stops withPostHog.captureAi is not in docs/capabilities.jsonon any unmapped member. The release step is best-effort, so the release would still publish, but the reference pages wouldn't regenerate.captureAi,onFeatureFlags, the four*PropertiesForFlagsfunctions andregisterOptions/unregisterOptionsmap to their sdk-specs capabilities;setAppLanguagegoes under SDK utils. Ran the generator locally against the native 4.0 builds: it passes, and writes the reference and the migration page.MIGRATION.mdagainst both native 4.0 descriptions and guides as of today. No gaps: the registered$process_person_profileexemption for identity events (fix: keep a registered personless setting off identity events posthog-android#979, posthog-iosidentityEvents),nullhandling (fix: keep null array elements in event properties posthog-android#955, fix: omit null-valued event properties posthog-ios#1047),$libkept per event (fix: keep $lib and $lib_version on capture v1 events posthog-android#942, fix: keep $lib and $lib_version on capture v1 events posthog-ios#1036), empty variants (fix(flags): read an empty variant as disabled in getFeatureFlagResult and onFeatureFlags posthog-android#949, fix(flags): read an empty variant as disabled in getFeatureFlagResult and onFeatureFlags posthog-ios#1037) and the 3.77mainmerge into android 4.0 (failed flags read as missing) all match.$process_person_profiledropsidentify/alias/groupevents, which native 4.0 changed. Fixed there (PostHog/posthog.com@cdab7ec), with thecaptureAi*config rows marked nullable as they are inPostHogConfig.PostHogDataMode.cellular, thePostHogConsoleLog*renames,didReceiveFeatureFlags,maxRetries→pushNotificationSubscriptionMaxRetries,screenshotMode. posthog-ios 4.0 is SPM-only, which KMP already uses, and its package traits are on by default.✅ Before release
CALayerreplay crash fix, docs: sort the iOS 4.0.0 migration guide by when you make each change posthog-ios#1061 and a finalmainmerge).TODOcomments ingradle/libs.versions.tomland theTODO(native-4.0-links)comment inMIGRATION.md, after checking that both native migration guide links (android-v4.0.0,4.0.0) resolve..swiftpm-locks/default/swiftImport/Package.resolvedandsample/iosApp/iosApp.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved(both still pin 3.64.1). CI's "Verify committed iOS linkage files" step fails until they do.mainagain, re-run CI, and get an approval. Ifmainadded aPostHogmember, map it indocs/capabilities.json.Release day, after 0.11.0 is on Maven Central
references/(best-effort step). If not, rungenerate-references.yml.@posthog/react-native-plugin3.0 isn't out yet.After release
captureAiin the LLM analytics manual-capture onboarding. docs(onboarding): update android onboarding for posthog-android 4.0 posthog#129665 adds Android, iOS and Flutter tabs only.🔍 Follow-ups found while testing (not caused by this PR)
TextFieldwas readable with default masking (simulator, 2026-11-13,1a1205c).ph-no-captureon the Compose view masks it whole.MIGRATION.md, the changeset and docs(kmp): update for posthog-kmp 0.11 posthog.com#22013 now document it. fix(replay): mask Compose Multiplatform views whole posthog-ios#1074 (draft) masks Compose views whole by default; verified end to end on the simulator. Decide before release whether to wait for it in posthog-ios 4.0.setup()again afterclose()keeps the first posthog-js instance, so a secondprojectTokenis ignored. Pre-existing on JS/Wasm.💚 How did you test it?
Built against the native integration branches as of 2026-11-05: posthog-android
chore/v4-remove-deprecated@be3ed4b+ #942, published to a local Maven repo as 4.0.0 / core 7.0.0; posthog-ioschore/v4-remove-deprecated@3460e53+ #1036 as a local Swift package. The sample was wired to them in a scratch worktree only. Nothing from that wiring is committed.🤖 Testing locally (native 4.0 isn't published yet)
CI fails here only because posthog-android 4.0.0, core 7.0.0 and posthog-ios 4.0.0 aren't released, so Gradle and SwiftPM can't resolve them. The PR is still testable: point it at the unreleased native branches locally. Don't commit any of this. Verified 2026-11-09:
:posthog-kmp:jvmTest,:posthog-kmp:testAndroidHostTestand:posthog-kmp:iosSimulatorArm64Testpass.Android: publish posthog-android 4.0 (and core 7.0) to mavenLocal:
Then add
mavenLocal()as the first entry ofdependencyResolutionManagement { repositories { … } }insettings.gradle.kts. The versions are pinned exactly (4.0.0/7.0.0ingradle/libs.versions.toml), so nothing else changes.iOS / macOS: in
posthog-kmp/build.gradle.kts, point theswiftPackage(…)at the branch:The build rewrites
.swiftpm-locks/; discard those changes too.Run:
Unit tests and builds
jvmTest/testAndroidHostTestiosSimulatorArm64Test/macosArm64TestjsBrowserTest/jsNodeTest/wasmJsBrowserTestdetektassembleDebug, JVM:sample:run, Wasm distribution,integrateLinkagePackage+ XcodeiosAppfor simulator and device (both privacy bundles present)Devices
A scratch scenario in the sample's common code ran the same script on every platform, logged each check, and tagged events with a run ID. Mobile and JVM traffic went through a logging proxy to PostHog US cloud, so the wire format and the stored events were both checked. Each platform ran a
mainlaunch and then arestartlaunch, which force-stops the app first.phx_step, see follow-ups)macOS native (
macosArm64) is covered bymacosArm64Testonly; the sample has no native macOS app.New 4.0 behavior, verified:
POST /i/v1/analytics/events(gzip,Authorization: Bearer phc_…,PostHog-Sdk-Info: posthog-kmp/0.10.0) on Android, JVM and iOS. Session replay uploads go to/s/.$lib = posthog-kmp,$lib_version = 0.10.0stay in each event body, can be read inbeforeSend, and are stored that way. On iOS this comes fromsetSdkName.phx_key disables the SDK: its event never arrived on Android, JVM or iOS.register("$os_name", …)super property overrides the SDK's value, andunregisterrestores it.process_person_profile: falsecapture option instead of a property.$session_idis sent as the top-levelsession_id.$localeisen-USeverywhere.$app_languageisenon iOS. On Android it'sfr-FRaftercmd locale set-app-locales … fr-FR, and absent without a per-app locale orlocaleConfig, as designed.Application Installed/Openedhave$app_version/$app_buildand noversion/build. Android keeps them."plain text") decodes to aString. A non-JSON payload can't be created in PostHog (the API rejects it), so thenullpath rests on the native tests.Regression, verified:
beforeSendremoves a property, adds one, and drops a named event.CaptureOptionsgroups and timestamp work, andscreen()keeps its name over a$screen_nameproperty.getFeatureFlagreturns the variant.isFeatureEnabledworks with and withoutdefaultValue, and a missing flag returnsnullor the default.getFeatureFlagResultreturns JSON payloads as maps, andgetAllFeatureFlagsworks.reloadFeatureFlagsfires its callback, and a person-property flag turns on afteridentify+ reload.identify($set/$set_once),alias,setPersonProperties,group($groupidentify),getAnonymousId,getDistinctIdandgetSessionIdall work.captureExceptionarrives with a stack trace.optOutdrops events andoptInresumes them.flushworks, and super properties persist.reset()creates a new ID.PostHog-Attempt: 2) and delivered it.Re-run on 2026-11-13 (release review)
At
7304360(after #119 and themainmerge), against the current native heads: posthog-androidchore/v4-remove-deprecated@7bd8b195published to mavenLocal as 4.0.0 / core 7.0.0, and posthog-ioschore/v4-remove-deprecated@ef45d7b. Same local wiring as above, not committed.jvmTest/testAndroidHostTestiosSimulatorArm64Test/macosArm64TestjsNodeTest/wasmJsBrowserTestdetektscripts/generate_markdown.pyDevices weren't re-run.
📝 Checklist
MIGRATION.md; docs(kmp): update for posthog-kmp 0.11 posthog.com#22013 and docs(replay): update kmp 0.11 and react native plugin 3.0 replay onboarding posthog#125537 merge after the release.)If releasing new changes
pnpm changeto generate a change intent file🤖 Agent context
Autonomy: Human-driven (agent-assisted)
Claude Code (Claude Opus 5.5) built KMP against the native 4.0 integration branches, fixed the compile and test failures, and ran the device matrix above. It audited both native 4.0 changesets against the KMP API to complete the changesets and write
MIGRATION.md, and ran amainbaseline to confirm that the iOS Compose replay gap predates this PR. In the 2026-11-13 release review it mergedmain, mapped the new members for the reference generator, re-checked the changesets and guide against the current native 4.0 PRs, and fixed the posthog.com page.🤖 Generated with Claude Code