Paywall Schema
Tap Behaviors

Tap Behaviors

Tap behaviors define what happens when a user interacts with an actionable component (buttons, links, toggles). They are specified via the action prop on cta_button and link_row components.

Available Actions

ActionDescription
purchaseInitiate purchase of the specified or selected product
select_productSet the selected product (used in product pickers)
restoreRestore previous purchases
closeDismiss the paywall
open_urlOpen a URL in the system browser
custom_actionFire a custom action handled by the app delegate
custom_placementRegister another placement (chain paywalls)
navigate_pageNavigate to the next page in a multi-page flow
request_reviewTrigger the App Store / Play Store review prompt

purchase

Initiates a purchase flow for a product.

Required props: product (slot name or "selected")

{
  "type": "cta_button",
  "id": "buy",
  "props": {
    "text": "Subscribe Now",
    "action": "purchase",
    "product": "selected"
  }
}

The product value can be:

  • "selected" -- Purchase whichever product the user has selected via the product picker
  • "primary", "secondary", "tertiary" -- Purchase a specific product slot

On iOS, this triggers a StoreKit 2 purchase. On Android, this triggers Google Play Billing.


select_product

Sets the currently selected product. Used internally by product_picker but can also be used on custom buttons.

{
  "type": "cta_button",
  "id": "pick_annual",
  "props": {
    "text": "Annual Plan",
    "action": "select_product",
    "product": "primary"
  }
}

restore

Triggers a purchase restoration flow. On iOS, this calls AppStore.sync(). On Android, this queries Play Billing for existing purchases.

{
  "text": "Restore Purchases",
  "action": "restore"
}

The SDK tracks restore_started and restore_complete events and calls the delegate's didRestorePurchases() method on success.


close

Dismisses the paywall. The SDK tracks a paywall_close event.

{
  "text": "Not Now",
  "action": "close"
}

open_url

Opens a URL in the system browser (Safari on iOS, Chrome on Android).

Required props: url

{
  "text": "Terms of Service",
  "action": "open_url",
  "url": "https://example.com/terms"
}

custom_action

Fires a named action that the app handles via the delegate. This is an escape hatch for app-specific behavior that the paywall schema cannot express.

Required props: action_name

{
  "type": "cta_button",
  "id": "watch_video",
  "props": {
    "text": "Watch Demo Video",
    "action": "custom_action",
    "action_name": "play_demo_video"
  }
}

The delegate receives this via:

  • iOS: handleCustomAction(name: "play_demo_video")
  • Android: onCustomAction("play_demo_video")

custom_placement

Registers another placement, allowing paywalls to chain. For example, a paywall could have a button that triggers a different paywall flow.

Required props: placement_name

{
  "type": "cta_button",
  "id": "see_plans",
  "props": {
    "text": "See All Plans",
    "action": "custom_placement",
    "placement_name": "full_pricing"
  }
}

navigate_page

Navigates to the next page in a slides component. Used for multi-step onboarding or wizard-style paywalls.

{
  "type": "cta_button",
  "id": "next",
  "props": {
    "text": "Next",
    "action": "navigate_page"
  }
}

request_review

Triggers the native app review prompt (SKStoreReviewController on iOS, ReviewManager on Android). Typically used after a positive user interaction.

{
  "type": "cta_button",
  "id": "rate",
  "props": {
    "text": "Rate Us",
    "action": "request_review"
  }
}

Note: The system may throttle review prompts. The SDK calls the system API but cannot guarantee the prompt will appear.