I Built a RevenueCat Paywall That Doesn’t Hold the First Lesson Hostage

I Built a RevenueCat Paywall That Doesn’t Hold the First Lesson Hostage

The technical part of adding a subscription is only half the work. The uncomfortable part is deciding what the user is actually paying for. Slovo teaches Russian through one daily word, spaced review, widgets, pronunciation, and short reading. Its entire philosophy is low pressure. An aggressive paywall after a six-step onboarding would contradict that philosophy before the learner experienced a single useful moment. So I chose a constraint for the first version: The initial paywall can be dismissed, and the free daily word must remain genuinely useful. Premium is not permission to find out what Slovo does. It is access to the broader system that makes the habit deeper and more continuous. RevenueCat as the Subscription Source of Truth Slovo uses a single premium entitlement. The app configures RevenueCat, requests CustomerInfo, and maps the entitlement state into three useful product states: free; active trial; and premium. The core check is deliberately small: guard let entitlement = customerInfo.entitlements["premium"] else { isPremium = false isTrialActive = false return } isPremium = entitlement.isActive isTrialActive = entitlement.isActive && entitlement.periodType == .trial That state gates premium surfaces throughout the app. It also lets Slovo schedule or cancel a trial-ending reminder and publish a coarse subscriber_status tag for retention messaging. I avoid using a locally stored “purchased” Boolean as authority. Local state is useful for UI continuity, but RevenueCat’s customer information decides access. Why the Paywall Is Custom Slovo has a distinct visual language: warm paper, dark editorial type, a red accent, rounded cards, and an animated bird mascot. A generic commerce screen felt detached from the learning experience. The custom SwiftUI paywall still reads the current RevenueCat offering. It does not hard-code a display price as the source of truth. It: loads available packages from the current offering; displays the localized StoreKit price; identifies introductory trial information; lets the user select monthly or annual access; calls RevenueCat to purchase the selected package; and provides Restore Purchases, Terms, and Privacy links. The current US configuration is $4.99 monthly and $29.99 annually, with a three-day introductory trial on the annual product. Those are the App Store Connect values at the time of writing, not universal prices; RevenueCat and StoreKit provide the localized value shown to each user. The $79.99 Price That Was Not My Price One simulator displayed $79.99 for the annual plan while App Store Connect showed the correct $29.99. That created an immediate temptation: patch the UI string so the paywall “looked right.” That would have hidden the symptom and made the architecture worse. Subscription prices can come from different environments: a local StoreKit configuration; App Store Connect sandbox metadata; cached simulator storefront data; or a live App Store product. The correct response was to verify the product identifier, offering/package mapping, StoreKit configuration, sandbox account/storefront, and live App Store Connect price—not override the returned value with a marketing string. The lesson is simple: when testing commerce, first identify which store environment is speaking. Purchase, Cancellation, and Restore Are Different Outcomes The purchase method returns success only after the premium entitlement becomes active. A user cancellation is not shown as an error. let result = try await Purchases.shared.purchase(package: package) guard !result.userCancelled else { return false } apply(customerInfo: result.customerInfo) return isPremium Restore follows the same rule: fetch restored customer information, apply it, then evaluate the entitlement. These details matter because subscription UI often treats every non-success state as “something broke.” Cancellation is a valid user choice. Restore is a primary path for an existing customer, not a footnote added for App Review. What the Free/Paid Boundary Is Testing The first version is testing a specific packaging hypothesis: Free: experience the daily ritual and understand Slovo’s teaching style. Premium: use the complete retention system—deeper review, reading, audio, widgets, and continuing practice features. The annual package is meant for learners choosing a habit, while monthly access reduces the commitment required to explore premium. This is a reasonable hypothesis. It is not yet a result. For Shipaton’s HAMM category, a polished paywall is not enough. I still need to measure: onboarding completion; paywall views; dismissals; trial starts; purchases; restores; monthly vs annual selection; and conversion and retention over time. Slovo currently has a privacy-safe local event vocabulary for key milestones. The next step is connecting those events to a reliable analysis workflow and RevenueCat’s dashboard data. The Experiment I Want to Run The first meaningful paywall experiment will not be a button-color test. I want to compare two value explanations: Feature framing: unlimited vocabulary, reading, audio, reviews, and widgets. Outcome framing: remember useful Russian with one daily lesson and reviews timed before forgetting. The packages and price remain unchanged. The variable is whether the paywall explains inventory or the learning system. My prediction is that outcome framing will create more annual trials because it connects the subscription to a long-term habit. The honest answer will come from conversion data, not preference. What I Learned RevenueCat made the mechanics—offerings, entitlement state, purchase, trial detection, and restore—much smaller than implementing the same system directly across StoreKit edge cases. That did not make monetization automatic. It made the product decisions more visible. The difficult questions remain mine: Has the user received enough value before the paywall? Is premium coherent with the product’s promise? Are monthly and annual packages serving different needs? Does the trial provide enough time to experience the review loop? What evidence would make me change the packaging? My goal is not to build the most restrictive paywall. It is to build a subscription that feels like a reasonable continuation of the first useful minute.

Original Source

Read the full article at Hackernoon →

KhanList aggregates and links to publicly available news content. We do not host full articles from third-party sources. Always verify important information with original sources.