Skip to content

Track marketing notification opens - #6067

Merged
peachbits merged 1 commit into
developfrom
matthew/marketing-push-tracking
Aug 28, 2026
Merged

Track marketing notification opens#6067
peachbits merged 1 commit into
developfrom
matthew/marketing-push-tracking

Conversation

@peachbits

@peachbits peachbits commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

CHANGELOG

Does this branch warrant an entry to the CHANGELOG?

  • Yes
  • No

Dependencies

none

Requirements

If you have made any visual changes to the GUI. Make sure you have:

  • Tested on iOS device
  • Tested on Android device
  • Tested on small-screen device (iPod Touch)
  • Tested on large-screen device (tablet)

No visual changes — this is push-payload parsing plus navigation/analytics, no new UI.

Description

Recognizes a marketing push notification and, when the user opens the app from it, reports the campaign open to analytics and navigates to an optional deep link.

  • parsePushMessage now recognizes a { type: 'marketing', campaignId, url? } FCM data payload and returns a new MarketingLink deep-link type. An unrecognized or malformed url degrades to track-only.
  • On open (background tap or cold start), the deep-link handler dispatches a Marketing_Notification_Opened PostHog event carrying the campaignId, then navigates to the optional deep link through the existing handler.
  • Adds a PushMessageParser unit test.

Verified with the unit test and end-to-end on a real Android device against a local push server: the open was tracked in PostHog and the deep link navigated.

The sending side lives in edge-push-server (companion PR EdgeApp/edge-push-server#78). This PR is the receiving side and is safe to merge on its own — it only acts on notifications that carry the marketing payload.


Note

Medium Risk
Push URLs can drive navigation for all campaign recipients; the allow-list mitigates operator error or compromised send keys, but expanding destinations or parser gaps could still route users to sensitive flows.

Overview
Marketing push notifications (type: marketing with campaignId and optional url) are now recognized when the user opens the app from the notification.

parsePushMessage returns a new MarketingLink deep-link type. Optional URLs are parsed through the existing deep-link parser; only allow-listed campaign destinations (home, wallets, earn, markets, swap, buy/sell quotes, promotions, fund-account modal) trigger navigation—sensitive or unlisted targets (recovery, edge-login, arbitrary scenes, provider returns) are track-only. Wrapped deep.edge.app URLs are judged by their inner destination; malformed URLs still record the open.

On handle, DeepLinkingActions logs Marketing_Notification_Opened to analytics with campaignId, then navigates via the shared link handler when a permitted link was parsed. PushMessageParser.test.ts covers destinations, refusals, attribution wrappers, and existing price-change payloads.

Reviewed by Cursor Bugbot for commit 1cdb570. Bugbot is set up for automated code reviews on this repo. Configure here.


Comment thread src/util/PushMessageParser.ts
@peachbits
peachbits force-pushed the matthew/marketing-push-tracking branch from b4eafc8 to 5d8b895 Compare August 14, 2026 17:40
Comment thread src/util/PushMessageParser.ts Outdated
Comment thread src/util/PushMessageParser.ts Outdated
@peachbits
peachbits force-pushed the matthew/marketing-push-tracking branch from f149ce7 to b8a1392 Compare August 14, 2026 18:56
Comment thread src/util/PushMessageParser.ts Outdated
Comment thread src/util/PushMessageParser.ts Outdated
@peachbits
peachbits force-pushed the matthew/marketing-push-tracking branch from b8a1392 to ff38b7b Compare August 14, 2026 22:15
Comment thread src/util/PushMessageParser.ts Outdated
@peachbits
peachbits force-pushed the matthew/marketing-push-tracking branch from ff38b7b to 83177c4 Compare August 14, 2026 22:34

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

There are 2 total unresolved issues (including 1 from previous review).

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 83177c4. Configure here.

Comment thread src/util/PushMessageParser.ts Outdated
@peachbits
peachbits force-pushed the matthew/marketing-push-tracking branch from 83177c4 to 1cdb570 Compare August 14, 2026 22:46
@peachbits
peachbits force-pushed the matthew/marketing-push-tracking branch 4 times, most recently from a30df05 to c14a73a Compare August 27, 2026 23:39

@j0ntz j0ntz 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.

Minor naming nit, and to ensure QA is able to test this fully

Comment thread src/util/tracking.ts Outdated
| 'Fio_Handle_Bundled_Tx'
| 'Load_Install_Reason_Match'
| 'Load_Install_Reason_Fail'
| 'Marketing_Notification_Opened'

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.

Genericize to Push_Notification_Opened

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done in 9553f1f — renamed to Push_Notification_Opened. Agreed on the reasoning: the event describes a push being opened, so price-change or any future push type can report through the same one instead of accruing an event per category. campaignId stays an optional param since only marketing pushes carry one.

@peachbits
peachbits force-pushed the matthew/marketing-push-tracking branch from c14a73a to e4a6665 Compare August 28, 2026 18:40

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Claude Code Review

Claude Code Review is paused for this repository. To reconnect it, an admin of this repository's GitHub organization (or the account owner, for personal repositories) who can also manage your Claude organization's Code Review settings needs to re-link GitHub in Code Review settings. This is a one-time step.

Tip: disable this comment in your organization's Code Review settings.

The push server attaches a campaignId (and an optional deep link URL) to
every marketing notification. Parse that payload when the user opens the
app from one: report the campaign to analytics, and navigate to the URL.

A campaign link goes wherever its URL points, the same as a link tapped
in a browser or a message. Both reach the app through `parseDeepLink`
and the same handler, so a campaign can send users anywhere the app
already goes - including both the new and legacy fiat ramp spellings -
without a list here to keep in step with the rest of the app. A URL the
parser does not recognize tracks the open without navigating.

Sends are gated behind a marketer API key that is not shipped in the
apps, so a campaign URL is not reachable by an outsider.
@peachbits
peachbits force-pushed the matthew/marketing-push-tracking branch from e4a6665 to 9553f1f Compare August 28, 2026 18:43
@peachbits
peachbits merged commit a94fc6a into develop Aug 28, 2026
6 checks passed
@peachbits
peachbits deleted the matthew/marketing-push-tracking branch August 28, 2026 20:37
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.

2 participants