Skip to content

feat(events): attribute checkout_session events to originating paywall#880

Open
JZDesign wants to merge 9 commits into
mainfrom
jzdesign/paywall-context-checkout-events
Open

feat(events): attribute checkout_session events to originating paywall#880
JZDesign wants to merge 9 commits into
mainfrom
jzdesign/paywall-context-checkout-events

Conversation

@JZDesign

@JZDesign JZDesign commented May 13, 2026

Copy link
Copy Markdown
Contributor

Summary

Backend analytics couldn't tie successful purchases to the paywall that initiated them — checkout_session_end carried only mode, outcome, and with_redemption_info, no paywall identifiers. This PR threads paywall_session_id, paywall_id, and offering_id onto all four checkout_session_* events (start, finished, closed, errored) so purchases, drop-offs, and errors can all be attributed to their originating paywall.

  • Adds the three fields to the four CheckoutSession*Event interfaces (factored into a shared PaywallContext type) and the matching event helpers in src/behavioural-events/
  • Extends internal PurchaseParams with paywallSessionId?: string and offeringId?: string (alongside the existing paywallId?: string, all @internal)
  • Updates presentPaywall's internal startPurchaseFlow to forward its already-generated paywallSessionId UUID and offering.identifier into purchase()
  • Plumbs the context through performStripePurchase / performWebBillingPurchase / performPaddlePurchase and the three private createCheckoutOn{Close,Finished,Error}Handler factories
  • Non-paywall callers (direct purchase({rcPackage}), presentExpressPurchaseButton) correctly emit null for the three fields

Test Plan

  • New unit test: direct purchase({ rcPackage, paywallId, paywallSessionId, offeringId }) call asserts wire payload of checkout_session_end includes all three IDs (src/tests/purchase.events.test.ts)
  • New integration test: presentPaywall forwards paywallSessionId (UUID-shaped) and offering.identifier into the spied purchase() call (src/tests/present-paywall.events.test.ts)
  • Existing 5 assertions in purchase.events.test.ts updated to expect paywall_session_id: null, paywall_id: null, offering_id: null for non-paywall flows
  • Full suite: 593 tests pass
  • pnpm typecheck, pnpm lint, pnpm build clean
  • git diff origin/main -- api-report/ empty (no public API drift — new PurchaseParams fields are @internal)

Follow-ups (out of scope)

  • Add tests asserting paywall context also propagates through closed and errored checkout_session_end events when paywall context is supplied (production code is correct; just untested under the cancel/error paths)
  • Update the success-page events (checkout_purchase_successful_impression / _dismiss in src/ui/pages/success-page.svelte) to carry the same paywall context — requires extra Svelte context plumbing and was deliberately scoped out

🤖 Generated with Claude Code

Summary by CodeRabbit

Release Notes

  • New Features
    • Enhanced checkout event tracking with paywall session, paywall, and offering identifiers to improve purchase attribution and analytics correlation.

Review Change Stack

@coderabbitai

coderabbitai Bot commented May 13, 2026

Copy link
Copy Markdown

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: c73e7955-cc77-4fbb-b91c-2c25b2235bc1

📥 Commits

Reviewing files that changed from the base of the PR and between ebd3eaf and 9f9c569.

📒 Files selected for processing (7)
  • src/behavioural-events/sdk-event-helpers.ts
  • src/behavioural-events/sdk-events.ts
  • src/entities/purchase-params.ts
  • src/main.ts
  • src/tests/main.test.ts
  • src/tests/present-paywall.events.test.ts
  • src/tests/purchase.events.test.ts

📝 Walkthrough

Walkthrough

This PR extends checkout session events with paywall context identifiers (session ID, paywall ID, offering ID) and threads them through all three checkout provider implementations (Stripe, Web Billing, Paddle) while validating the propagation in tests.

Changes

Paywall Context Event Tracking

Layer / File(s) Summary
Event type contracts and PaywallContext definition
src/behavioural-events/sdk-events.ts
Introduces exported PaywallContext type with nullable identifiers, then extends CheckoutSessionStartEvent, CheckoutSessionFinishedEvent, CheckoutSessionClosedEvent, and CheckoutSessionErroredEvent properties to include PaywallContext via type intersection.
Event helper function implementation
src/behavioural-events/sdk-event-helpers.ts
Updates four event creation helpers (createCheckoutSessionStartEvent, createCheckoutSessionEndFinishedEvent, createCheckoutSessionEndClosedEvent, createCheckoutSessionEndErroredEvent) to accept optional paywallSessionId, paywallId, and offeringId parameters and include them in returned event properties.
Purchase parameters data contract
src/entities/purchase-params.ts
Extends PurchaseParams interface with optional paywallSessionId and offeringId fields to carry paywall context from presentation layer through purchase flow.
Paywall context wiring through checkout flows
src/main.ts
Imports PaywallContext type; updates presentPaywall to forward paywall identifiers into purchase(); extends performStripePurchase, performWebBillingPurchase, and performPaddlePurchase to destructure paywall fields from PurchaseParams, build paywallContext objects, and inject them into checkout start/close/finish/error events via updated handler factories.
Test validation of paywall context
src/tests/main.test.ts, src/tests/present-paywall.events.test.ts, src/tests/purchase.events.test.ts
Updates existing event assertions to expect paywall_session_id, paywall_id, and offering_id fields (null by default); adds test verifying presentPaywall calls purchase() with UUID-formatted paywallSessionId and offering/paywall IDs; adds test validating checkout end events include paywall context when purchase is called with those parameters.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 The paywall hops through checkout's door,
With session IDs it did adore,
Through Stripe and Paddle, Web Billing too,
Context flows—analytics shine anew!
Events enriched, the metrics true.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically describes the main change: adding paywall attribution to checkout_session events, which is the core objective of the PR.
Description check ✅ Passed The description is comprehensive, covering motivation, detailed changes, test plan, and follow-ups. It aligns well with the template and provides sufficient context for understanding the changes.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch jzdesign/paywall-context-checkout-events

Comment @coderabbitai help to get the list of available commands and usage tips.

@RevenueCat-Danger-Bot

Copy link
Copy Markdown
1 Error
🚫 Label the PR using one of the change type labels. If you are not sure which label to use, choose pr:other.
Label Description
pr:feat A new feature. Use along with pr:breaking to force a major release.
pr:fix A bug fix. Use along with pr:force_minor to force a minor release.
pr:other Other changes. Catch-all for anything that doesn't fit the above categories. Releases that only contain this label will not be released. Use along with pr:force_patch, or pr:force_minor to force a patch or minor release.
pr:RevenueCatUI Use along any other tag to mark a PR that only contains RevenueCatUI changes
pr:next_release Preparing a new release
pr:dependencies Updating a dependency
pr:phc_dependencies Updating purchases-hybrid-common dependency
pr:changelog_ignore The PR will not be included in the changelog. This label doesn't determine the type of bump of the version and must be combined with pr:feat, pr:fix or pr:other.

Generated by 🚫 Danger

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants