Skip to content

docs(push): mobile push open docs for the pending SDK releases - #20114

Draft
turnipdabeets wants to merge 4 commits into
masterfrom
docs/push-open-accuracy-fixes
Draft

docs(push): mobile push open docs for the pending SDK releases#20114
turnipdabeets wants to merge 4 commits into
masterfrom
docs/push-open-accuracy-fixes

Conversation

@turnipdabeets

@turnipdabeets turnipdabeets commented Sep 12, 2026

Copy link
Copy Markdown
Contributor

Changes

Every push notification docs change for this effort, in one PR, written as true after the SDK releases land. This replaces #20102, which is closed.

Draft until the releases are published. posthog.com deploys on merge, so merging early would publish claims about versions nobody can install yet.

Two kinds of change are mixed here on purpose, because they touch the same paragraphs:

  • corrections that are wrong today (the React Native coverage paragraphs, the delegate callout, the missing troubleshooting row, the iOS 14 floor, the stale Flutter native floors),
  • behavior the pending releases add (the open dedupe, the React Native iOS cold launch, the killed-process override, the Flutter pre-setup replay).

What changed, per page

react-native.mdx

Change Depends on
iOS now captures a tap that cold-launches the app, instead of only taps while the app runs. The plugin installs the native hook at launch rather than at setup(). @posthog/react-native-plugin 2.8.2 (#4921)
Automatic capture needs iOS 14 or newer, on all three iOS surfaces of the page. released
Android coverage rewritten: warm-start taps have been captured since plugin 2.6.0 (the page claimed cold start only), and the one remaining gap is the killed-process case. released
New ### Android taps after the process is killed section: the posthog-react-native/expo config plugin writes the MainActivity.onNewIntent override on expo prebuild, patchMainActivityNewIntent: false opts out, and a bare React Native app adds setIntent(intent) before super.onNewIntent(intent) by hand. Snippet taken verbatim from the block the config plugin generates. posthog-react-native 4.72.0 (#4929)
Notification-delegate requirement promoted to a CalloutBox, matching ios.mdx and flutter.mdx. released
"Capturing opens": the onNotificationOpenedApp snippet is gone (following it double-counts every Android tap since 2.6.0), replaced by the plain manual call plus a "don't wire this to onNotificationOpenedApp / getInitialNotification()" warning and the dedupe rule. @posthog/react-native-plugin 2.8.2 (#4919)
"Opting out" rewritten. After #4921, capturePushNotificationOpened: false stops the event but not the launch hook, which is installed before any JavaScript runs and only released at setup(). The section now documents com.posthog.posthog.CAPTURE_PUSH_NOTIFICATION_OPENED = false in Info.plist (Expo: ios.infoPlist) as the way to skip the hook entirely, with a JSON example. @posthog/react-native-plugin 2.8.2 (#4921)
New $push_notification_opened never fires troubleshooting row, which the iOS and Flutter pages already had, covering all three causes above. mixed

android.mdx

Change Depends on
PostHog.capturePushNotificationOpened is no longer described as never deduplicated. A repeat of a PostHog-sent notification captured in the last 5 minutes is skipped, so one tap counts once whichever path reports it. Notifications PostHog didn't send are still never deduplicated. posthog-android 3.65.0 (posthog-android#783)

flutter.mdx

Change Depends on
Same dedupe correction, replacing "the manual call isn't deduplicated against them, so the open is counted twice". Stated as guaranteed on Android (the plugin's floor requires it) and as applying on iOS once the build resolves posthog-ios 3.75.0 – see the caveat below. posthog_flutter 5.41.1 (posthog-flutter#578)
A tap that reaches the app before Posthog().setup() runs is held and captured once setup completes, so coverage no longer depends on the FCM package refreshing the activity's intent. posthog_flutter 5.41.1 (posthog-flutter#579)
Dropped the native-floor prose naming posthog-android 3.62.0, which the plugin no longer declares. Both halves of automatic open capture landed in the Flutter SDK 5.40.0, so the page names that instead. released
Added the iOS 14 floor. released

ios.mdx

Change Depends on
The prewarm troubleshooting row now says the Flutter and React Native plugins do it for you, so a JavaScript host doesn't wire up something it already has. @posthog/react-native-plugin 2.8.2 (#4921)
"Capturing opens" gains the dedupe note: both manual overloads skip a repeat of a PostHog-sent notification captured in the last 5 minutes. posthog-ios 3.75.0 (posthog-ios#828)
Automatic registration and open capture require iOS 14 or newer – getIntegrations() installs both push integrations inside if #available(iOS 14.0, macOS 11.0, *) while the deployment target is iOS 13, so an iOS 13 device silently captures nothing. Added as a requirement and to the "Opens are never captured" row. released

Versions this PR names, and where they come from

Every number below is the next release, derived from the version on main plus the changeset on the PR branch. None is cut yet, so all of them need re-checking on Monday.

Package On main today Named here Why
com.posthog:posthog-android 3.64.0 3.65.0 posthog-android#783 changeset is minor
PostHog (posthog-ios) 3.74.0 3.75.0 posthog-ios#828 changeset is minor
@posthog/react-native-plugin 2.8.1 2.8.2 #4921 and #4919 are both patch
posthog-react-native 4.71.0 4.72.0 #4929 is minor (#4921, #4919 are patch)
posthog_flutter 5.41.0 5.41.1 #578 and #579 are both patch

No other changesets are pending on any of those main branches, so nothing else should move the numbers – unless something merges between now and the releases.

Caveat worth deciding before merge

The React Native plugin cannot resolve posthog-ios 3.75.0. posthog-react-native-plugin.podspec pins PostHog as ~> 3.73.3 (upToNextMinorVersion), which resolves 3.73.x only, and none of #4919, #4921 or #4929 raises it. So after the releases, React Native gets the dedupe on Android (#4919 raises the Android pin to 3.65.0) but not on iOS. react-native.mdx is written to match: Android dedupes, iOS still double-counts a manual call. If #4919 is extended to bump posthog_ios_version to 3.75.0 before it merges, that sentence should be simplified.

Flutter is the softer version of the same thing: posthog_flutter.podspec declares PostHog >= 3.74.0, < 4.0.0, and #578 raises only the Android floor. A fresh pod install resolves 3.75.0 and gets the dedupe, but a Podfile.lock pinned to 3.74.0 does not, which is why flutter.mdx says "once your build resolves posthog-ios 3.75.0 or newer" rather than stating it flatly.

Monday re-verification checklist

Before taking this out of draft:

  • posthog-android 3.65.0 is published on Maven Central and contains posthog-android#783.
  • posthog-ios 3.75.0 is published and contains posthog-ios#828.
  • @posthog/react-native-plugin 2.8.2 is on npm and contains Build fix / GitHub tooltip body update #4921 (iOS launch hook + the Info.plist key) and added link to developing with an enterprise license #4919 (posthog-android pinned to 3.65.0). If the published version is not 2.8.2, update all four mentions on react-native.mdx and the one on ios.mdx.
  • posthog-react-native 4.72.0 is on npm and contains Improve Community dropdown menu #4929. If the published version differs, update the one mention in the "Android taps after the process is killed" section.
  • posthog_flutter 5.41.1 is on pub.dev and contains Add Actions + Custom Events Tutorial #578 and added disclaimer to docker deployment #579. If the published version differs, update the two mentions on flutter.mdx.
  • Decide the podspec question above: if added link to developing with an enterprise license #4919 ended up bumping posthog_ios_version to 3.75.0, rewrite the React Native dedupe sentence to cover iOS too.
  • The Expo config plugin option is still spelled patchMainActivityNewIntent and still defaults to on in the published posthog-react-native.
  • The Info.plist key is still spelled com.posthog.posthog.CAPTURE_PUSH_NOTIFICATION_OPENED in the published plugin.
  • Check the changed pages in the Vercel preview build.

Verification behind the claims

Read against origin/main and the open PR branches of posthog-android, posthog-ios, posthog-js and posthog-flutter, not against the old docs:

  • Dedupe rule (both platforms): PostHog.recordPushOpen in posthog/src/main/java/com/posthog/PostHog.kt and PostHogSDK.recordPushOpen in PostHog/PostHogSDK.swift. Keyed on posthog.invocation_id + action_id, 5 minute window, at most 20 remembered opens, skipped in either direction (manual after automatic and automatic after manual). A payload with no posthog.invocation_id is always captured, which is why every page says notifications PostHog didn't send are never deduplicated.
  • React Native iOS launch hook: PosthogReactNativePlugin.mm registers a UIApplicationDidFinishLaunchingNotification observer at image load, which calls prewarmPushNotificationOpenCapture() unless com.posthog.posthog.CAPTURE_PUSH_NOTIFICATION_OPENED is false, guarded by if #available(iOS 14.0, *).
  • Opting out: PostHogSDK.prewarmPushNotificationOpenCapture()'s own doc says the swizzles are "released again … at setup() when the config disables push-open capture", which is exactly why the JS flag stops the event but not the hook.
  • Killed-process snippet: copied from NEW_INTENT_KOTLIN_BODY in packages/react-native/src/tooling/expoconfig.ts on the Improve Community dropdown menu #4929 branch, so the hand-written override and the generated one are the same code.
  • Flutter pre-setup replay: pendingPushIntent in PosthogFlutterPlugin.kt on the added disclaimer to docker deployment #579 branch remembers a tray tap (an intent carrying google.message_id) and replays it from capturePushNotificationOpenedFromLaunchIntent().
  • iOS 14 floor: PostHogConfig.getIntegrations() installs both push integrations inside if #available(iOS 14.0, macOS 11.0, *).

pnpm vale:staged reports 0 errors. The remaining warnings are the pre-existing APNs / classpath / unregister spelling entries already on these pages.

Checklist

  • I've read the docs and/or content style guides.
  • Words are spelled using American English
  • Use relative URLs for internal links
  • I've checked the pages added or changed in the Vercel preview build
  • If I moved a page, I added a redirect in vercel.json (no pages moved)

Related PRs

One push-open capture effort across the mobile SDKs: count every notification tap exactly once, and stop losing taps the SDK starts too late to see.

PR What it does Blocked by
PostHog/posthog-android#783 Core: capture each PostHog push open once, whichever path reports it (ships as 3.65.0)
PostHog/posthog-ios#828 Same rule on iOS, so both platforms behave identically (ships as 3.75.0)
PostHog/posthog-js#4921 React Native on iOS: capture a tap that launches the app
PostHog/posthog-js#4929 React Native on Android: capture a tap lost when the process was killed but the task stayed in recents
PostHog/posthog-flutter#579 Flutter: replay a tap that arrives before the SDK is set up, instead of relying on firebase_messaging
PostHog/posthog-js#4919 React Native plugin: take the core dedupe, drop the plugin-level copy posthog-android 3.65.0
PostHog/posthog-flutter#578 Flutter plugin: take the core dedupe, drop the plugin-level copy posthog-android 3.65.0
#20114 (this PR) All of the push notification docs for the above every release above

Merge order: posthog-android#783 and posthog-ios#828 first, then their releases. #4921, #4929 and #579 are independent and can go any time. #4919 and #578 go green once posthog-android 3.65.0 is published. This PR merges last, after every release above is out.

Earlier work this builds on: PostHog/posthog-android#753, PostHog/posthog-ios#792, PostHog/posthog-js#4858, PostHog/posthog-flutter#556, PostHog/posthog-flutter#557, #19905.

🤖 Generated with Claude Code

https://claude.ai/code/session_01UJgnRvz58rzgFVCiUfjxkL

- React Native: iOS taps that cold-launch the app are not captured, and
  automatic capture needs iOS 14 or newer
- React Native: Android captures warm-start taps since plugin 2.6.0, except
  when the process was killed with its task still in the recent apps list
- React Native: promote the notification-delegate requirement to a callout, and
  add the missing $push_notification_opened troubleshooting row
- iOS and Flutter: state the iOS 14 floor for the automatic hooks
- Flutter: name the plugin version instead of native floors the plugin no
  longer declares
@github-actions github-actions Bot added docs Improvements or additions to product documentation, "Docs" content PR only touches files under contents/ labels Sep 12, 2026
@github-actions

github-actions Bot commented Sep 12, 2026

Copy link
Copy Markdown
Contributor

Deploy preview

Status Details Updated (UTC)
🟢 Ready View preview Sep 12, 2026 07:30PM

Changed pages

Page Source
Android push notifications contents/docs/workflows/push-notifications/android.mdx
Flutter push notifications contents/docs/workflows/push-notifications/flutter.mdx
iOS push notifications contents/docs/workflows/push-notifications/ios.mdx
React Native push notifications contents/docs/workflows/push-notifications/react-native.mdx

@github-actions

github-actions Bot commented Sep 12, 2026

Copy link
Copy Markdown
Contributor

Vale prose linter → found 0 errors, 32 warnings, 11 suggestions in your markdown

Full report → Copy the linter results into an LLM to batch-fix issues.

Linter being weird? Update the rules!

contents/docs/workflows/push-notifications/android.mdx — 0 errors, 5 warnings, 2 suggestions
Line Severity Message Rule
12:94 suggestion Address the reader directly. Use 'you' instead of 'the user'. PostHogDocs.DirectAddress
16:72 warning 'classpath' is a possible misspelling. PostHogBase.Spelling
48:37 warning 'unregisters' is a possible misspelling. PostHogBase.Spelling
48:127 warning Use 'ID' instead of 'id'. Vale.Terms
50:18 warning 'unregistration' is a possible misspelling. PostHogBase.Spelling
94:66 warning 'classpath' is a possible misspelling. PostHogBase.Spelling
95:102 suggestion Address the reader directly. Use 'you' instead of 'the user'. PostHogDocs.DirectAddress
contents/docs/workflows/push-notifications/flutter.mdx — 0 errors, 8 warnings, 3 suggestions
Line Severity Message Rule
12:118 suggestion Address the reader directly. Use 'you' instead of 'the user'. PostHogDocs.DirectAddress
26:110 warning 'APNs' is a possible misspelling. PostHogBase.Spelling
26:254 warning 'classpath' is a possible misspelling. PostHogBase.Spelling
26:334 suggestion Address the reader directly. Use 'you' instead of 'the user'. PostHogDocs.DirectAddress
54:9 warning Capitalize 'Logs' for PostHog's product. Use 'logs' for the general industry concept. PostHogBase.ProductNames
78:1 warning 'Unregister' is a possible misspelling. PostHogBase.Spelling
86:18 warning 'unregistration' is a possible misspelling. PostHogBase.Spelling
127:66 suggestion Address the reader directly. Use 'you' instead of 'the user'. PostHogDocs.DirectAddress
127:159 warning 'classpath' is a possible misspelling. PostHogBase.Spelling
128:77 warning 'APNs' is a possible misspelling. PostHogBase.Spelling
128:105 warning Use 'ID' instead of 'id'. Vale.Terms
contents/docs/workflows/push-notifications/ios.mdx — 0 errors, 10 warnings, 3 suggestions
Line Severity Message Rule
12:192 suggestion Address the reader directly. Use 'you' instead of 'the user'. PostHogDocs.DirectAddress
13:28 warning 'APNs' is a possible misspelling. PostHogBase.Spelling
13:79 warning 'APNs' is a possible misspelling. PostHogBase.Spelling
13:98 warning Use 'ID' instead of 'id'. Vale.Terms
28:199 suggestion Address the reader directly. Use 'you' instead of 'the user'. PostHogDocs.DirectAddress
52:9 warning Capitalize 'Logs' for PostHog's product. Use 'logs' for the general industry concept. PostHogBase.ProductNames
72:1 warning 'Unregister' is a possible misspelling. PostHogBase.Spelling
78:52 warning 'unregisters' is a possible misspelling. PostHogBase.Spelling
78:142 warning Use 'ID' instead of 'id'. Vale.Terms
80:18 warning 'unregistration' is a possible misspelling. PostHogBase.Spelling
120:83 suggestion Address the reader directly. Use 'you' instead of 'the user'. PostHogDocs.DirectAddress
121:47 warning 'APNs' is a possible misspelling. PostHogBase.Spelling
121:120 warning Use 'ID' instead of 'id'. Vale.Terms
contents/docs/workflows/push-notifications/react-native.mdx — 0 errors, 9 warnings, 3 suggestions
Line Severity Message Rule
12:132 suggestion Address the reader directly. Use 'you' instead of 'the user'. PostHogDocs.DirectAddress
32:110 warning 'APNs' is a possible misspelling. PostHogBase.Spelling
32:252 warning 'classpath' is a possible misspelling. PostHogBase.Spelling
32:382 suggestion Address the reader directly. Use 'you' instead of 'the user'. PostHogDocs.DirectAddress
96:54 warning 'APNs' is a possible misspelling. PostHogBase.Spelling
96:83 warning Use 'ID' instead of 'id'. Vale.Terms
98:1 warning 'Unregister' is a possible misspelling. PostHogBase.Spelling
106:18 warning 'unregistration' is a possible misspelling. PostHogBase.Spelling
167:112 suggestion Address the reader directly. Use 'you' instead of 'the user'. PostHogDocs.DirectAddress
167:203 warning 'classpath' is a possible misspelling. PostHogBase.Spelling
168:77 warning 'APNs' is a possible misspelling. PostHogBase.Spelling
168:105 warning Use 'ID' instead of 'id'. Vale.Terms

@github-actions

Copy link
Copy Markdown
Contributor

Bundle report

Total JS (gzip)

8.78 MiB (+0.4 KiB / +0.0%)

Eager graph (modules shipped in each entrypoint's initial chunks)

Entrypoint Eager size Budget Modules
app 18.52 MiB (+3.2 KiB / +0.0%) report-only 2062
Largest modules in the app closure
Module Size
./src/data/mcp-tools.json 1131.9 KiB
css ./node_modules/.pnpm/css-loader@5.2.7_webpack@5.101.3/node_modules/css-loader/dist/cjs.js??ruleSet[1].rules[8].oneOf[1].use[1]!./node_modules/.pnpm/postcss-loader@4.3.0_postcss@8.5.6_webpack@5.101.3/node_modules/postcss-loader/dist/cjs.js??ruleSet[1].rules[8].oneOf[1].use[2]!./src/styles/global.css 773.9 KiB
./src/components/Stickers/Stickers.tsx 696.4 KiB
./node_modules/.pnpm/@radix-ui+react-icons@1.3.2_react@18.3.1/node_modules/@radix-ui/react-icons/dist/react-icons.esm.js 481.4 KiB
./node_modules/.pnpm/@posthog+brand@0.8.0_react@18.3.1/node_modules/@posthog/brand/dist/generated/hoggies/svg/x-ray.mjs 480.8 KiB
./node_modules/.pnpm/rehype-raw@7.0.0/node_modules/rehype-raw/lib/index.js + 29 modules 395.1 KiB
./node_modules/.pnpm/@posthog+brand@0.8.0_react@18.3.1/node_modules/@posthog/brand/dist/generated/hoggies/svg/im-the-driver.mjs 385.7 KiB
./src/hooks/useCustomers.tsx + 55 modules 370.0 KiB
./node_modules/.pnpm/@posthog+icons@0.36.6_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@posthog/icons/dist/posthog-icons.es.js 354.8 KiB
./node_modules/.pnpm/react-markdown@8.0.7_@types+react@16.14.66_react@18.3.1/node_modules/react-markdown/lib/react-markdown.js + 88 modules 351.4 KiB
./src/components/ProductComparisonTable/index.tsx + 126 modules 305.7 KiB
./node_modules/.pnpm/cloudinary-core@2.14.0_lodash@4.17.21/node_modules/cloudinary-core/cloudinary-core.js 281.9 KiB
./node_modules/.pnpm/@posthog+brand@0.8.0_react@18.3.1/node_modules/@posthog/brand/dist/generated/hoggies/svg/doll-house.mjs 281.7 KiB
./node_modules/.pnpm/@posthog+brand@0.8.0_react@18.3.1/node_modules/@posthog/brand/dist/generated/hoggies/svg/director.mjs 275.6 KiB
./src/components/SearchUI/index.tsx + 87 modules 273.7 KiB

Eager-graph budgets are report-only until a baseline is established. Sizes are gzip of public/**/*.js; eager size is webpack module source bytes for the modules actually shipped in the entrypoint's initial chunks (post-tree-shake).

- Android, Flutter, iOS: a repeat of a PostHog-sent notification captured in
  the last 5 minutes is skipped, so one tap counts once
- React Native: iOS captures a tap that cold-launches the app, and
  capturePushNotificationOpened: false no longer stops that launch hook -
  document the Info.plist key that does
- React Native: document the MainActivity onNewIntent override for taps that
  arrive after the process was killed, via the Expo config plugin or by hand
- React Native: replace the manual open guidance with the dedupe rule
- Flutter: a tap that lands before setup() is replayed once setup completes
- iOS: the React Native plugin now prewarms open capture too
@turnipdabeets turnipdabeets changed the title docs(push): correct push open claims that are wrong today docs(push): mobile push open docs for the pending SDK releases Sep 12, 2026
@turnipdabeets
turnipdabeets marked this pull request as draft September 12, 2026 16:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

content PR only touches files under contents/ docs Improvements or additions to product documentation, "Docs"

Projects

Status: Backlog

Development

Successfully merging this pull request may close these issues.

1 participant