Implementing Hard Paywall (No Skip Option) in Mobile Application
Hard paywall blocks content or features without payment, no skip option. Most aggressive but, correctly applied, most converting model. Main mistake: violate App Store rules or create UX where user feels deceived.
App Store Rules for Hard Paywall
Apple scrutinizes hard paywall on review. 3.1.1 rejection happens if:
- App doesn't work at all without purchase, but description doesn't explicitly state it's paid.
- User can't tap anything without subscription (even "See pricing" or "Log in").
- Hard paywall shows immediately on first launch without demonstrating minimum value.
Permitted schemes with hard paywall: onboarding shows key features → paywall. Or: trial period (3–7 days free) → hard paywall when expires. App description explicitly states subscription-based.
Onboarding + Hard Paywall as Funnel
Standard conversion scheme:
- Onboarding (2–4 screens)—demonstrate value via concrete features, not abstract promises.
- Personalization step—questions on user goal (genre for reader, workout goal for fitness). Answers don't necessarily affect algorithm—important is psychological investment (user invested, harder to leave).
- Hard Paywall—after user "configured" product for themselves.
On client: OnboardingCoordinator manages steps, PaywallCoordinator—final onboarding step. After successful purchase—navigation to main screen without paywall return option.
Hard Paywall Required Elements
Restore Purchases—mandatory. User reinstalled app—must restore subscription. AppStore.sync() (StoreKit 2) or BillingClient.queryPurchasesAsync() (Android) for restoration. Without—App Store rejection, angry reviews.
SKPaymentQueue.canMakePayments() check before paywall—some devices (corporate MDM profiles, Screen Time limits) have IAP blocked. If canMakePayments == false—show explanation, don't crash.
Terms of Service / Privacy Policy links—bottom in small font, but accessible. For subscription apps: explicitly state amount, period, auto-renewal condition in CTA button or nearby: "7 days free, then $9.99/month, cancel anytime".
Navigation Blocking
Hard paywall shouldn't be bypassed via back gesture or physical back button. iOS: UIViewController.isModalInPresentation = true forbids swipe-to-dismiss for .pageSheet / .formSheet. Full-screen—back gesture unavailable by default. Android: override onBackPressed() / BackHandler (Compose)—either do nothing or show confirmation "Sure? App unavailable without subscription".
In NavigationStack (SwiftUI) or NavHost (Compose)—paywall screen has no NavigationBarBackButton and isn't in standard stack, presented modally over.
Introductory Offer
Hard paywall with trial converts better than without—doesn't mean trial always needed. For utilitarian apps (calculators, tools)—trial-less hard paywall works. For lifestyle/habit/health—trial necessary, user must verify value.
StoreKit 2 product.subscription?.introductoryOffer—show only eligible users. isEligibleForIntroOffer—async check, do at product prefetch, cache.
Analytics
Key events for hard paywall: paywall_shown, paywall_purchase_started, paywall_purchase_success, paywall_purchase_failed, paywall_restore_tapped, paywall_restore_success. Foundation for monetization health monitoring. Drop between purchase_started and purchase_success >20%—billing issue, investigate.
Timeline Estimates
Hard paywall with full StoreKit 2 / Play Billing flow, restore, introductory offer, event analytics, navigation blocking: 2–3 working days. With custom onboarding funnel—plus 3–5 days for onboarding screens.







