Repository navigation
chore!: iOS Major Release 4.0 - #873
turnipdabeets wants to merge 17 commits into
Conversation
There was a problem hiding this comment.
This review was skipped because it would exceed your organization's monthly flex usage limit. Raise the limit in billing settings or wait until the next billing period resets limits.
posthog-ios Compliance ReportDate: 2026-10-09 16:05:23 UTC
|
| Test | Status | Duration |
|---|---|---|
| Format Validation.Event Has Required Fields | ✅ | 3172ms |
| Format Validation.Event Has Uuid | ✅ | 2709ms |
| Format Validation.Event Has Lib Properties | ✅ | 2772ms |
| Format Validation.Distinct Id Is String | ✅ | 2684ms |
| Format Validation.Token Is Present | ✅ | 2708ms |
| Format Validation.Custom Properties Preserved | ✅ | 2760ms |
| Format Validation.Event Has Timestamp | ✅ | 2817ms |
| Retry Behavior.Retries On 503 | ✅ | 11818ms |
| Retry Behavior.Does Not Retry On 400 | ✅ | 4702ms |
| Retry Behavior.Does Not Retry On 401 | ✅ | 4888ms |
| Retry Behavior.Respects Retry After Header | ✅ | 7707ms |
| Retry Behavior.Implements Backoff | ✅ | 21698ms |
| Retry Behavior.Retries On 500 | ✅ | 9207ms |
| Retry Behavior.Retries On 502 | ✅ | 9106ms |
| Retry Behavior.Retries On 504 | ✅ | 9190ms |
| Retry Behavior.Max Retries Respected | ❌ | 15272ms |
| Deduplication.Generates Unique Uuids | ✅ | 3196ms |
| Deduplication.Preserves Uuid On Retry | ✅ | 5262ms |
| Deduplication.Preserves Uuid And Timestamp On Retry | ✅ | 10367ms |
| Deduplication.Preserves Uuid And Timestamp On Batch Retry | ✅ | 7776ms |
| Deduplication.No Duplicate Events In Batch | ✅ | 2782ms |
| Deduplication.Different Events Have Different Uuids | ✅ | 2844ms |
| Compression.Sends Gzip When Enabled | ✅ | 2776ms |
| Batch Format.Uses Proper Batch Structure | ✅ | 2757ms |
| Batch Format.Flush With No Events Sends Nothing | ✅ | 339ms |
| Batch Format.Multiple Events Batched Together | ✅ | 2813ms |
| Error Handling.Does Not Retry On 403 | ✅ | 4716ms |
| Error Handling.Does Not Retry On 413 | ✅ | 4736ms |
| Error Handling.Retries On 408 | ✅ | 9296ms |
Failures
retry_behavior.max_retries_respected
Expected 4 requests, got 5
Feature_Flags Tests
✅ 16/16 tests passed
View Details
| Test | Status | Duration |
|---|---|---|
| Request Payload.Request With Person Properties Device Id | ✅ | 2768ms |
| Request Payload.Flags Request Uses V2 Query Param | ✅ | 2666ms |
| Request Payload.Flags Request Hits Flags Path Not Decide | ✅ | 2776ms |
| Request Payload.Flags Request Omits Authorization Header | ✅ | 2723ms |
| Request Payload.Token In Flags Body Matches Init | ✅ | 2775ms |
| Request Payload.Groups Round Trip | ✅ | 2769ms |
| Request Payload.Groups Default To Empty Object | ✅ | 2701ms |
| Request Payload.Person Properties Distinct Id Auto Populated When Caller Omits It | ✅ | 2691ms |
| Request Payload.Disable Geoip False Propagates As Geoip Disable False | ✅ | 2706ms |
| Request Payload.Disable Geoip Omitted Defaults To False | ✅ | 2726ms |
| Request Payload.Flag Keys To Evaluate Contains Only Requested Key | ✅ | 2806ms |
| Request Lifecycle.No Flags Request On Init Alone | ✅ | 58ms |
| Request Lifecycle.No Flags Request On Normal Capture | ✅ | 2779ms |
| Request Lifecycle.Two Flag Calls Produce Two Remote Requests | ✅ | 5490ms |
| Request Lifecycle.Mock Response Value Is Returned To Caller | ✅ | 2742ms |
| Side Effect Events.Get Feature Flag Captures Feature Flag Called Event | ✅ | 2972ms |
6db44c0 to
9393686
Compare
|
[High risk] Removes public API surface for iOS SDK major version. The PR appears safe to merge; no actionable regression was identified. Reviews (1) · Last reviewed commit: "chore!: remove deprecated public APIs fo..." |
e1cc8cf to
5b6c50e
Compare
|
SwiftPM floor: options if Xcode 16 support is needed later 4.0 ships If needed, either of these can ship in a 4.x release without breaking anyone. Both were checked on Xcode 16 in CI:
Either option needs a CI job on the oldest supported Xcode. Raising the floor again before 5.0 would break those users. |
Removes PostHogConfig.apiKey and the apiKey initializers, propertiesSanitizer and PostHogPropertiesSanitizer, evaluationEnvironments, remoteConfig, PostHogSDK.getFeatureFlagPayload, and the session replay debouncerDelay and maskPhotoLibraryImages options. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…hangeset Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Raise the iOS floor from 13 to 15 (Mac Catalyst follows) and remove the availability checks and fallbacks that only protected iOS 13/14. macOS, tvOS, watchOS and visionOS minimums are unchanged, so checks that also gate those platforms keep their non-iOS clauses. Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Moves postHogSdkName, postHogVersion, PostHogSessionManager, PostHogStorageManager, PostHogConfig.storageManager, PostHogConfig.snapshotEndpoint, dateToMillis and imageToBase64 behind @_spi(PostHogInternal), and makes unused public helpers internal. Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
PostHogDataMode.cellular has always behaved the same as .any. Remove it; callers switch to .any with identical flushing behavior. .wifi and .any keep explicit raw values 0 and 2 so the Objective-C constants and any stored raw values stay the same as in 3.x. Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Collapse Package.swift and Package@swift-5.9.swift into a single swift-tools-version 6.2 manifest that keeps Swift 5 language mode, and drop the compiler-version fallbacks that a Swift 6 floor makes dead. CI's minimum-toolchain, Pods-example and CocoaPods publish jobs move to Xcode 26.0.1. Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* chore!: raise minimum macOS to 11, tvOS to 15 and watchOS to 8 Xcode 26, which the package now requires, supports deployment targets down to macOS 11, tvOS 15 and watchOS 8, so the old 10.15 / 13 / 6 floors could no longer be built or tested. Raise them in Package.swift, the podspec, PostHog.xcodeproj and the downgrade smoke package, and remove the availability checks and fallbacks the new floors make dead. iOS 15, Mac Catalyst and visionOS 1 are unchanged. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * chore!: raise minimum watchOS to 10 No posthog-ios events came from watchOS 9 or earlier in the last 30 days on US or EU Cloud, and watchOS 10 supports the same hardware as watchOS 9 (Apple Watch Series 4 and later). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
PostHogLogLevel and PostHogLogEntry belong to session replay console capture, but their names read like the Logs product's PostHogLogSeverity and PostHogLogRecord. Rename them to PostHogConsoleLogLevel and PostHogConsoleLogEntry, matching the existing PostHogSessionReplayConsoleLogConfig naming. No behavior change. Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* chore!: remove the v2 legacy queue migration for v4 Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * chore!: stop reading the 2.x event format in queued events Drop the top-level $set and message_id fallbacks in PostHogEvent.fromJSON. They only served events copied unchanged from the 2.x queue, whose import was removed in the previous commit. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * docs: narrow the changeset to events created by 3.x Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* chore!: drop legacy version and build from lifecycle events Application Installed, Application Updated and Application Opened no longer set `version`/`build`; every event already carries `$app_version` and `$app_build` from the static context. `previous_version` and `previous_build` stay on Application Updated. Matches posthog-react-native 4.0 (#557). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * test: check the background-open event in the from_background test Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* chore!: pass the reload result to reloadFeatureFlags' callback reloadFeatureFlags(_:) now hands its callback a PostHogFeatureFlagsLoaded, the same type onFeatureFlags receives, so callers can tell a failed reload from a successful one. errorsLoading is true when the request failed or the SDK isn't set up; flags and variants then hold the last known values. Part of #557. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: snapshot a failed reload's last known flags once for all callbacks Coalesced reload callbacks each read the live cache on failure, so a reset() in one callback emptied the last known flags reported to the next. The load now captures its result once, before fan-out. Also updates the setPersonPropertiesForFlags example and note for the new callback argument. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * test: gate the first failed reload so the reset regression always coalesces The coalesced-failure + reset() test assumed the first reload was still in flight when the next two registered. Hold its response until both callbacks are pending, and check both shared one request. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * chore!: mark off-main public callbacks @sendable for v4 (#914) * chore!: mark off-main public callbacks @sendable for v4 The reloadFeatureFlags callback, beforeSend blocks, getAnonymousId, pushIdentityProvider and logSanitizer run off the main thread but weren't @sendable. In Swift 6 apps a reloadFeatureFlags closure written in main-actor code traps at runtime; the other callbacks race silently. Also make PostHogFeatureFlagsLoaded Sendable and add a Swift 6 language-mode test target that calls the API as an app would. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * chore: match the public API snapshot to CI's Xcode 26.3 output Xcode 26.3's symbol graph leaves @sendable out of declaration fragments, which 26.4 prints; the mangled names still differ. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: store bridged flag values in PostHogFeatureFlagsLoaded The init kept the original variant values after filtering, so a mutable NSString passed via bootstrap stayed mutable inside a Sendable payload. Store the `as? Bool`/`as? String` results instead. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * docs: clarify the Sendable callbacks changeset Name the config properties unambiguously and warn that array conversions crash in both directions. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* chore!: return nil for malformed feature flag payloads Follow the sdk-specs payload decoding contract: a serialized payload that fails to decode (malformed, empty or whitespace-only) now reads as nil and is logged, instead of leaking the raw string. The flag's value, enabled state and sibling payloads are unaffected. Bootstrapped payloads are already decoded, so they are now serialized when seeded into the payload cache. Reads decode each payload exactly once, so a bootstrapped "123" or "true" string stays a String instead of becoming a number or Bool. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * test: cover bootstrapped string payloads read back after a restart Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * test: clear leftover queue files before each ignoredExceptionTypes capture test storage.reset() keeps the event queue, and getBatchedEvents returns once the mock receives a batch, before the SDK deletes the sent file. The previous test's $exception could survive on disk and be resent by the next SDK, failing the "drops ignored types" assertion on the iOS simulator job. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* chore: replace vendored Reachability with NWPathMonitor Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: match the old reachability notifications Notify on every path update and report the current connection when the notifier starts, as the SCNetworkReachability version did. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: cap the first-path wait and test the reachability notifier Wait for the first path at most 100 ms after init in total, not 100 ms per read. Add tests for the start/update/stop notification rules. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: report reachability from the connection at delivery A start notification queued before a newer path could arrive last and pause the queues while online. Also narrow the changeset to what is actually preserved and list the edge-state changes. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * test: cover unknown and known network state in the context test Seed the context's reachability instead of relying on a live NWPathMonitor delivering its first path within 100 ms, and assert that network properties are omitted until a path arrives. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * test: drive queue reachability tests with update(_:) and cover data modes The logs and replay queue reachability tests used a live NWPathMonitor, so a real path update could race the simulated offline event. Drive them through update(_:) instead, and add tests for .wifi waiting for a Wi-Fi path and .any sending before the first path. Mark the changeset major like the rest of v4. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* feat: add SessionReplayWebP and CrashReporting package traits SwiftPM apps can now leave out the vendored libwebp and PLCrashReporter by disabling the traits. Both are on by default, so existing setups are unchanged; CocoaPods and xcodeproj builds always include both. Also moves the ignoredExceptionTypes matcher out of the crash-reporting gate so it applies to manual captures everywhere, which fixes it on watchOS and visionOS. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * test: gate WebP suites on the SessionReplayWebP trait The WebP test suites called `UIImage.webpData`, which SwiftPM compiles out on iOS when the trait is off, so the test target failed to build. Gate them like the encoder and add a separate encoding test that expects WebP or the JPEG fallback depending on the trait. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * ci: compile the iOS test target with package traits off `make test` runs on macOS, where the iOS-only trait gates compile out, so a test calling trait-gated SDK code on iOS went unnoticed. Build the iOS test target for the simulator with traits off and with each trait on its own. The concurrent flag reload suite's `.timeLimit` needs iOS 16, so limit it to macOS SwiftPM builds rather than every SwiftPM build. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * feat!: replace the SessionReplayWebP trait with SessionReplay SessionReplay now gates the whole replay engine along with libwebp, so an app that doesn't use replay can leave all of it out. The public replay API (config, masking modifiers, URLSession helpers, start/stop recording) stays compiled; with the trait off the replay integration is a stub that is skipped with `disabledByPackageTrait`. A finer split (replay without WebP) can come later in a minor release by keeping SessionReplay as an umbrella trait that enables the new ones. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * test: gate the remaining replay tests on the SessionReplay trait The session replay suite and the two SDK tests that assert replay debug properties need the replay engine, so skip them in SPM builds with the SessionReplay trait off. Also list buildTestsSpmTraitsIOS for trait-gated changes in the contributor guide. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * test: limit the Swift 6 callback suite's timeLimit to macOS `.timeLimit` needs iOS 16, above the iOS 15 minimum, so the iOS SwiftPM test build failed after merging the 4.0 base. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * feat: add Surveys package trait (#918) * feat: add Surveys package trait SwiftPM apps that don't use surveys can now leave out the survey engine and UI by disabling the `Surveys` trait. It is on by default, so existing setups are unchanged; CocoaPods and xcodeproj builds always include surveys. The public survey API (`config.surveys`, `surveysConfig`, the delegate protocol and display models) stays compiled. With the trait off, the survey integration is a stub that is skipped with `disabledByPackageTrait`. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * docs: note the Surveys trait on surveysConfig and surveysDelegate A custom surveysDelegate is never called when the trait is off, so say so where apps set it. Also drop the unused clearInstalls() from the stub. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
3e050a7 to
7bb79ca
Compare
There was a problem hiding this comment.
Not approved yet — waiting on the conditions below.
Re-add the stamphog label to request another review once you have addressed this.
Gates denied this change because it modifies toolchain and CI infrastructure and exceeds the automated-review size limit; no current-head review or ownership/familiarity assurance is reported. Route the release to human maintainers, disclose its broader scope, and address the persisted-data loss before re-requesting.
- 👍 on the PR from greptile-apps[bot].
- PostHog/PostHogFileBackedQueue.swift: setup deletes legacy queue files rather than importing their events, losing queued analytics on direct upgrades from version 2. PostHog/Models/PostHogEvent.swift also drops legacy person-property updates from already-imported events. Restore preservation of these persisted records or obtain explicit human review of the data-loss behavior.
- Trusted gate denial: dependency/toolchain and CI infrastructure changes are excluded from automated approval, and the cross-cutting change exceeds the automated-review size ceiling. Route this release to human maintainers.
- Undisclosed risky behavior: the description limits the scope to deprecated declarations and their supporting code, but Package.swift adds optional feature traits, workflows change build and release execution, and PostHog/PostHogFileBackedQueue.swift deletes legacy queued data. Update the description to disclose the full scope and request human review; changeset documentation does not make the stated scope accurate.
Gate mechanics and policy version
| Gate | Result | |
|---|---|---|
| prerequisites | ✓ | all clear |
| deny-list | ✗ | matches: deps_toolchain, infra_cicd |
| size | ✗ | too large for auto-review (10396L substantive in global — ceiling is 800L; 10396L, 156F total, 10628L/176F incl. docs/generated/snapshots) |
| tier | ✗ | classified as T2-never: T2-never (10628L, 176F, cross-cutting, chore) |
| stamphog 2.4.1 | .stamphog/policy.yml @ 7bb79ca · reviewed head 7bb79ca |
* chore!: remove wireframe session replay capture Session replay on iOS now always captures masked screenshots. Wireframe mode skipped SwiftUI-rooted windows entirely and leaked ph-no-capture containers (sdk-specs n26). `screenshotMode` is kept as a deprecated no-op so wrappers that set it keep compiling. The replay meta href is now resolved from the visible screen on every capture. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: keep secure text fields masked under ph-no-mask Wireframe masked secure fields regardless of ph-no-mask; screenshot capture stopped the walk at the unmasked ancestor. Now that screenshots are the only mode, keep secure-entry inputs masked in that subtree, matching Android's password handling and the session-replay-privacy spec. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: mask full-window no-capture leaves and secure fields under a no-mask cover ancestor A full-window view tagged ph-no-capture with no subviews now contributes its own mask instead of relying on descendants it doesn't have. When a ph-no-mask ancestor sits above a selected presentation cover, secure-entry fields inside the cover are still masked. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix(replay): keep view controller titles out of the replay href A plain UIViewController's title is display text and can contain user data, so the replay meta href now uses the controller's type name only. $screen naming still falls back to the title. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
| if !viewRect.equalTo(windowRect) { | ||
| // Check if the rectangles do not match. A full-window leaf has no descendants | ||
| // to carry the mask, so it is masked itself. | ||
| if !viewRect.equalTo(windowRect) || view.subviews.isEmpty { |
There was a problem hiding this comment.
Low: Full-window no-capture containers expose their own drawing
Consider a full-window custom UIView tagged ph-no-capture that draws a secret at the top and contains a small child at the bottom: this branch collects only the child's mask, leaving the secret readable in the uploaded screenshot. For apps previously using default wireframes, replay viewers can now read that custom-drawn content despite the explicit privacy marker. (raw.githubusercontent.com)
Redact the tagged view's own rendered region even when it has subviews, rather than assuming descendant masks cover its content; preserve intentional unmask overrides separately.
PR overviewThis PR introduces the iOS 4.0 major release, including changes to session replay screenshot masking for view hierarchies. One privacy issue remains open: certain full-window custom views marked as no-capture can still expose their own drawn content in uploaded replay screenshots. This can make sensitive content readable to replay viewers despite the app’s explicit privacy marker, though exposure depends on the affected view layout. No issues have been fixed or addressed yet. Open issues (1)
Fixed/addressed: 0 · PR risk: 5/10 |
Screenshots are always captured on the main thread with the settle-then-shoot path. Removes the opt-in off-main render path, its sweptRects mask helper and the tests that only covered it. Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
💡 Motivation and Context
Closes #557
First PR stacked on
release/4.0, the base branch for the 4.0 major. It removes every public API that is already marked deprecated.PostHogConfig.apiKey,init(apiKey:),init(apiKey:host:)projectToken,init(projectToken:),init(projectToken:host:)PostHogConfig.propertiesSanitizer,PostHogPropertiesSanitizerPostHogConfig.setBeforeSend(_:)PostHogConfig.evaluationEnvironmentsevaluationContextsPostHogConfig.remoteConfigPostHogSDK.getFeatureFlagPayload(_:)getFeatureFlagResult(_:sendFeatureFlagEvent:)?.payloadPostHogSessionReplayConfig.debouncerDelaythrottleDelayPostHogSessionReplayConfig.maskPhotoLibraryImagesPublic API change: this is a breaking removal, see the
api/posthog-ios.public-api.txtdiff.Left in place on purpose:
PostHog/Utils/Reachability.swift, which is internal vendored code.PostHogConfig(apiKey:)inscripts/downgrade-compatibility-smoke, which compiles against 3.48.0.PostHogEvent.apiKeyandPostHogRemoteConfig.getFeatureFlagPayload.migrateLegacyStorage(added in 3.20) andmergeLegacyContainerIfNeeded(the app-group merge, added in 3.27). Both run on every init, but removing them would cost data. If someone updates an app straight from an older version to 4.x, their users lose their distinct ID and any queued events. In the last 7 days (US), about 8% of iOS SDK end-users were on an app build older than 3.27, and about 6% of apps had not shipped 3.27 or later. The app-group merge only affects apps that setappGroupIdentifier, so its share is smaller. We'll revisit in a later major.Wrapper SDKs: posthog-flutter called
getFeatureFlagPayload; PostHog/posthog-flutter#630 moves it off. The React Native plugin calls none of the removed APIs. Both pin posthog-ios below 4.0.Wrapper SDK releases
posthog-ios 4.0 ships with a major release of each wrapper that embeds it. Each adoption PR waits until 4.0 is published.
💚 How did you test it?
make testpasses locally (909 tests, macOS).make apiUpdate.make buildfor the other platforms and example apps, and the iOS simulator test job.📝 Checklist
If releasing new changes
pnpm changesetto generate a changeset fileThe changeset is
majorand was written by hand in the changeset format. The release workflow only runs onmain, so nothing publishes untilrelease/4.0merges there.🤖 Agent context
Autonomy: Human-driven (agent-assisted)
@available(*, deprecated), plus the code, tests and comments that only existed to support them.🤖 Generated with Claude Code