Paywall Screen

PaywallScreen — where users subscribe. Renders RevenueCat's prebuilt Compose paywall, so the design, copy, prices, and offerings live in the RevenueCat dashboard (no UI code to maintain). Hard or soft.

📱Paywall — lightlight/docs/screens/paywall-light.png
📱Paywall — darkdark/docs/screens/paywall-dark.png

feature/paywall/PaywallScreen.kt

How it's wired

KitNavHost shows the paywall after auth when the user isn't subscribed. Configure with:

/kit-setup-paywall
// KitConfig.kt — set for you
const val PAYWALL_ENABLED = true
val PAYWALL_MODE = PaywallMode.HARD      // SOFT (skippable) · HARD (blocking)
const val ENTITLEMENT_ID = "premium"
ModeBehaviour
SOFTShows a dismiss (✕) — user can skip into the app
HARDBlocking — Home only after subscribing or restoring

Subscribers (anyone holding the premium entitlement) skip the paywall automatically on next launch — PurchaseManager.isPremium drives the nav resolver.

What's in the code (and what isn't)

PaywallScreen.kt is tiny on purpose — it just hosts RevenueCat's Paywall composable and forwards events:

  • The design, copy, prices, and offerings are NOT in the app. You build them in the RevenueCat dashboard (Project → Paywalls); the app downloads and renders whatever you publish. Change the paywall there and the app picks it up — no rebuild.
  • A PaywallListener forwards purchase and restore completions to navigation (the built-in paywall already shows the Restore button + price options).
  • During development, before you've published an offering, the composable shows RevenueCat's own empty/offering state on device — that's expected, not a bug.

Because the whole paywall UI is RevenueCat's, the kit deliberately does not ship a custom pricing screen. (KitPricingCard / KitFeatureRow exist for other upsell UIs you might build — they are not the paywall.)

Turning it on + going live

/kit-setup-paywall

This sets the config above, pastes your API key, and uncomments the com.android.vending.BILLING permission in the manifest (a free app keeps it commented).

Real purchases need a few dashboard-side pieces — products, an offering, and the RevenueCat↔Play link — plus some lead time (~36 h for the service-account link, and a build on an internal testing track). The paywall renders before all that is done; it just can't complete a real purchase yet.

→ Full setup, billing, testing + troubleshooting: Paywall & Subscriptions.

For a free app, /kit-start-setup sets PAYWALL_ENABLED = false and the screen never appears. The paywall talks to PurchaseManager — see Backend.