Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -468,6 +468,43 @@ enum InternalSuperwallEvent {
}
}

struct PaywallPageView: TrackableSuperwallEvent {
var superwallEvent: SuperwallEvent {
return .paywallPageView(paywallInfo: paywallInfo)
}
let paywallInfo: PaywallInfo
let pageNodeId: String
let flowPosition: Int
let pageName: String
let navigationNodeId: String
let previousPageNodeId: String?
let previousFlowPosition: Int?
let navigationType: String
let timeOnPreviousPageMs: Int?

func getSuperwallParameters() async -> [String: Any] {
var params = await paywallInfo.placementParams()
params["page_node_id"] = pageNodeId
params["flow_position"] = flowPosition
params["page_name"] = pageName
params["navigation_node_id"] = navigationNodeId
params["navigation_type"] = navigationType
if let previousPageNodeId = previousPageNodeId {
params["previous_page_node_id"] = previousPageNodeId
}
if let previousFlowPosition = previousFlowPosition {
params["previous_flow_position"] = previousFlowPosition
}
if let timeOnPreviousPageMs = timeOnPreviousPageMs {
params["time_on_previous_page_ms"] = timeOnPreviousPageMs
}
return params
}
var audienceFilterParams: [String: Any] {
return paywallInfo.audienceFilterParams()
}
}

struct PaywallClose: TrackableSuperwallEvent {
var superwallEvent: SuperwallEvent {
return .paywallClose(paywallInfo: paywallInfo)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,9 @@ public enum SuperwallEvent {
/// When the test mode modal is closed.
case testModeModalClose

/// When a user navigates to a page in a multi-page paywall.
case paywallPageView(paywallInfo: PaywallInfo)
Copy link

Choose a reason for hiding this comment

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

The paywallPageView event only carries paywallInfo as its associated data. SDK consumers receiving this event via the delegate callback will know that a page view occurred, but won't be able to determine which page was viewed, what the navigation type was, or access any other page-specific details.

The internal tracking (lines 262–272 of PaywallMessageHandler.swift) captures all this context—pageNodeId, pageIndex, pageName, navigationType, previousPageNodeId, etc.—but none of it is surfaced in the public event.

Compare this to similar rich events like surveyResponse(survey:selectedOption:customResponse:paywallInfo:) or triggerFire(placementName:result:), which embed their contextual data directly. Consider whether page-specific fields should be included as associated values to make the event useful to SDK integrators:

case paywallPageView(
  paywallInfo: PaywallInfo,
  pageNodeId: String,
  pageIndex: Int,
  pageName: String,
  navigationType: String
)
Prompt To Fix With AI
This is a comment left during a code review.
Path: Sources/SuperwallKit/Analytics/Superwall Placement/SuperwallEvent.swift
Line: 285

Comment:
The `paywallPageView` event only carries `paywallInfo` as its associated data. SDK consumers receiving this event via the delegate callback will know that a page view occurred, but won't be able to determine which page was viewed, what the navigation type was, or access any other page-specific details.

The internal tracking (lines 262–272 of `PaywallMessageHandler.swift`) captures all this context—`pageNodeId`, `pageIndex`, `pageName`, `navigationType`, `previousPageNodeId`, etc.—but none of it is surfaced in the public event.

Compare this to similar rich events like `surveyResponse(survey:selectedOption:customResponse:paywallInfo:)` or `triggerFire(placementName:result:)`, which embed their contextual data directly. Consider whether page-specific fields should be included as associated values to make the event useful to SDK integrators:

```swift
case paywallPageView(
  paywallInfo: PaywallInfo,
  pageNodeId: String,
  pageIndex: Int,
  pageName: String,
  navigationType: String
)
```

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

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!


var canImplicitlyTriggerPaywall: Bool {
switch self {
case .appInstall,
Expand Down Expand Up @@ -478,6 +481,8 @@ extension SuperwallEvent {
return .init(objcEvent: .testModeModalOpen)
case .testModeModalClose:
return .init(objcEvent: .testModeModalClose)
case .paywallPageView:
return .init(objcEvent: .paywallPageView)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,9 @@ public enum SuperwallEventObjc: Int, CaseIterable {
/// When the test mode modal is closed.
case testModeModalClose

/// When a user navigates to a page in a multi-page paywall.
case paywallPageView

public init(event: SuperwallEvent) {
self = event.backingData.objcEvent
}
Expand Down Expand Up @@ -419,6 +422,8 @@ public enum SuperwallEventObjc: Int, CaseIterable {
return "testModeModal_open"
case .testModeModalClose:
return "testModeModal_close"
case .paywallPageView:
return "paywall_page_view"
}
}
}
6 changes: 6 additions & 0 deletions Sources/SuperwallKit/Models/Paywall/Paywall.swift
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,10 @@ struct Paywall: Codable {

// MARK: - Added by client

/// A unique identifier for this paywall presentation, used to correlate all events
/// within a single presentation lifecycle.
var presentationId: String?

var responseLoadingInfo: LoadingInfo
var webviewLoadingInfo: LoadingInfo
var shimmerLoadingInfo: LoadingInfo
Expand Down Expand Up @@ -424,6 +428,7 @@ struct Paywall: Codable {
url: url,
products: products,
productIds: productIds,
presentationId: presentationId,
fromPlacementData: fromPlacement,
responseLoadStartTime: responseLoadingInfo.startAt,
responseLoadCompleteTime: responseLoadingInfo.endAt,
Expand Down Expand Up @@ -460,6 +465,7 @@ struct Paywall: Codable {
presentationSourceType = paywall.presentationSourceType
experiment = paywall.experiment
featureGating = paywall.featureGating
presentationId = paywall.presentationId
}
}

Expand Down
11 changes: 10 additions & 1 deletion Sources/SuperwallKit/Paywall/Presentation/PaywallInfo.swift
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,10 @@ public final class PaywallInfo: NSObject {
/// `.automatic`.
public let introOfferEligibility: IntroOfferEligibility

/// A unique identifier for this paywall presentation, used to correlate all events
/// within a single presentation lifecycle.
public let presentationId: String?

init(
databaseId: String,
identifier: String,
Expand All @@ -144,6 +148,7 @@ public final class PaywallInfo: NSObject {
url: URL,
products: [Product],
productIds: [String],
presentationId: String?,
fromPlacementData placementData: PlacementData?,
responseLoadStartTime: Date?,
responseLoadCompleteTime: Date?,
Expand Down Expand Up @@ -182,6 +187,7 @@ public final class PaywallInfo: NSObject {
self.presentationSourceType = presentationSourceType
self.experiment = experiment
self.paywalljsVersion = paywalljsVersion
self.presentationId = presentationId
self.products = products
self.productIds = productIds
self.isFreeTrialAvailable = isFreeTrialAvailable
Expand Down Expand Up @@ -271,7 +277,8 @@ public final class PaywallInfo: NSObject {
"close_reason": closeReason.description,
"is_scroll_enabled": isScrollEnabled as Any,
"intro_offer_eligibility": introOfferEligibility.description,
"app_transaction_id": ReceiptManager.appTransactionId as Any
"app_transaction_id": ReceiptManager.appTransactionId as Any,
"presentation_id": presentationId as Any
]

var loadingVars: [String: Any] = [:]
Expand Down Expand Up @@ -356,6 +363,7 @@ extension PaywallInfo: Stubbable {
url: URL(string: "https://superwall.com")!,
products: [],
productIds: [],
presentationId: nil,
fromPlacementData: nil,
responseLoadStartTime: nil,
responseLoadCompleteTime: nil,
Expand Down Expand Up @@ -398,6 +406,7 @@ extension PaywallInfo: Stubbable {
url: URL(string: "https://superwall.com")!,
products: [],
productIds: [],
presentationId: nil,
fromPlacementData: nil,
responseLoadStartTime: nil,
responseLoadCompleteTime: nil,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ extension PaywallRequestManager {
paywallId: request.responseIdentifiers.paywallId,
placement: request.placementData
)
let paywall = try await getPaywallResponse(from: request)
var paywall = try await getPaywallResponse(from: request)
paywall.presentationId = UUID().uuidString

let paywallInfo = paywall.getInfo(fromPlacement: request.placementData)
await trackResponseLoaded(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,17 @@ enum PaywallMessage: Decodable, Equatable {
variables: JSON?
)
case hapticFeedback(hapticType: String)
// swiftlint:disable:next enum_case_associated_values_count
case pageView(
pageNodeId: String,
flowPosition: Int,
pageName: String,
navigationNodeId: String,
previousPageNodeId: String?,
previousFlowPosition: Int?,
type: String,
timeOnPreviousPageMs: Int?
)

// All cases below here are sent from device to paywall
case paywallClose
Expand Down Expand Up @@ -121,6 +132,7 @@ enum PaywallMessage: Decodable, Equatable {
case requestPermission = "request_permission"
case requestCallback = "request_callback"
case hapticFeedback = "haptic_feedback"
case pageView = "page_view"
}

// Everyone write to eventName, other may use the remaining keys
Expand Down Expand Up @@ -149,6 +161,13 @@ enum PaywallMessage: Decodable, Equatable {
case behavior
case variables
case hapticType
case pageNodeId
case flowPosition
case pageName
case navigationNodeId
case previousPageNodeId
case previousFlowPosition
case timeOnPreviousPageMs
}

enum PaywallMessageError: Error {
Expand Down Expand Up @@ -310,6 +329,26 @@ enum PaywallMessage: Decodable, Equatable {
self = .hapticFeedback(hapticType: hapticType)
return
}
case .pageView:
let pageNodeId = try values.decode(String.self, forKey: .pageNodeId)
let flowPosition = try values.decode(Int.self, forKey: .flowPosition)
let pageName = try values.decode(String.self, forKey: .pageName)
let navigationNodeId = try values.decode(String.self, forKey: .navigationNodeId)
let previousPageNodeId = try? values.decode(String.self, forKey: .previousPageNodeId)
let previousFlowPosition = try? values.decode(Int.self, forKey: .previousFlowPosition)
let type = try values.decode(String.self, forKey: .type)
let timeOnPreviousPageMs = try? values.decode(Int.self, forKey: .timeOnPreviousPageMs)
self = .pageView(
pageNodeId: pageNodeId,
flowPosition: flowPosition,
pageName: pageName,
navigationNodeId: navigationNodeId,
previousPageNodeId: previousPageNodeId,
previousFlowPosition: previousFlowPosition,
type: type,
timeOnPreviousPageMs: timeOnPreviousPageMs
)
return
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,23 @@
)
case .hapticFeedback(let hapticType):
triggerHapticFeedback(hapticType)
case let .pageView(pageNodeId, flowPosition, pageName, navigationNodeId, previousPageNodeId, previousFlowPosition, type, timeOnPreviousPageMs):

Check warning on line 258 in Sources/SuperwallKit/Paywall/View Controller/Web View/Message Handling/PaywallMessageHandler.swift

View workflow job for this annotation

GitHub Actions / Package-SwiftLint

Line Length Violation: Line should be 120 characters or less; currently it has 147 characters (line_length)
guard let delegate = delegate else { return }
let paywallInfo = delegate.info
Task {
let event = InternalSuperwallEvent.PaywallPageView(
paywallInfo: paywallInfo,
pageNodeId: pageNodeId,
flowPosition: flowPosition,
pageName: pageName,
navigationNodeId: navigationNodeId,
previousPageNodeId: previousPageNodeId,
previousFlowPosition: previousFlowPosition,
navigationType: type,
timeOnPreviousPageMs: timeOnPreviousPageMs
)
await Superwall.shared.track(event)
}
}
}

Expand Down Expand Up @@ -414,7 +431,7 @@
// block selection
let selectionString =
// swiftlint:disable:next line_length
"var css = '*{-webkit-touch-callout:none;-webkit-user-select:none} .w-webflow-badge { display: none !important; }'; "

Check warning on line 434 in Sources/SuperwallKit/Paywall/View Controller/Web View/Message Handling/PaywallMessageHandler.swift

View workflow job for this annotation

GitHub Actions / Package-SwiftLint

Superfluous Disable Command Violation: SwiftLint rule 'line_length' did not trigger a violation in the disabled region; remove the disable command (superfluous_disable_command)
+ "var head = document.head || document.getElementsByTagName('head')[0]; "
+ "var style = document.createElement('style'); style.type = 'text/css'; "
+ "style.appendChild(document.createTextNode(css)); head.appendChild(style); "
Expand Down
Loading
Loading