Skip to content

Use stable PostHog identity for newsletter signups#6588

Open
Alek99 wants to merge 2 commits into
mainfrom
fix-posthog-newsletter-distinct-id
Open

Use stable PostHog identity for newsletter signups#6588
Alek99 wants to merge 2 commits into
mainfrom
fix-posthog-newsletter-distinct-id

Conversation

@Alek99

@Alek99 Alek99 commented May 30, 2026

Copy link
Copy Markdown
Member

Summary

  • stop using email as the PostHog distinct ID for demo/intro form tracking
  • capture newsletter signups in PostHog with email in $set person properties
  • only call posthog.identify when a canonical non-email ID is provided
  • add track_newsletter_posthog_subscription(email, contact_uuid) as the new preferred API for newsletter tracking
  • preserve track_newsletter_posthog_submission(form_data) for backwards compatibility (now uses the improved _capture_posthog_person_event under the hood)

cc @Alek99

Testing

  • uv run ruff format packages/reflex-components-internal/src/reflex_components_internal/blocks/telemetry/posthog.py packages/reflex-components-internal/src/reflex_components_internal/blocks/telemetry/__init__.py packages/reflex-site-shared/src/reflex_site_shared/backend/signup.py
  • uv run ruff check packages/reflex-components-internal/src/reflex_components_internal/blocks/telemetry/posthog.py packages/reflex-components-internal/src/reflex_components_internal/blocks/telemetry/__init__.py packages/reflex-site-shared/src/reflex_site_shared/backend/signup.py
  • uv run --package reflex-site-shared python - <<'PY' ... script assertions for newsletter PostHog payload

@Alek99 Alek99 requested a review from a team as a code owner May 30, 2026 00:10
@codspeed-hq

codspeed-hq Bot commented May 30, 2026

Copy link
Copy Markdown

Merging this PR will not alter performance

✅ 24 untouched benchmarks


Comparing fix-posthog-newsletter-distinct-id (8c4adad) with main (e88acf7)1

Open in CodSpeed

Footnotes

  1. No successful run was found on main (7281317) during the generation of this report, so e88acf7 was used instead as the comparison base. There might be some changes unrelated to this pull request in this report.

@greptile-apps

greptile-apps Bot commented May 30, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR stops using email addresses as PostHog distinct IDs for demo/intro/newsletter form tracking, instead routing PII into $set person properties and only calling posthog.identify when a stable UUID-based canonical ID is present.

  • Introduces _capture_posthog_person_event, a shared JS-injection helper that separates person-property keys from event payload keys, builds personProps, strips canonical-ID fields from the captured event, and calls identify only when a non-email canonical ID (e.g. user_uuid, contact_uuid) is available.
  • Adds track_newsletter_posthog_subscription(email, contact_uuid=None) as the new call site used by signup.py, replacing the generic track_newsletter_posthog_submission which also would have used email as the distinct ID.
  • Moves the PostHog yield ahead of the webhook/Loops yields in signup.py; since all three calls are fire-and-forget this ordering change has no functional effect on the signup flow.

Confidence Score: 5/5

The change is narrowly scoped to PostHog analytics; no core signup logic, auth, or data-storage paths are altered.

The refactoring correctly strips PII from event payloads, the new JS helper handles all edge-case deletions and the identify guard, and the public API change is backward-compatible. No regressions are expected in the signup or form-submission flows.

No files require special attention.

Important Files Changed

Filename Overview
packages/reflex-components-internal/src/reflex_components_internal/blocks/telemetry/posthog.py Adds _capture_posthog_person_event helper that separates PII into $set person properties and derives a stable canonical ID from UUID fields; refactors existing form-tracking to use it; adds track_newsletter_posthog_subscription.
packages/reflex-components-internal/src/reflex_components_internal/blocks/telemetry/init.py Re-exports the new track_newsletter_posthog_subscription function from the public __all__.
packages/reflex-site-shared/src/reflex_site_shared/backend/signup.py Switches newsletter signup tracking to track_newsletter_posthog_subscription and moves the PostHog yield ahead of the webhook/Loops calls.

Reviews (2): Last reviewed commit: "Merge origin/main into fix-posthog-newsl..." | Re-trigger Greptile

Comment on lines +108 to 110
yield track_newsletter_posthog_subscription(email)
yield IndexState.send_contact_to_webhook(email)
yield IndexState.add_contact_to_loops(email)

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.

P2 PostHog fires a newsletter_subscribed event even when email is None. If the user submits the form without an email address, email_to_validate is falsy and the if block is skipped entirely — so email stays None and tracking fires with an empty props object. The resulting event has no identity and no person properties, creating noise in PostHog analytics.

Suggested change
yield track_newsletter_posthog_subscription(email)
yield IndexState.send_contact_to_webhook(email)
yield IndexState.add_contact_to_loops(email)
if email:
yield track_newsletter_posthog_subscription(email)
yield IndexState.send_contact_to_webhook(email)
yield IndexState.add_contact_to_loops(email)

Comment on lines +79 to +84
if (Object.keys(personProps).length > 0) {{
eventProps.$set = personProps;
}}
if (canonicalDistinctId && canonicalDistinctId !== props.email) {{
posthog.identify(String(canonicalDistinctId), personProps);
}}

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.

P2 Double person-property write when canonical ID is present

When canonicalDistinctId is truthy, posthog.identify(canonicalDistinctId, personProps) is called and then posthog.capture(event_name, {..., $set: personProps}) is called immediately after with the same personProps in $set. PostHog merges both writes, so this is harmless in practice, but the $set payload on the capture event is redundant when identify already carries the same data. Removing the $set attachment when canonicalDistinctId is present would eliminate the duplicate write, though this is a minor analytics hygiene concern.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

@masenf

masenf commented Jun 11, 2026

Copy link
Copy Markdown
Collaborator

@copilot resolve the merge conflicts in this pull request

Copilot AI commented Jun 11, 2026

Copy link
Copy Markdown

@copilot resolve the merge conflicts in this pull request

Resolved the merge conflicts in 84e6a63. The two conflicting areas were:

  1. posthog.py: main had added track_newsletter_posthog_submission(form_data) while this PR renamed/redesigned it as track_newsletter_posthog_subscription(email, contact_uuid). Resolved by keeping both — track_newsletter_posthog_subscription as the new preferred API and track_newsletter_posthog_submission for backwards compatibility (it now benefits from the improved _capture_posthog_person_event implementation).

  2. signup.py: kept this PR's version using track_newsletter_posthog_subscription(email) directly, removing the duplicate track_newsletter_posthog_submission call that the auto-merge had inserted.

Copilot AI requested a review from masenf June 11, 2026 21:10
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