Before you startPaywalls build on the standard FlowPilot setup, plus RevenueCat:
- A FlowPilot workspace, an app inside it, and an SDK API key for that app.
- A RevenueCat account with your products, entitlements, and an offering configured for your app.
- Paywalls enabled for your workspace. If you do not see a Paywalls item in the dashboard sidebar, reach out and we will turn it on.
Create a paywall
Start a new paywall
Open the Paywalls section in the sidebar and choose New paywall. This creates a flow of type paywall, seeded with a starter layout and its monetization settings already turned on.
Monetization settings
The paywall inspector holds the settings that make a flow behave like a paywall. You reach it from the flow settings panel.| Setting | What it does |
|---|---|
| Offering | Current, or a pinned offering by identifier. Determines which packages are available. |
| Required entitlement | The entitlement this paywall unlocks (for example pro). Used for gating and to skip already-subscribed users. |
| Skip if entitled | When on, the paywall is not shown to a user who already holds the required entitlement. On by default. |
| Gating mode | soft (dismissible, continues on close), hard (closing leaves the feature locked, your app decides), or none (informational). Defaults to soft. |
| Close behavior | Whether to show the close control, and an optional delay before it appears. |
| Default plan | Which package is pre-selected when the paywall opens. |
| Plan order | The order your bound packages appear in. |
| Legal links | Your Terms and Privacy URLs, surfaced by the legal footer. |
| Restore copy | The message shown if a restore finds no purchase. |
Add Offers blocks
Paywall-specific building blocks live in the editor’s Offers category. They are compositions of standard components, so they render on every SDK with no extra work, but they carry the purchase wiring for you.Plan picker
A group of selectable plan cards that behaves like a single-select question. Add or remove plans, bind each to a package, set the order, and mark a best-value badge.
Plan option
A single selectable plan card: name, price, period, a trial line that shows only when the user is eligible, and a savings badge slot. Tapping it selects that package.
Purchase CTA
The primary button. It runs the purchase, shows a busy state while it is in flight, and closes the flow on success by default.
Restore
A text button that restores a previous purchase. App Review requires one somewhere in the flow.
Bind plans to packages
Each plan card points at one package from your synced catalog. Select a plan card, open its controller, and pick the package. When you rebind a plan, FlowPilot rewrites its price bindings and its selection wiring in one step, and keeps the plan order in sync, so you do not chase references by hand.TODO: screenshot of a plan option controller showing the package picker fed by the synced catalog.
Dynamic, store-truth pricing
Plan cards never contain a typed-in price. They read live values from the store through variables in thepaywall namespace, so what a user sees is exactly what they will be charged, in their currency, after any eligible trial.
The most useful values:
| Variable | Meaning |
|---|---|
paywall.selected.price | Localized price of the currently selected plan. |
paywall.selected.periodText | Localized billing period of the selected plan, for example month. |
paywall.package.<id>.price | Localized price of a specific package. |
paywall.package.<id>.trialText | Trial text, for example 7 days free, empty when the user is not eligible. |
paywall.productsState | loading, loaded, or failed, for skeleton and retry states. |
paywall.purchaseState | Drives the CTA’s busy and disabled state during a purchase. |
Continue for {{paywall.selected.price}} updates as the user switches plans.
Preview every state
Prices, trials, and purchase outcomes only exist at runtime, so the editor gives you a paywall preview to exercise them. Open the paywall preview control in the phone toolbar and switch between:- Products: loading, loaded, or failed to load.
- Trial: eligible or not eligible.
- Purchase result on tap: success, cancelled, pending, or failure.
- Restore result: found or not found.
- Entitlement: subscribed or not, to preview the skip-if-entitled path.
- Locale: sample currencies including a right-to-left layout, to catch overflow and truncation.
Publish
Publishing a paywall runs the normal publish flow plus a set of paywall checks. If any fail, publishing is blocked until you fix them. The main ones:- A purchase CTA is present.
- A restore action exists somewhere in the flow.
- Legal links (Terms and Privacy) are set.
- No hardcoded prices anywhere in the paywall’s text.
- Every bound package exists in your catalog and is not removed.
Common mistakes
- Typing a price into a headline or button. Bind to
paywall.selected.priceor apaywall.package.<id>.pricevariable so the store’s real, localized price shows. - Forgetting the restore button. App Review will reject a subscription paywall with no way to restore. Add the restore block.
- Leaving trial copy unconditional. A “7 days free” line must be bound to the trial variable so it only appears for users who are actually eligible.
- Not previewing the failed-products state. If products fail to load on device, your paywall still has to look right. Preview the loading and failed states.