Skip to content
Nuxie
Esc
navigateopen⌘Jpreview
On this page

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 remains showFlow(with:); its flowId parameter is an experience version ID. The code samples below match that current SDK surface.

How experiences reach the device

  1. You design and publish a project in the Nuxie Studio.
  2. The SDK fetches the experience definition as part of the user’s profile payload.
  3. Experience assets (HTML, CSS, JavaScript, fonts) are cached locally as a WebArchive for fast presentation.
  4. 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 .alert window 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

Last updated on July 30, 2026

Was this page helpful?