Skip to main content
A paywall is a fullscreen UI that you design in Helium and display to users in your app. It’s built with React, rendered in a WebView, and can be fully customized — layout, copy, images, animations, products, and translations. Paywalls are the visual surface of your monetization strategy; workflows and experiments decide when to show them, but the paywall is what the user sees.

Anatomy of a Paywall


How Paywalls Are Rendered

Paywalls are bundled into a single web file and rendered inside a native WebView:
  1. Your app’s SDK receives a trigger and resolves it to a workflow.
  2. The SDK loads this bundle in a WKWebView (iOS) or WebView (Android).
  3. The paywall communicates back to the native app via a bridge — handling subscribe, dismiss, restore purchases, and product selection events.
This architecture means paywalls support anything a web page can: CSS animations, custom fonts, Lottie animations, responsive layouts, and dynamic product data. And your paywall can interact directly with the native functions of your mobile frameworks.

Creating a Paywall

Paywalls can be created in four ways: All creation methods follow the same flow:
  1. Enter a name and description.
  2. Select product buckets (and choose initial iOS/Android/Stripe products).
  3. Helium generates the initial files and opens the editor.

The Paywall Editor

The editor is a live coding environment powered by Sandpack (CodeSandbox’s embeddable bundler). You edit React code on the left and see a real-time preview on the right.

Editable files

Auto-generated files (read-only in most cases)

Preview features

  • Device selector — Preview on different phone models and sizes.
  • Platform toggle — Switch between iOS and Android to see platform-specific products.
  • Territory picker — Preview localized prices for any App Store or Play Store territory.
  • Offer simulation — Toggle intro offer eligibility to preview trial and promotional pricing.

Versioning

Every paywall has a version history. Each save creates a new version, building a timeline of changes.

Version statuses

How it works

  • Every save (manual or autosave) creates a new draft version.
  • The version stores all paywall files, product bucket references, font references, and a CRDT snapshot.
  • Each version tracks its parent version, forming a version tree.
  • You can browse version history and see who saved each version and when.

Saving

Paywalls support both manual and automatic saving: Each save bundles the code into a deployable web file. This means your draft is always previewable — bundling doesn’t wait for publish.

Publishing

Publishing makes a draft version live. When you publish:
  1. Validation — Helium checks for issues like hardcoded prices (prices should come from product data, not be typed into the UI).
  2. Status update — The draft becomes published. The previously published version becomes archived.
  3. SDK sync — The bundle_url on the paywall record is updated so the SDK fetches the new version.
  4. History entry — A record is added to paywall_publish_history with who published and when.
Publishing is instant — once published, the next SDK fetch gets the new bundle. There’s no deploy step or propagation delay.

Products and Buckets

Paywalls don’t reference raw product IDs. Instead, they reference product buckets — cross-platform containers that hold iOS, Android, and Stripe products for a single logical offering.
  • A paywall’s product_bucket_ids lists which buckets it uses.
  • The editor resolves buckets into a products.tsx file with localized pricing for the selected territory.
  • When the SDK loads the paywall, it receives the product references and handles purchasing natively.

How Paywalls Connect to Workflows

Paywalls are used in workflows in three ways:
  • Control paywall — Every workflow has a default paywall shown when no targeting rules match.
  • Audience targeting — A workflow rule can map an audience directly to a specific paywall.
  • Experiment variants — Paywalls serve as variants in A/B tests, each receiving a share of traffic.
Only published paywalls can be assigned to workflows and experiments. Draft-only paywalls won’t appear in selection lists.

Second-Try Paywalls

A paywall can optionally have a second-try paywall — a follow-up paywall shown if the user dismisses the first one. This is configured via paywall settings field and allows for a softer re-engagement attempt (e.g., a discounted offer after the user declines the full-price paywall). Second-try paywalls can either appear after a paywall dismiss or after a subscription cancel event.

Localization

Paywalls have a full localization system with per-locale translations, territory-aware pricing, and right-to-left layout support. Translation keys are defined and managed through the editor. Localizely support is available for localization management as well. See [Localization] for the complete localization documentation.

Key Rules

  • Paywall names can be up to 100 characters.
  • Only published paywalls can be used in workflows and experiments.
  • Only one published version exists per paywall at a time.
  • Publishing runs validation — hardcoded prices and other issues can block publish.
  • Paywalls cannot be deleted if they’re referenced by a workflow.
  • Every save bundles the code — drafts are always previewable.
  • Product data is auto-generated from buckets — don’t hardcode prices in your UI.
  • Paywalls render in a WebView — they support standard web features (CSS, fonts, animations, Lottie).

Common Patterns