Presenting via Events
Deprecating Soon!
All of the below (and so much more) can be accomplished by registering features, so we strongly recommend using
Superwall.shared.register(event:)
instead
You can also retroactively decide where and when to show a paywall in your app by tracking events using Superwall.shared.track(event:params:paywallOverrides:paywallHandler:)
, although we are planning on dropping this feature.
Register vs. Track
Since all of the below (and so much more) can be accomplished by registering features, we strongly recommend using Superwall.shared.register(event:)
in favor of track.
Here is how the main workflow differs:
Using Track
Take the following event as an example:
Superwall.shared.track(event: "workout_complete", params: ["total_workouts": 7])
[[Superwall sharedInstance] trackWithEvent:@"workout_complete" params:@{ @"total_workouts": @7 }];
This event gets tracked and sent back to Superwall.
You can configure this event to present a paywall by creating a campaign, adding the event, and adding a rule in the dashboard.
The SDK retrieves and caches your events and rules from the dashboard on app launch. The rules are evaluated on device whenever Superwall.shared.track(...)
is called. This means there's no delay between tracking an event and presenting a paywall.
When a user is assigned a paywall for a rule, they will continue to see that paywall unless you remove the paywall from the rule or reset assignments to the paywall.
The SDK automatically tracks some internal events which can be used to present paywalls:
app_install
app_launch
deepLink_open
session_start
In some circumstances, you might like to get the result of tracking an event before you actually track the event. For example, to check if a particular event will present a paywall. To do this, you can use
Superwall.shared.getPresentationResult(forEvent:params:)
.
To provide your team with ultimate flexibility, we recommend tracking all of your analytics events. This way you can retroactively add a paywall almost anywhere, without an app update!
If you're already set up with an analytics provider, you'll typically have an Analytics.swift
singleton (or similar) to disperse all your events from. Here's how that file might look:
import SuperwallKit
import Mixpanel
import Firebase
final class Analytics {
static var shared = Analytics()
func track(
event: String,
properties: [String: Any]
) {
// Superwall
Superwall.shared.track(event: event, params: properties)
// Firebase (just an example)
Firebase.Analytics.logEvent(event, parameters: properties)
// Mixpanel (just an example)
Mixpanel.mainInstance().track(event: eventName, properties: properties)
}
}
// And thus ...
Analytics.shared.track(
event: "workout_complete",
properties: ["total_workouts": 17]
)
// ... just works :)
Tracking an event doesn't guarantee the paywall will show
A paywall will only show if the following conditions are met:
- An event you provide is added to a campaign on the Superwall Dashboard
- The user matches a rule in the campaign.
- The user doesn't have an active subscription.
- The user isn't in a holdout group.
If you are seeing unexpected behavior when tracking a paywall, please run through this checklist to diagnose what's happening.
Handling Paywall State
You can receive callbacks for the paywall state after tracking by using the paywallHandler
:
Superwall.shared.track(
event: "workout_complete",
params: ["total_workouts": 17]
) { [weak self] paywallState in
switch paywallState {
case .presented(let paywallInfo):
print("paywall info is", paywallInfo)
case .dismissed(let paywallInfo, let purchaseResult):
switch purchaseResult {
case .purchased(let productId):
print("The purchased product ID is", productId)
case .closed:
print("The paywall was closed.")
case .restored:
print("The product was restored.")
}
case .skipped(let reason):
switch reason {
case .holdout(let experiment):
print("The user is in a holdout group, with id \(experiment.id) and group id \(experiment.groupId)")
case .noRuleMatch:
print("The user did not match any rules")
case .eventNotFound:
print("The event wasn't found in a campaign on the dashboard.")
case .userIsSubscribed:
print("The user is subscribed.")
case .error(let error):
print("Failed to present paywall. Consider a native paywall fallback", error)
}
}
}
}
-(void)trackEvent {
[[Superwall sharedInstance] trackWithEvent:@"workout_complete"
params:@{@"total_workouts" : @17}
onSkip:^(enum SWKPaywallSkippedReason reason, NSError * _Nullable error) {
// Handle skipped paywall
}
onPresent:^(SWKPaywallInfo * _Nonnull paywallInfo) {
// Handle paywall presentation
}
onDismiss:^(enum SWKPaywallDismissedResultState dismissedResultState, NSString * _Nullable productIdentifier, SWKPaywallInfo * _Nonnull paywallInfo) {
// Handle paywall dismissal
}
];
}
In this example, you're sending the event workout_complete
to the dashboard along with some parameters. You can then utilize the completion handler to respond accordingly.
Parameter | Type | Notes |
---|---|---|
event | String | The name of the event you wish to track. |
params | [String: Any]? | Optional parameters you’d like to pass with your event. These can be referenced within the rules of your campaign. Keys beginning with $ are reserved for Superwall and will be dropped. Values can be any JSON encodable value, URLs or Dates . Arrays and Dictionaries as values are not supported at this time, and will be dropped. |
paywallOverrides | PaywallOverrides? | An optional PaywallOverrides object whose parameters override the paywall defaults. Use this to override products, presentation style, and whether it ignores the subscription status. Defaults to nil. |
paywallHandler | ((PaywallState) -> Void)? | An optional callback that provides updates on the state of the paywall via a PaywallState object. |
SwiftUI
For SwiftUI apps, you call the same function. It's best practice to create a model class that calls this UIKit function:
import SuperwallKit
final class TrackEventModel {
func trackEvent() {
Superwall.shared.track(event: "workout_complete") { paywallState in
// State handling here...
}
}
}
import SwiftUI
struct TrackEventView: View {
private let model = TrackEventModel()
var body: some View {
Button(
action: {
model.trackEvent()
},
label: {
Text("Track Event")
}
)
}
}
Using Combine
An alternative to using completion handlers is to use Combine publishers. You can use Superwall.shared.publisher(forEvent:params:paywallOverrides)
to get a Publisher
that publishes PaywallState
updates upon tracking an event:
import Combine
import SuperwallKit
final class TrackEventModel {
private var cancellable: AnyCancellable?
func trackEvent() {
cancellable = Superwall.shared
.publisher(
forEvent: "workout_complete",
params: ["total_workouts": 17]
)
.sink { paywallState in
switch paywallState {
case .presented(let paywallInfo):
print("paywall info is", paywallInfo)
case .dismissed(let result):
switch result.state {
case .closed:
print("User dismissed the paywall.")
case .purchased(productId: let productId):
print("Purchased a product with id \(productId), then dismissed.")
case .restored:
print("Restored purchases, then dismissed.")
}
case .skipped(let reason):
switch reason {
case .noRuleMatch:
print("The user did not match any rules")
case .holdout(let experiment):
print("The user is in a holdout group, with experiment id: \(experiment.id), group id: \(experiment.groupId), paywall id: \(experiment.variant.paywallId ?? "")")
case .eventNotFound:
print("The event wasn't found in a campaign on the dashboard.")
case .userIsSubscribed:
print("The user is subscribed.")
case .error(let error):
print("Failed to present paywall. Consider a native paywall fallback", error)
}
}
}
}
}
Updated 26 days ago