Skip to content

chore(react-native-plugin)!: Major Release v3 - #5194

Draft
turnipdabeets wants to merge 10 commits into
mainfrom
chore/rn-plugin-v3
Draft

turnipdabeets wants to merge 10 commits into
mainfrom
chore/rn-plugin-v3

Conversation

@turnipdabeets

@turnipdabeets turnipdabeets commented Oct 2, 2026 •

Copy link
Copy Markdown
Contributor

Problem

posthog-ios 4.0 will require iOS 15 (PostHog/posthog-ios#876) and macOS 11 (PostHog/posthog-ios#906). The plugin's podspec still declares iOS 13 and macOS 10.15, so we need a major version to raise the floor. This PR prepares @posthog/react-native-plugin 3.0.0 and bundles a few low-risk cleanups that are only safe in a major, including removing the legacy start() method.

posthog-ios 4.0 (PostHog/posthog-ios#873) is not released yet, so this PR keeps the posthog-ios pin at 3.88.2. The 4.0 bump is prepared in stacked PRs (below). 3.0 is released only after posthog-ios 4.0 and #5237 are in.

What breaks for users, and what to do

Change Who is affected What to do
Requires iOS 15 Apps on React Native < 0.76 whose iOS deployment target is below 15. RN 0.76+ already raises pods to 15.1. Set the iOS deployment target to 15 or later.
Requires macOS 11 React Native macOS apps whose deployment target is below 11. Over the last 30 days, posthog-ios saw 4 events from macOS 10.15 across PostHog Cloud. Set the macOS deployment target to 11 or later.
Requires React Native 0.71 Apps on RN < 0.71. On iOS the podspec already required RN 0.69+ (min_ios_version_supported); on Android RN 0.70 worked until now. Upgrade React Native.
start() is removed Only code that calls the plugin's start() directly. posthog-react-native calls setup() since 4.47.0, the first release that loads this plugin. Call setup().
iOSdebouncerDelayMs / androidDebouncerDelayMs are no longer read natively Only code that calls the plugin's setup() directly with these keys. posthog-react-native always sends throttleDelayMs (since #2328), and it still maps the deprecated options in JS. Pass throttleDelayMs.

posthog-react-native only gets a type-only change (see below) and does not need a release: every version that loads this plugin already calls setup(). Its optional peer is >= 2.9.3, which includes 3.0.0.

Changes

  • iOS floor: the podspec now states :ios => '15.0' once in s.platforms. Before, s.platforms used min_ios_version_supported, and a later s.ios.deployment_target = '13.0' overrode it. ios/Package.swift already uses .iOS(.v15).
  • macOS floor: the podspec now declares :osx => '11.0', matching posthog-ios 4.0. ios/Package.swift is iOS-only, so it doesn't change.
  • Swift: removed the #available(iOS 14.0, *) and #available(iOS 15.0, *) checks, which are always true on iOS 15.
  • Throttle delay: iOS and Android read only throttleDelayMs.
  • Legacy start(): removed from iOS, Android and JS. In packages/react-native, PostHogReactNativePluginExtended now types start as optional and the legacy session-replay branch calls start?.(...). posthog-react-native-session-replay still has start(), so runtime behaviour is unchanged.
  • RN < 0.71 leftovers:
    • podspec: removed the old-architecture else branch and folly_compiler_flags. install_modules_dependencies now runs unconditionally (available since RN 0.71).
    • Android: namespace is now unconditional (RN 0.71 ships AGP 7.3+). Deleted the legacy AndroidManifest.xml with package=, and renamed AndroidManifestNew.xml to AndroidManifest.xml.
    • Android: the dependency is now com.facebook.react:react-android. The RN Gradle plugin provides the version. Before, it was react-native:+, which relied on substitution.
    • Android: removed the unused reactNativeArchitectures() function and the unused ndkversion property.
    • package.json: the react-native peer is now >=0.71, and the missing cpp entry is removed from files.

Why React Native 0.71

  • posthog-react-native's current release doesn't bundle on RN ≤ 0.71 without workarounds: older Metro ignores package exports, so @posthog/core/surveys can't be resolved. Only apps on an older posthog-react-native that upgrade this plugin are affected.
  • iOS already required RN 0.69+ through min_ios_version_supported in the podspec, so the iOS floor only moves from 0.69 to 0.71.
  • 3.0 is a major for iOS 15 anyway, so it's the cheapest point to set a floor.
  • It removes the pre-0.71 fallbacks (CocoaPods else branch, react-native:+, AGP < 7.3 namespace switch), which no current SDK user can reach.

Verified: an RN 0.70.15 Android app builds and runs with plugin 2.12.4 (events and replay received). The same app fails to build with this branch (Could not find com.facebook.react:react-android). RN 0.71.19 builds with this branch. On iOS, a fresh RN 0.71.19 app with this plugin (CocoaPods, deployment target 15) builds and launches on Xcode 26.4.1, after three React Native patches the app needs anyway on current tooling: gem 'json', '< 3' in the Gemfile, ERB.new(..., trim_mode:) for Ruby 4, and operator""_pt in Yoga's YGValue.h. None come from the plugin.

Considered and left out

Item Why
Push-config "set only when present" (iOS/Android) Still needed. Older posthog-react-native versions call setup() without push config, and native defaults must apply then.
s.swift_versions = "5.3" Already matches posthog-ios's podspec (including 4.0) and the .v5 language mode in Package.swift. Changing it gains nothing.
kotlinOptions → compilerOptions Not a drop-in. Task-level compilerOptions needs KGP 1.8+ and a JvmTarget value, and RN 0.71/0.72 apps use Kotlin 1.7.
Conditional apply plugin: "com.facebook.react" This is the new-architecture hook, not an RN < 0.71 leftover. It belongs with the TurboModule migration.

Stacked PRs (merge into this one)

PR What When
#5226 CocoaPods CI lanes on Xcode 26 Now
#5236 Drop the deprecated screenshotMode Any time before release. On 3.88.2 iOS replay falls back to wireframe, so this branch can't release without #5237
#5238 Leave out posthog-ios's Surveys trait (stacked on #5237) Optional, only if the traits ship in 4.0
#5237 Require posthog-ios 4.0 (Xcode 26) Last, once 4.0 is published. CI fails until then

Docs: PostHog/posthog.com#20922 (draft) documents the 3.0 requirements and upgrade notes. Merge it when 3.0.0 is released.

Release blocker: posthog-ios 4.0 must reach CocoaPods trunk before it goes read-only on 2 Dec 2026, or the default CocoaPods path can't resolve it.

Follow-ups (not in this PR)

Release info Sub-libraries affected

Libraries affected

  • All of them
  • posthog-js (web)
  • posthog-js-lite (web lite)
  • posthog-node
  • posthog-react-native
  • @posthog/react-native-plugin
  • @posthog/react
  • @posthog/ai
  • @posthog/convex
  • @posthog/next
  • @posthog/nextjs-config
  • @posthog/nuxt
  • @posthog/openfeature-node-provider
  • @posthog/openfeature-web-provider
  • @posthog/rollup-plugin
  • @posthog/webpack-plugin
  • @posthog/types
  • @posthog/browser-common

Checklist

  • Tests for new code (no new behavior; existing plugin JS and Kotlin tests pass)
  • Accounted for the impact of any changes across different platforms
  • Accounted for backwards compatibility of any changes (no breaking changes!) (intentional major; see table above)
  • Took care not to unnecessarily increase the bundle size

If releasing new changes

  • Ran pnpm changeset to generate a changeset file. npx changeset status shows only @posthog/react-native-plugin 3.0.0 (major).

🤖 Agent context

Autonomy: Human-driven (agent-assisted)

Prepared with Claude Code from a maintainer-defined scope. Before each removal, the agent checked the git history. Core started loading this plugin in #3677 and checks setup before start, and throttleDelayMs (#2328) predates that. Items it could not prove safe were left out, as listed above. Removing start() needed a type-only edit in packages/react-native, included here.

Checks run locally:

  • plugin pnpm lint, pnpm typecheck, pnpm test:unit (vitest 11/11 and check-spm-manifest.mjs)
  • pnpm turbo run check-types --filter=posthog-react-native, and the posthog-react-native unit tests (1224/1224)
  • examples/example-rn-native-plugin (RN 0.79.6):
    • Android ./gradlew assembleDebug :posthog_react-native-plugin:testDebugUnitTest (17/17; re-run after removing start())
    • iOS pod install + xcodebuild simulator Debug build
    • macOS pod install + xcodebuild

Not tested: the SPM paths and an iOS build after removing start(). Package.swift did not change. No manual device testing.

🤖 Generated with Claude Code

@turnipdabeets turnipdabeets self-assigned this Oct 2, 2026
@greptile-apps

greptile-apps Bot commented Oct 2, 2026 •

Copy link
Copy Markdown
Contributor

Retrigger

[High risk] Breaking changes to React Native plugin API and platform requirements.

The PR appears safe to merge; no outstanding blocking finding was identified.

Reviews (2) · Last reviewed commit: "chore(react-native-plugin)!: require mac..."

@github-actions

github-actions Bot commented Oct 2, 2026 •

Copy link
Copy Markdown
Contributor

Node SDK acceptance v2

Commit: c81d985
Workflow run and artifacts

Capture v0

✅ 83 passed / ❌ 4 non-passing / ⚠️ 954 not selected

Drill-down: run artifacts → node-v2-v0 → acceptance/report.json.diagnostics.json (match case_id below).

❌ server_snapshot_payload_false — failed_assertion

Expected native data result

Code: snapshot_result

Failed step: acceptance/public/evaluate-flags.feature:868

the public snapshot outcomes should have these semantics:
❌ server_snapshot_payload_zero — failed_assertion

Expected native data result

Code: snapshot_result

Failed step: acceptance/public/evaluate-flags.feature:868

the public snapshot outcomes should have these semantics:
❌ server_snapshot_payload_null — failed_assertion

Expected native data result

Code: snapshot_result

Failed step: acceptance/public/evaluate-flags.feature:868

the public snapshot outcomes should have these semantics:
❌ migration/yaml-parity-v1/remote-flags-v1.feature::Omitted GeoIP settings default to enabled in flag requests — failed_assertion

Flags field differs

Code: flag_request_field

Failed step: migration/yaml-parity-v1/remote-flags-v1.feature:134

the first flags request field "geoip_disable" should equal JSON false

Operation: /flags/

Field: geoip_disable

Expected:

false

Actual value:

true

Harness exit: 1; report validation exit: 1.

Capture v1

✅ 148 passed / ❌ 4 non-passing / ⚠️ 889 not selected

Drill-down: run artifacts → node-v2-v1 → acceptance/report.json.diagnostics.json (match case_id below).

❌ server_snapshot_payload_false — failed_assertion

Expected native data result

Code: snapshot_result

Failed step: acceptance/public/evaluate-flags.feature:868

the public snapshot outcomes should have these semantics:
❌ server_snapshot_payload_zero — failed_assertion

Expected native data result

Code: snapshot_result

Failed step: acceptance/public/evaluate-flags.feature:868

the public snapshot outcomes should have these semantics:
❌ server_snapshot_payload_null — failed_assertion

Expected native data result

Code: snapshot_result

Failed step: acceptance/public/evaluate-flags.feature:868

the public snapshot outcomes should have these semantics:
❌ migration/yaml-parity-v1/remote-flags-v1.feature::Omitted GeoIP settings default to enabled in flag requests — failed_assertion

Flags field differs

Code: flag_request_field

Failed step: migration/yaml-parity-v1/remote-flags-v1.feature:134

the first flags request field "geoip_disable" should equal JSON false

Operation: /flags/

Field: geoip_disable

Expected:

false

Actual value:

true

Harness exit: 1; report validation exit: 1.

@turnipdabeets turnipdabeets changed the title chore(react-native-plugin)!: require iOS 15 and React Native 0.71 chore(react-native-plugin)!: require iOS 15 and React Native 0.71, remove start() Oct 5, 2026
@turnipdabeets turnipdabeets changed the title chore(react-native-plugin)!: require iOS 15 and React Native 0.71, remove start() chore(react-native-plugin)!: require iOS 15, macOS 11 and React Native 0.71, remove start() Oct 5, 2026
@turnipdabeets
turnipdabeets marked this pull request as ready for review October 5, 2026 23:40
@turnipdabeets
turnipdabeets requested a review from a team as a code owner October 5, 2026 23:40

@dustinbyrne dustinbyrne left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

any default configs worth changing? additional features we can turn on by default that are currently opt-in?

or perhaps this is not relevant to this package?

@turnipdabeets

turnipdabeets commented Oct 6, 2026 •

Copy link
Copy Markdown
Contributor Author

@dustinbyrne Good question! I went through it and there's nothing to change in this package. The plugin is a bridge: posthog-react-native sends explicit values for replay, error tracking and push, so the plugin's own fallbacks only matter for old posthog-react-native versions or direct setup() callers. Flipping one here would only silently change behaviour for apps that upgrade the plugin without upgrading the SDK. The hardcoded falses (lifecycle, screen views, surveys, persistOptOut) are deliberate, since JS owns those features.

Turning opt-in features like native crash autocapture on by default would be a PostHogOptions change in posthog-react-native, so it belongs in that package's next major, not here.

@turnipdabeets
turnipdabeets requested review from a team and dustinbyrne October 6, 2026 19:59
@github-actions

Copy link
Copy Markdown
Contributor

This PR hasn't seen activity in a week! Should it be merged, closed, or further worked on? If you want to keep it open, post a comment or remove the stale label – otherwise this will be closed in another week.

@github-actions

github-actions Bot commented Oct 20, 2026 •

Copy link
Copy Markdown
Contributor

Coherence

📄 0 spec file errors · ⛔ 0 broken rules · 🚪 2 unchecked inputs · 🐛 0 bugs that came back

What is Coherence?

Coherence compares the code with its spec files (*.spec.md). A spec file lists the rules for one part of the code.

This check read 44 parts of the code and 7 rules.

Note

These findings do not make this check fail.

None of these findings are in files that this pull request changes. You do not need to fix them in this pull request.

🚪 Unchecked inputs (2)

  • public api in packages/web/Web.spec.md. The input comes from: host-app.
  • webpack plugin in packages/webpack-plugin/Webpack-plugin.spec.md. The input comes from: build.
What this means and how to fix it

Input from outside this code comes in at these places. The spec does not say what checks that input. 10 more places were already like this when Coherence was added. This list does not show them.

To close one of these, find the place by its name in the ## entrances section of its spec file. Add one line under it:

  • If all of the input goes through one function that a rule in the spec protects, add guard: <function>.
  • If a rule in the spec already checks input from the same source, add the place's name to the entrances: line of that rule.
  • If the input needs no check, add control: none - <reason>.

To get the line to add, run npx --no -- coherence scaffold control "<name>".

@marandaneto

Copy link
Copy Markdown
Member

keep PRs like this in draft until its ready to go so its out of our review list

turnipdabeets and others added 10 commits October 30, 2026 22:02
…move start()

- podspec: state the iOS 15.0 floor once in s.platforms (was overridden to
  13.0 by s.ios.deployment_target); drop the pre-0.71 old-architecture branch
  and folly flags; call install_modules_dependencies unconditionally
- Swift: drop #available(iOS 14/15) checks that are always true on iOS 15
- iOS/Android: read only throttleDelayMs; drop the iOSdebouncerDelayMs and
  androidDebouncerDelayMs fallbacks (posthog-react-native always sends
  throttleDelayMs since #2328)
- Android: unconditional namespace (AGP >= 7.3 ships with RN 0.71), delete
  the package= manifest, depend on react-android, drop unused
  reactNativeArchitectures() and ndkversion property
- package.json: peer react-native >=0.71; drop missing cpp/ from files
- remove the legacy start() method on iOS, Android and JS; posthog-react-native
  calls setup() since it first loaded this plugin (4.47.0), and only types
  start as optional for the legacy session-replay package

BREAKING CHANGE: requires iOS 15 and React Native 0.71 or later; start() is removed.
posthog-ios 4.0 raises its macOS minimum to 11 (PostHog/posthog-ios#906).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…m, accept projectToken on Android (#5214)

* refactor(react-native-plugin): drop unused setupNativeSdk method param and projectToken key

Both were left over from removing start(); the JS layer only calls setup and only sends apiKey.

* refactor(react-native-plugin): accept projectToken on both platforms

Keeps the iOS fallback and adds it on Android, so a future RN SDK can send projectToken.
* chore(react-native-plugin)!: require posthog-ios 4.0 and leave out its Surveys trait

The plugin disables native surveys (React Native surveys are rendered in JS),
so its Swift package depends on posthog-ios with only the SessionReplay and
CrashReporting traits. The manifest moves to tools 6.2, which posthog-ios 4.0
requires anyway and which package traits need.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* ci(react-native-plugin): build CocoaPods lanes on Xcode 26

* chore(react-native-plugin): move the posthog-ios 4.0 pin to #5237

posthog-ios 4.0 isn't released yet; this PR keeps only the Xcode 26 CI lanes.

---------

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…5236)

* chore(react-native-plugin): drop screenshotMode for posthog-ios 4.0

posthog-ios 4.0 always records screenshots, so the setting is a deprecated no-op.

* chore(react-native-plugin): add changeset for dropping screenshotMode

* chore(react-native-plugin): shorten screenshotMode changeset
…e Manager (#5449)

* chore(react-native-plugin)!: resolve posthog-ios through Swift Package Manager

posthog-ios 4.0 ships on Swift Package Manager only, so the podspec always
adds posthog-ios with React Native's spm_dependency helper instead of
depending on the PostHog pod from CocoaPods trunk. That helper needs
react-native / react-native-macos 0.75, so the peer floor moves from 0.71.

Also stop setting screenshotModeBackgroundCapture, which posthog-ios 4.0
removes, and turn the posthog.useSpm CI lane into a dynamic-frameworks lane.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(react-native-plugin): explain that generate_multiple_pod_projects isn't supported

React Native's spm_dependency only searches the main Pods project for the plugin's target, so pod install crashed with that option on.

* fix(react-native-plugin): explain that deduplicate_targets => false isn't supported

With target deduplication off, CocoaPods names the plugin's target posthog-react-native-plugin-Pods-<App>, and React Native's spm_dependency looks it up by its exact pod name, so pod install crashed on a nil target.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(react-native-plugin): don't reload the app's Podfile from the podspec

Autolinking evaluates the podspec while the Podfile is still loading, so Pod::Config#podfile loaded the Podfile again from the plugin directory, re-running use_native_modules! and its CLI config command. Read the already-loaded Podfile instead; pod install re-evaluates the :path podspec afterwards, so the install! option checks still run.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(react-native-plugin): explain that app targets with different platforms or linkage aren't supported

CocoaPods then splits the plugin into scoped targets (posthog-react-native-plugin-iOS15.1, -framework/-library), and React Native's spm_dependency crashed on a nil target looking up the exact pod name.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(react-native-plugin): count abstract targets when checking for scoped pods

An abstract parent with a platform gets its own plugin variant, so a different linkage there splits the target too.

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants