How Remote UI is selected
Your app requests a placement with a locale and user ID. PNLight returns the matching dashboard config when the placement is enabled and a usable config is available. Create every placement that your app can request in Remote UI. On a fresh fetch from PNLight (for example, when you passignoreCache), if the placement is missing, disabled, deleted, or missing a usable locale config, PNLight returns no UI for that request.
The dashboard tracks:
- Requests: users who requested the placement.
- Shown: users who received a UI config that could be shown.
{{monthlyProductId}}.
Render a placement
RemoteUiView calls getUIConfig internally. On the first app launch, when you use attribution from AppsFlyer, wait 4-5 seconds after AppsFlyer initialization before showing the placement so conversion data has time to arrive. When attributionRequired is true, the SDK also waits for attribution internally before requesting the config.
Server-driven flows
Remote UI can return a flow instead of a single card. A flow usesschemaVersion: 2, type: "flow", an initial_route, and a routes object where each route contains a complete UI document.
Render a flow with the same RemoteUiView integration. The SDK handles native navigation and modal presentation inside the Remote UI surface, so React Native and Flutter apps do not need extra navigation setup for PNLight routes.
Use PNLight navigation URLs inside flow routes:
PNLight consumes these navigation URLs inside a valid flow. Use app-specific URLs, action IDs, or action paths when the host app should handle an action through
onAction.
Remote UI components
Use Remote UI components to add PNLight components to a config and review their properties.Remote UI schema version
PNLight versions the Remote UI envelope separately from SDK package versions. Put the version at the document root.- Schema v2 adds flows, safe areas, scaling variables, haptics, and dialogs.
- Schema v3 keeps that behavior and adds
pnlight.purchase,pnlight.progress_bar, andpnlight.animated_number. - Schema v4 keeps schema v3 behavior and adds
on_failandon_cancelfollow-ups onpnlight.purchase.
pnlight.purchase or render schema v3 components. Schema v3 configs still run
on_success only.
Handle actions
Remote UI actions are delivered to your app. Use action IDs, paths, or query parameters to decide what it should do. Different placements can return different actions, so make the handler explicit. Common actions:- Start a purchase with
pnlight.purchase, or route to a host-app purchase flow when you need custom behavior. - Return the user to the main app screen after a successful subscription.
- Close the screen.
- Open another app screen.
- Track a product interaction.
SDK-owned purchase action
Usepnlight.purchase when a Remote UI button should start a StoreKit purchase
through the PNLight SDK. The document must declare "schemaVersion": 3 or
"schemaVersion": 4.
params.product_id is required. Use a literal App Store product ID or a product
runtime placeholder from the placement.
These follow-up lists are optional. Each one accepts ordinary DivKit action
dictionaries:
on_successruns after a successful purchase. Schema v3 and v4 both support it.on_failruns when the purchase throws an error. This needs schema v4.on_cancelruns when the user dismisses the StoreKit sheet. This also needs schema v4.
pnlight.purchase opens a simulator. Success
runs on_success. In schema v4, Fail runs on_fail, and Cancel or
dismissing the simulator runs on_cancel. Schema v3 preview still has
Success and Fail only. Fail just closes the simulator. No real
StoreKit transaction occurs in the preview.
Use the onPurchased callback on RemoteUiView when the app needs to refresh
entitlements, unlock content, or update navigation after a Remote UI purchase.
The callback receives the purchased product ID. It is emitted only for purchases
started by that Remote UI view, not for manual SDK purchase calls.
Fetch configs manually
UsegetUIConfig if you need to fetch the placement configuration yourself. On the first app launch, when attribution is required, call it after sending attribution and wait 4-5 seconds after AppsFlyer initialization before requesting the config. The SDK still waits for attribution internally when attributionRequired is true.
Config cache behavior
Remote UI configs are cache-first by default. If a cached config exists, the SDK can return it immediately and refresh it in the background with an ETag request. This keeps repeat displays responsive while still picking up dashboard changes. UseignoreCache when the app needs the latest server response, such as during QA or after a user changes a state that should affect targeting.
Handle missing configs and errors
On a fresh fetch from PNLight, anull or empty config means PNLight did not return UI for that placement. This can happen when the placement does not exist in Remote UI, the placement is disabled, targeting does not match, show-once rules suppress the placement, capture protection blocks the user, no matching locale config exists, or a runtime placeholder cannot be resolved.
React Native and Flutter wrappers surface loading errors separately from missing UI. Use onError on RemoteUiView or handle getUIConfig errors when you fetch manually.
Swift apps that fetch manually can use getUIConfigResult to distinguish all outcomes: