Presenting Experiences
Show paywalls and screens to users as overlay WebViews
Experiences are the published screen bundles you build in the Studio – paywalls, onboarding sequences, upgrade prompts – compiled and delivered to the SDK. Present them as overlay WebViews that render above your app’s UI and support native actions like purchases, navigation, and custom events.
Terminology note: In the Studio you edit a Project. Publishing creates an immutable Version (
ver_...). The current iOS method remainsshowFlow(with:); itsflowIdparameter is an experience version ID. The code samples below match that current SDK surface.
How experiences reach the device
- You design and publish a project in the Nuxie Studio.
- The SDK fetches the experience definition as part of the user’s profile payload.
- Experience assets (HTML, CSS, JavaScript, fonts) are cached locally as a WebArchive for fast presentation.
- When an experience triggers or you call
showFlow(), the SDK loads the cached assets into a WebView overlay.
The SDK prefetches experience assets in the background whenever the profile updates, so experiences load instantly even on first presentation.
Manual presentation
Present a experience directly by its ID:
try await NuxieSDK.shared.showFlow(with: "ver_abc123")
This opens the experience in a dedicated overlay window above your app’s current view hierarchy. The experience renders full-screen and handles its own dismissal through actions configured in the Studio.
You can also get a FlowViewController for custom embedding:
let viewController = try await NuxieSDK.shared.getFlowViewController(with: "ver_abc123")
present(viewController, animated: true)
Automatic presentation via experiences
Experiences present experiences automatically based on triggers you configure in the dashboard:
- Event triggers – a experience appears when the user fires a specific event via
trigger(). - Segment triggers – a experience appears when the user enters (or exits) a segment.
When an experience matches, the SDK presents the experience without any additional code:
// If an experience targets "checkout_started", this may present a experience
NuxieSDK.shared.trigger("checkout_started")
Use the TriggerHandle to observe what happened:
NuxieSDK.shared.trigger("checkout_started") { update in
switch update {
case .decision(.flowShown(let ref)):
print("Experience presented: \(ref)")
case .decision(.suppressed(let reason)):
print("Experience suppressed: \(reason)")
case .decision(.noMatch):
print("No experience matched this event")
default:
break
}
}
Reentry policies
Experiences support reentry policies that control how often a experience appears:
| Policy | Behavior |
|---|---|
| Every time | Show the experience on every qualifying trigger. |
| One time | Show the experience once per user, ever. |
| Once per window | Show the experience once within a time window (e.g., once per day). |
The overlay window
Experiences display in a dedicated UIWindow layered above your app:
- The window sits at the
.alertwindow level, so it appears above navigation bars, tab bars, and modals. - Only one experience can be presented at a time. Presenting a new experience dismisses the current one.
- After the app returns to the foreground, there is a short grace period (under one second) before experiences can appear, preventing abrupt presentations.
Runtime bridge
The experience’s web content communicates with your native app through a runtime bridge. This bridge supports:
- Purchase actions – initiate a StoreKit purchase from a button in the experience.
- Restore actions – trigger a purchase restore.
- Navigation actions – move between screens within a multi-screen experience.
- Dismiss actions – close the experience.
- Open link actions – open a URL in the system browser.
- Custom delegate actions – send a message to your app via
NotificationCenter.
Listening for delegate actions
When a experience fires a call_delegate action, the SDK posts a Notification your app can observe:
NotificationCenter.default.addObserver(
forName: .nuxieCallDelegate,
object: nil,
queue: .main
) { notification in
let message = notification.userInfo?["message"] as? String
let payload = notification.userInfo?["payload"] as? [String: Any]
// Handle the delegate call
}
Other bridge actions post similar notifications: .nuxiePurchase, .nuxieRestore, .nuxieOpenLink, .nuxieDismiss.
Experience caching
The SDK caches experience assets at multiple layers for fast loading:
- WebArchive cache – the full experience bundle is stored on disk as a WebArchive file. On presentation, the SDK loads from the local file instead of fetching over the network.
- Font cache – custom fonts referenced by experiences are downloaded and served from a local cache via a custom URL scheme.
- In-memory cache – enriched experience models (including resolved StoreKit product metadata) are held in memory for the current session.
Cache invalidation happens automatically:
- When the profile delivers updated experience content (detected by content hash), the old cache is removed and the new version is prefetched.
- When the user logs out (
reset()), all experience caches are cleared.
Next steps
- Purchases – handle purchases initiated from within experiences
- Experiences – configure triggers, goals, and reentry policies in the dashboard
- Features & Entitlements – gate features based on what the user has purchased