Skip to content

feat: add event sending#448

Merged
yusuftor merged 14 commits intodevelopfrom
christo/onboarding-analytics
Mar 16, 2026
Merged

feat: add event sending#448
yusuftor merged 14 commits intodevelopfrom
christo/onboarding-analytics

Conversation

@chroxify
Copy link
Contributor

@chroxify chroxify commented Mar 6, 2026

Changes in this pull request

  • Adds multipage paywall navigation tracking by tracking a paywall_page_view event, which contains information about the page view.

Checklist

  • All unit tests pass.
  • All UI tests pass.
  • Demo project builds and runs on iOS.
  • Demo project builds and runs on Mac Catalyst.
  • Demo project builds and runs on visionOS.
  • I added/updated tests or detailed why my change isn't tested.
  • I added an entry to the CHANGELOG.md for any breaking changes, enhancements, or bug fixes.
  • I have run swiftlint in the main directory and fixed any issues.
  • I have updated the SDK documentation as well as the online docs.
  • I have reviewed the contributing guide

Greptile Summary

This PR adds multi-page paywall navigation tracking by introducing a paywall_page_view event. It wires a new page_view WebView message through the existing PaywallMessagePaywallMessageHandlerInternalSuperwallEventSuperwallEvent pipeline, and introduces a presentationId (UUID assigned once per network fetch) that is threaded through all paywall lifecycle events to allow analytics consumers to correlate every event within a single presentation.

Key changes:

  • New PageViewData public struct carries page-specific context (pageNodeId, flowPosition, pageName, navigationNodeId, navigationType, optional previous-page fields)
  • New SuperwallEvent.paywallPageView(paywallInfo:data:) case and matching ObjC enum value paywallPageView
  • presentationId: String? added to both Paywall (client-side var, not in CodingKeys) and PaywallInfo (public let), assigned via UUID().uuidString in getRawPaywall and propagated through Paywall.update(from:) for cached VC re-use scenarios
  • Version bumped to 4.14.2 across Constants.swift, podspec, and CHANGELOG.md
  • Two new test files with thorough coverage of decoding, event parameters, and full presentation lifecycle scenarios
  • Minor unrelated fix in WebEntitlementRedeemerTests: captures a baseline call count before the operation rather than resetting it, and extends the settlement sleep to 200 ms

Confidence Score: 4/5

  • PR is safe to merge; only style-level concerns remain
  • The implementation is well-structured and follows existing patterns. The presentationId lifecycle (set at fetch, propagated through update(from:), excluded from CodingKeys) is correct. The PageViewData decoding correctly uses the top-level decoder with JSONDecoder.fromSnakeCase. The only notable concern is the type property name in PageViewData diverging from its analytics key "navigation_type", and the WebEntitlementRedeemerTests timing fix being pragmatic rather than structurally sound. Neither is a blocker.
  • PageViewData.swift — type property naming vs. analytics key inconsistency

Important Files Changed

Filename Overview
Sources/SuperwallKit/Paywall/View Controller/Web View/Message Handling/PageViewData.swift New public struct for page-view data. Correct use of synthesized Decodable with convertFromSnakeCase. Minor naming concern: type property is semantically the navigation type but named generically.
Sources/SuperwallKit/Paywall/View Controller/Web View/Message Handling/PaywallMessage.swift Adds pageView(PageViewData) case. Decoding uses try? PageViewData(from: decoder) (top-level decoder) instead of the keyed container values — correct because all page-view fields are at the root JSON level and JSONDecoder.fromSnakeCase is used in production. Follows the existing try?/if-let error-handling pattern.
Sources/SuperwallKit/Analytics/Internal Tracking/Trackable Events/TrackableSuperwallEvent.swift Adds PaywallPageView internal event struct. Maps data.type to "navigation_type" analytics key — inconsistent with the Swift property name.
Sources/SuperwallKit/Paywall/Request/Operators/RawPaywallResponse.swift Correctly assigns a new UUID as presentationId after paywall fetch and before trackResponseLoaded, so all subsequent events within the presentation carry this ID.
Sources/SuperwallKit/Models/Paywall/Paywall.swift Adds presentationId as a var not included in CodingKeys, so it is never persisted to/from JSON. update(from:) correctly propagates the ID on re-presentation.

Sequence Diagram

sequenceDiagram
    participant WV as WebView (paywall.js)
    participant RW as RawWebMessageHandler
    participant PM as PaywallMessage decoder
    participant MH as PaywallMessageHandler
    participant SW as Superwall.shared

    WV->>RW: postMessage({ event_name: "page_view", page_node_id, flow_position, ... })
    RW->>PM: JSONDecoder.fromSnakeCase.decode(PaywallMessage.self)
    PM-->>RW: .pageView(PageViewData)
    RW->>MH: handle(.pageView(data))
    MH->>MH: guard delegate != nil
    MH->>MH: let paywallInfo = delegate.info (includes presentationId)
    MH->>SW: Task { track(PaywallPageView(paywallInfo, data)) }
    SW-->>SW: fire SuperwallEvent.paywallPageView<br/>params: page_node_id, flow_position,<br/>page_name, navigation_node_id,<br/>navigation_type, presentation_id, ...
Loading
Prompt To Fix All With AI
This is a comment left during a code review.
Path: Sources/SuperwallKit/Paywall/View Controller/Web View/Message Handling/PageViewData.swift
Line: 31

Comment:
**Ambiguous property name `type`**

The property is named `type` here, but it is mapped to the analytics key `"navigation_type"` in `TrackableSuperwallEvent.PaywallPageView.getSuperwallParameters()`:

```swift
params["navigation_type"] = data.type
```

This creates a confusing disconnect for SDK consumers who receive this struct in the `paywallPageView` delegate callback: the Swift property is `data.type`, but the analytics event parameter is `navigation_type`. A more descriptive name aligned with its semantics and the analytics key would be `navigationType`.

```suggestion
  /// How the user navigated to the page (e.g. "entry", "forward", "back").
  public let navigationType: String
```

This would also require updating the corresponding decode key handling and all references.

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: Tests/SuperwallKitTests/Web/WebEntitlementRedeemerTests.swift
Line: 2497-2503

Comment:
**Timing-based test synchronization**

The fix increases the sleep from 50 ms to 200 ms to reduce flakiness, but a wall-clock delay is still the synchronization mechanism. On a heavily loaded CI runner this can still race. A more reliable approach would be to inject a hook or use `withCheckedContinuation`/`AsyncStream` to await the init task's actual completion rather than guessing at its duration.

How can I resolve this? If you propose a fix, please make it concise.

Last reviewed commit: 5ac3e13

@chroxify chroxify requested review from yusuftor March 10, 2026 17:31
yusuftor and others added 4 commits March 16, 2026 14:03
…attern

Add PaywallPageViewInfo struct to expose pageNodeId, pageIndex, pageName,
and navigationType to SDK consumers. Align pageView message decoding with
the try?/if-let pattern used by all other PaywallMessage cases.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace PaywallPageViewInfo with public PageViewData, used for decoding,
internal tracking, and the public delegate event. Removes redundant
field-by-field passing throughout the chain.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
yusuftor and others added 6 commits March 16, 2026 14:46
Add CodingKeys to map from JSON "type" to navigationType property.
Document all possible values: entry, forward, back, auto_transition.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@yusuftor yusuftor merged commit 9d0da91 into develop Mar 16, 2026
3 checks passed
@yusuftor yusuftor deleted the christo/onboarding-analytics branch March 16, 2026 16:01
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