paywall-conversion-flow
Skill1 starsChanged 26 days agoBSD-3-ClauseView on GitHub
Designs value-first onboarding and paywalls that convert in freemium Flutter, native Swift or native Kotlin apps. Use when adding or auditing IAP, StoreKit, Play Billing, RevenueCat paywalls, free trial flows or onboarding screens.
In this repository52 other files it gives its agents.
- academic-research-assistantSkill
- answer-sheetSkill
- app-graphicsSkill
- app-landing-pageSkill
- app-screenshotsSkill
- break-uiSkill
- consumer-app-from-behaviorSkill
- cross-language-safetySkill
- dart-tool-scriptsSkill
- decision-sweepSkill
- engineering-diarySkill
- figma-review-loopSkill
- flutter-app-size-auditSkill
- flutter-async-at-the-edgeSkill
- flutter-async-cubit-safetySkill
- flutter-bloc-clean-architectureSkill
- flutter-clean-architecture-tddSkill
- flutter-cubit-smart-cachingSkill
- flutter-error-logging-conventionsSkill
- flutter-observability-instrumentationSkill
- flutter-paywall-and-review-timingSkill
- flutter-precommit-cleanupSkill
- flutter-router-decisionSkill
- flutter-runtime-safetySkill
- flutter-shorebird-otaSkill
- flutter-stream-architectureSkill
- flutter-strict-analysisSkill
- flutter-web-first-paintSkill
- forced-pivot-15-daySkill
- gplay-consoleSkill
- ios-distribution-feature-flagsSkill
- launch-readinessSkill
- launch-watchSkill
- locale-expert-reviewSkill
- market-pulseSkill
- mobile-ui-referenceSkill
- moscow-prioritizationSkill
- orchestrate-agentic-engineeringSkill
- parallel-agent-inboxSkill
- paywall-transparencySkill
- proactive-crash-repair-loopSkill
- promise-auditSkill
- pr-preview-shippingSkill
- ship-first-dollar-appSkill
- slim-ios-simulator-fleetSkill
- spec-sql-harnessSkill
- store-launch-mastermindSkill
- sync-contextSkill
- task-blitzSkill
- techdebtSkill
- vendor-decisionSkill
- web-interface-reviewSkill
The file
Show its rules and text
We split this skill into the rules it gives an agent
57 rules. About 0 are common, 48 are distinctive, and 9 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈48
Distinctive · estimate
This author's own choices. Worth a look.
9
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 23
Hard paywall AFTER a success event: - never on launch, never on tab switch.
- Distinctive: line 37
After a freemium app moved to a hard paywall with a 2 week trial, the headline table showed onboarding to trial start rising from 7.4% to …
- Distinctive: line 39
Read a trial change in four columns per weekly cohort: trials, paid, cancelled and still in trial.
- Distinctive: line 41
Do not read a cohort as final before the trial length has passed, and for a 2 week trial that is about two weeks after the cohort week ends …
- Distinctive: line 42
Keep one change per test window, because the same app was also running a higher price test for about two weeks and the author's later rows …
- Distinctive: line 43
Ask for price and revenue per onboarding as well, because trial start rate and paid rate can move in different directions.
- Distinctive: line 44
Do not quote the example as a benchmark.
- Distinctive: line 46
When a ladder mixes a free trial, a paid introductory offer and a no-trial plan, record which products share a group.
- Very specific: line 47
Check eligibility before showing the offer (StoreKit 2 isEligibleForIntroOffer) and show no trial CTA to an ineligible user, since that …
- Distinctive: line 52
If you test such a pair, say on the badge what the saving is compared with, and read paid conversion per paywall viewer and refund rate for …
- Distinctive: line 61
Treat both as hypotheses to A/B test, not defaults.
- Distinctive: line 63
Write the annualized weekly cost in the test notes, since $9.99 per week is $519.48 per year, 13 times the $39.99 yearly plan (arithmetic).
- Distinctive: line 65
Treat it as one datapoint, not a price benchmark.
- Distinctive: line 71
If you test it, show the $6.99 price at a size and contrast next to the $0.99, read refund rate and revenue per paywall viewer at week 8, …
- Distinctive: line 82
Use the same habit for any extra paywall surface, such as a second paywall after the user dismisses the first one in onboarding, or an …
- Distinctive: line 86
Never mention it in What's New, because that text is public and shows the offer to every user.
- Distinctive: line 89
Treat the list as a checklist of what to measure, not as evidence that each pays.
- Distinctive: line 102
If a tool triggers an offer from a RevenueCat webhook, choose the event on purpose.
- Distinctive: line 114
Treat it as a test design and read incremental revenue per eligible user, opt-out rate and OS-level notification disabling.
- Very specific: line 115
Keep every offer out of What's New, see asc-whats-new-writer.
- Distinctive: line 117
Test a paywall per traffic source only after attribution works.
- Very specific: line 121
Do not infer gender from ad copy, because Apple Ads age and gender targeting returns no attribution since September 2026 (see …
- Distinctive: line 127
Only the purchase plumbing changes.
- Distinctive: line 128
Do not add RevenueCat to a native app that has no third-party dependencies unless the user asks, because StoreKit 2 and Play Billing cover …
- Very specific: line 143
Test iOS purchases with a StoreKit configuration file in the scheme (simulator and Xcode runs) and with SKTestSession in unit tests.
- Distinctive: line 146
Test Android purchases from a Play-installed build on an internal test track with a license tester account.
- Very specific: line 150
Do not sell a Mac app distributed outside the App Store with StoreKit.
- Distinctive: line 166
Read the heuristic as a floor for suspicion, not a pass.
- Distinctive: line 168
Keep the list, as in Paywall transparency, and treat an outcome headline as an A/B test idea with no data behind it.
- Distinctive: line 171
Test the headline with the feature list kept below it, and judge it on paid conversion per paywall viewer.
- Distinctive: line 175
If you test it, keep the generic headline as the control, keep price, trial and plan lines the same in both arms, and read paid conversion …
- Distinctive: line 177
Write one phrase per goal option that reads well in the template, because the option label alone may not.
- Distinctive: line 179
Do not state a health or weight result as a promise, because Guideline 1.4.1 reviews medical apps that could give inaccurate information …
- Very specific: line 183
Create a custom variable such as goal_phrase with a default of the generic headline, write {{ custom.goal_phrase }} in the headline text, …
- Distinctive: line 186
When no value is passed, the editor default is shown, so a skipped goal falls back to the generic headline by itself (RevenueCat docs, read …
- Distinctive: line 200
Use quotes and ratings that can be shown to a regulator, and say where an invited review came from.
- Very specific: line 201
Check a rating badge on the paywall against the live store rating before release.
- Distinctive: line 241
Do not show a fabricated score or a fake loading analysis to drive a purchase.
- Distinctive: line 243
Treat that as a risk of a misleading claim (my inference) and keep the paywall honest about what unlocks.
- Distinctive: line 247
Treat signup as deferrable.
- Distinctive: line 271
After the plan decision, the same walk showed:
- Distinctive: line 281
If your onboarding builds something before the account step, decide on purpose what happens to it when the user signs in to an older …
- Distinctive: line 285
Use a fresh account, because signing in to one that already pays or has a trial skips the paywall, and say when the device's store account …
- Distinctive: line 292
Treat the first onboarding as hypothesis one and chart the funnel by cohort: onboarding start, abandonment screen, paywall reached, trial …
- Distinctive: line 298
Before reading any paywall result, trigger each placement on a test device and confirm its event reaches the analytics log with a nonzero …
- Distinctive: line 302
Keep trial starts on a separate line and never count them as paid.
- Distinctive: line 303
Keep trial starts, trial conversions (the first paid renewal after a trial) and paid introductory offer starts (pay up front or pay as you …
- Distinctive: line 307
Read active trials and new trial starts next to revenue.
- Distinctive: line 312
Never report a partial-week point as a result.
- Distinctive: line 315
When a founder reports a one-day jump, attribute it from that day's transaction list.
- Distinctive: line 316
Read each row's product, price and type (new subscription, trial start, trial conversion, cancelled trial), and add the rows to the day …
- Distinctive: line 324
Check it with a calculator before quoting it.
- Distinctive: line 325
Before changing a price because conversion is low, split paywall conversion by acquisition source (each ad creative, organic post, search, …
- Distinctive: line 326
If one source converts far better than another at the same price, price is not the first suspect.
- Very specific: line 332
Use CANCELLATION with cancel_reason UNSUBSCRIBE ("fires when a user unsubscribes, not when the subscription expires") for a user who turned …
- Distinctive: line 335
Treat a vendor's test list as a backlog and not as evidence.
- Very specific: line 340
Test the price and the annual discount rate separately from the plan layout, and test the main storefronts, because the list says Apple's …
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Paywall Conversion Flow
The single biggest lever in a freemium app is the first 30 seconds and the placement of the paywall. Most indies lose conversion by following the wrong order.
The Order That Works
- Show value before asking for anything. Skip the tutorial. Drop the user into a working "test project" or pre-filled state so they feel a win in <30s.
- Ask for a rating after a win in the main app, never during onboarding and not on the way to the paywall. The rule, Apple's caps and the rejection risk are in Flutter paywall and review timing. One founder (X post, October 2026, unverified) reports a rating screen as the last onboarding step before the paywall, with 50 ratings and 4.3 stars in 4 weeks. His 5 of 62 viewers (8.1%) before and 45 of about 440 (10.2%) after a popup delay change are my recomputation and sit within noise. A first-hand reply reports that App Review rejected a similar screen. He says none of the 5 one-star raters he tracked subscribed, but Apple never reveals who rated, so any claim about raters needs another method. Judge the placement by paid conversion, not by rating count.
- Hard paywall AFTER a success event - never on launch, never on tab switch. Wait for: streak day 3, first export, first AI generation, first item saved.
- Free trial requires card on file. It removes freeloaders and raises trial-to-paid conversion.
In First Page Sage's SaaS benchmark (86 companies, 2022-2025), card-required trials converted 48.8% to paid vs 18.2% for cardless, but visitor-to-trial fell from 8.5% to 2.5%, so judge the whole funnel, not trial-to-paid alone.
Make the cancel path easy to keep ratings intact.
Google Play already verifies a valid payment method before a store free trial starts, so a cardless trial only exists outside store billing.
One planner does exactly that: closing its paywall offers 3 free days granted by its own server, with no payment details (walked 2026-10-30, see the Onboarding flow reference below).
Judge a trial by paid conversion, not trial-start rate.
RevenueCat's State of Subscription Apps 2026 (metrics for 2025, read 2026-10-24) reports median trial-to-paid conversion of 25.5% for trials of 4 days or less, 37.4% for 5 to 9 days and 42.5% for 17 to 32 days.
It also reports that 55% of 3-day trial cancellations happen on Day 0, and that 84% of 3-day and 64% of 7-day trial cancellations happen by Day 1.
These medians compare different apps, so they are a reason to test a longer trial and not the lift to expect.
Change the trial length alone and write the date in the test notes, because a longer trial delays the first conversions by the length difference (inference), which makes the next days look slow.
One indie fasting app in October 2026 reported a 20% trial-start week with zero trials converting, while its no-trial weeks reached 12-19% paid, on samples in the tens.
The founder's own explanation, which they did not test, is that paid ads optimized on trial starts find users who start trials and never pay.
A second example runs the other way and shows the same trap (one indie app, X posts of 2026-09-26 and 2026-10-29, the author's own tables, unverified).
After a freemium app moved to a hard paywall with a 2 week trial, the headline table showed onboarding to trial start rising from 7.4% to 19.6% to 24.6%, with no price or revenue.
A second table, which only came on request, showed trial to paid at 44% and 41% for the first two cohorts and 24% of finished trials for the third (8 paid, 26 cancelled, 9 still in trial), with the last two cohorts marked too early.
Read a trial change in four columns per weekly cohort: trials, paid, cancelled and still in trial.
For a cohort with trials still open, report paid over all trials as the floor and paid plus still in trial over all trials as the ceiling, so 8 over 43 is 19% and 17 over 43 is 40% (arithmetic).
Do not read a cohort as final before the trial length has passed, and for a 2 week trial that is about two weeks after the cohort week ends (inference, not documented by Apple).
Keep one change per test window, because the same app was also running a higher price test for about two weeks and the author's later rows cannot separate the two.
Ask for price and revenue per onboarding as well, because trial start rate and paid rate can move in different directions.
Do not quote the example as a benchmark.
Apple allows one introductory offer per person per subscription group.
When a ladder mixes a free trial, a paid introductory offer and a no-trial plan, record which products share a group.
Check eligibility before showing the offer (StoreKit 2
isEligibleForIntroOffer) and show no trial CTA to an ineligible user, since that repeats a misleading claim under Guideline 3.1.2. Apple's page does not state what happens to a user who bought another product in the group at full price, so do not assume either way (Apple help page, read 2026-10-20). One observed paywall (Liftoff, screen recording, X post 2026-10-23, no results reported) offers a free 7-day trial and a 30-day pay-up-front introductory offer at 2.99 EUR side by side, both renewing at 79.99 EUR a year. A product has one current introductory offer per storefront, so such a pair is most likely two products (inference), and the subscription groups were not visible. Its "SAVE 55%" badge matches the first month against the annual price per month, which the screen does not say. If you test such a pair, say on the badge what the saving is compared with, and read paid conversion per paywall viewer and refund rate for both plans. In one founder's transaction lists (single report, October 2026, two screenshots), 4 of 7 visible trial rows carry a cancelled badge within hours of starting. The sample is tiny and the badge meaning is unverified, so use it only as a reason to read the cancel timing column before judging a trial. - Offer weekly + yearly, not just monthly. Weekly lowers commitment fear and converts the "let me test it" segment that monthly scares off. One operator's recipe (X post, October 2026, unverified, no conversion, refund or revenue figure given) pairs one trial with one no-trial plan in two ladders. Ladder A is yearly at $39.99 with a free 3 day trial plus a weekly plan with no trial. Ladder B is weekly at $9.99 with a free 7 day trial plus a yearly plan with no trial. The post does not define "direct", so the no-trial reading is an inference, and it names no weekly price for A or yearly price for B. Apple permits both trial lengths (Apple help page, read 2026-10-20). Treat both as hypotheses to A/B test, not defaults. Judge each on paid conversion per paywall viewer, refund rate and revenue per viewer after the first renewal, not on trial starts. Write the annualized weekly cost in the test notes, since $9.99 per week is $519.48 per year, 13 times the $39.99 yearly plan (arithmetic). One indie (single report, October 2026, a month of data, one screenshot) runs $5 per week and $49.99 per year, both with free trials, and a $24.99 yearly exit offer that is inferred from the product list. Treat it as one datapoint, not a price benchmark. A third operator recipe (X post by @ChadAppDev, 2026-10-24, unverified, no conversion, refund or revenue figure given) pairs $39.99 per year with $6.99 per week and a $0.99 first week, on a hard paywall. The author calls the $0.99 week a trial, but it fits Apple's pay as you go introductory offer type (inference from the offer types page). They say users "forget to cancel at roughly the same rate as free trials" and that "in just 6 weeks" they pay more than the yearly price, and they give no data for either. The break-even claim is one week early: 6 weeks cost $0.99 plus 5 times $6.99, which is $35.94, and 7 weeks cost $42.93 (arithmetic), before Apple's commission and any refund. $6.99 per week is $363.48 per year, about 9.1 times the $39.99 yearly plan (arithmetic), just under the 10 times heuristic in the anti-patterns. If you test it, show the $6.99 price at a size and contrast next to the $0.99, read refund rate and revenue per paywall viewer at week 8, and judge it against a free-trial ladder on the same traffic.
- Add one exit offer after the buyer cancels the store purchase sheet.
Superwall's
transaction_abandonplacement fires when a user dismisses the store purchase sheet before the transaction completes, and a matching paywall replaces the current one. RevenueCat's closest feature is Exit offers, which show a second paywall when the user dismisses the paywall without buying. Its docs do not say it fires on a cancelled purchase sheet, and it works only withpresentPaywallorpresentPaywallIfNeeded, so it is not shown to be equivalent. One indie fasting app shows a single discounted yearly plan with a close button, a 5 minute timer and the real billed price, and its author reported that the exit paywall produced 23% of its results over two weeks (author's figure, unit not stated, not verified). A second founder adds the offer in a follow-up release, after the base paywall is live. Ship it in a reviewed update, describe it in Notes for Review, and measure it on its own line so the base paywall rate stays clean. One indie article (2026-08-09, single source, unverified) gives the reason: reviewers judge a transaction abandon offer subjectively, and a first submission with a contested feature may go to a slower review track. Apple publishes no review tiers (Apple App Review page, read 2026-10-25), so treat the tier claim as a guess. The part that matches Apple's text is to describe the offer in the notes, because Guideline 2.3.1(a) requires new features to be described with specificity. Use the same habit for any extra paywall surface, such as a second paywall after the user dismisses the first one in onboarding, or an offer when the user closes the paywall. One founder calls these grey areas that depend on the reviewer, and says to name them in the review notes and get explicit approval (X article, 2026-10-25, no review outcome shown). The rule behind it is Guideline 2.3.1(a), so the notes say when the surface appears, what it offers and how to reach it with a demo account. Tag its events with aplacementproperty, see Flutter observability instrumentation. Never mention it in What's New, because that text is public and shows the offer to every user. - After the first purchase and after a lapse, sequence offers by user state, and test each as its own line.
One LinkedIn post (October 2026, unsourced, no data) lists five add-ons to onboarding and a paywall for larger apps: an upsell to new subscribers, a downsell to users who declined, email follow-up for non-purchasers, a retention offer when a subscriber leaves, and a win-back offer after a lapse.
Treat the list as a checklist of what to measure, not as evidence that each pays.
The same post says "up to 10% resubscribe within a year", with no source, so do not plan on it.
Apple's offer types, eligibility and limits are in subscription offers.
- Win-back on iOS: use Apple's win-back offer, not a custom price.
It is per product, needs a subscription approved by App Review, and is for churned subscribers only (
expirationDatein the past andwillAutoRenewfalse). Set Minimum Paid Duration, Time Since Last Subscribed (1 to 24 months) and Wait Between Offers (2 to 24 months) deliberately, and write the chosen window in the test notes, because the post's "3-6 months" is a guess. - Retention offer for a subscriber who turned auto-renew off on iOS: use a promotional offer.
Apple deems anyone with an existing or expired subscription in the app eligible, and you add your own criteria.
Listen for the
DID_CHANGE_RENEWAL_STATUSserver notification, let the server decide eligibility and tell the app to show the offer. Redeeming needs a server-generated signature, and it works on iOS 12.2 and later. - Downsell for a user who never subscribed: a promotional or win-back offer is not available to that user, so use a separate cheaper product or an offer code, and give it its own
placementvalue. - Pause: Google Play lists pause as a subscriber action. The Apple pages read describe no pause, so do not promise one on iOS.
- If a tool triggers an offer from a RevenueCat webhook, choose the event on purpose.
RevenueCat defines
CANCELLATIONas "A subscription or non-renewing purchase was canceled or refunded" andEXPIRATIONas "A subscription has expired", where "The associated user's access should be removed" (event types page, read 2026-10-25). A discount sent seconds afterCANCELLATION, as one founder's flow does with a 30 second wait, reaches a subscriber who still has access, and a refund of the latest period also firesCANCELLATION, so filter refunds out. Send a win-back only afterEXPIRATION, and send a retention offer after a cancel only if it is a promotional offer that Apple allows for that user. Show the post-offer price and renewal date as for any trial, see Paywall transparency. - Email follow-up needs an address, so decide where it is collected, and see
launch-watchfor EU consent and an unsubscribe link before the first send. - Push follow-up to a user who did not subscribe is direct marketing. Guideline 4.5.4 allows push for promotions or direct marketing only after customers have explicitly opted in "via consent language displayed in your app's UI", and you must give an in-app way to opt out (App Review Guidelines, read 2026-10-25). The system permission prompt alone is not app consent language (inference), so ask for marketing consent on its own screen before sending an offer. Guideline 5.1.2(i) bars requiring push notifications, location or tracking to use the app. Apple sets no cap on sends per week, and "1-2 a week" in one X article (2026-10-25) is the author's guess, so set a cap and measure opt-outs.
- One founder suggests testing a first push 5 minutes after the app closes without a subscription, then a second 4 days later if the user still has not subscribed (X article, no result reported). Treat it as a test design and read incremental revenue per eligible user, opt-out rate and OS-level notification disabling.
- Keep every offer out of What's New, see
asc-whats-new-writer. - Judge each stage by incremental revenue per eligible user, refund rate and churn, not by redemptions.
- Test a paywall per traffic source only after attribution works.
One founder routes one ad to a dark mode paywall aimed at men and another to a light mode paywall aimed at women, both at $7.99 per week, and reports no result (X article, 2026-10-25).
Change only the creative that matches the ad's promise (headline, image, order of benefits) and keep price, trial and disclosure the same on every variant, so the test reads copy and not price.
Judge each variant by paid conversion per paywall viewer on its own traffic, with the default paywall as the control.
Do not infer gender from ad copy, because Apple Ads age and gender targeting returns no attribution since September 2026 (see
ship-first-dollar-app/references/apple-ads.md), so build variants on the ad's topic. Tracking a user across an ad network for this needs the App Tracking Transparency prompt under Guideline 5.1.2.
- Win-back on iOS: use Apple's win-back offer, not a custom price.
It is per product, needs a subscription approved by App Review, and is for churned subscribers only (
Native Swift and Kotlin implementation
The order, copy and tests above do not depend on Flutter. Only the purchase plumbing changes. Do not add RevenueCat to a native app that has no third-party dependencies unless the user asks, because StoreKit 2 and Play Billing cover purchase, restore and entitlement checks.
| Need | Flutter in_app_purchase | Native iOS (StoreKit 2) | Native Android (Play Billing) |
| Load products | queryProductDetails | Product.products(for: ids) | BillingClient.queryProductDetailsAsync |
| Buy | buyNonConsumable | try await product.purchase() and handle .success, .userCancelled, .pending | launchBillingFlow with the chosen offer token |
| Live updates and renewals | purchaseStream | for await over Transaction.updates, started at launch | PurchasesUpdatedListener |
| Current entitlement | verify and deliver | Transaction.currentEntitlements, verified results only | queryPurchasesAsync at startup |
| Finish the purchase | completePurchase | await transaction.finish() after delivering | acknowledgePurchase or consumeAsync within 3 days, or Play refunds |
| Restore | restorePurchases() | try await AppStore.sync() behind a visible Restore button | queryPurchasesAsync, no separate store call |
| Trial eligibility | store response | product.subscription?.isEligibleForIntroOffer | offers returned for the user in ProductDetails, show only what is returned |
| Manage or cancel | store link | .manageSubscriptionsSheet(isPresented:) or AppStore.showManageSubscriptions(in:) | deep link to Play subscription management |
- SwiftUI can use
SubscriptionStoreVieworStoreViewfor a standard paywall. A custom paywall needs the price, period, trial end date and Restore control from the audit checklist. - Test iOS purchases with a StoreKit configuration file in the scheme (simulator and Xcode runs) and with
SKTestSessionin unit tests. Sandbox and TestFlight tests need the products in App Store Connect. Manage them with theasc-*skills. - Test Android purchases from a Play-installed build on an internal test track with a license tester account. Billing does not work from a sideloaded debug APK.
- A one-time unlock is a non-consumable on both stores. The free-versus-paid check is an entitlement read at launch, not a stored flag.
- Do not sell a Mac app distributed outside the App Store with StoreKit.
Licensing and trials for it are in
macos-direct-sales, and the web checkout route is inapp-to-web-checkout. - The paywall schedule and review prompt timing code is in Flutter paywall and review timing, which has Swift and Kotlin versions.
Anti-patterns to remove
- Paywall on cold launch.
- "Subscribe to continue" gate before any value is delivered.
- Tutorial screens explaining features (vs showing outcomes). This applies before the paywall. Whether a guided tour for someone who has already paid helps is a separate question, and this file holds no test result for it.
- Yearly-only pricing with no escape hatch for low-trust buyers.
- A weekly plan whose annualized price is above about 10 times the yearly price as the headline plan (my heuristic, not from Apple or any source). If you test it, show the weekly price, the billing period and the trial end date, and describe what the user gets for the price, as Guideline 3.1.2(c) requires. The $6.99 weekly and $39.99 yearly pair on one founder's X paywall is 9.1 times, so a 10 times line would not flag it (arithmetic). The $5.99 weekly and $29.99 yearly pair on one indie's paywall is 10.4 times (312.34/29.99, arithmetic), so a 10 times line flags it, while a $6.99 and $39.99 pair is 9.1 times and does not. That author reports weekly $5.99 to $7.99 and yearly $29.99 to $59.99 with no conversion figure (X article, 2026-04-18, single report). Read the heuristic as a floor for suspicion, not a pass.
- Replacing the concrete feature list with an outcome headline as the default. Keep the list, as in Paywall transparency, and treat an outcome headline as an A/B test idea with no data behind it. One founder (X post, October 2026) says selling the result instead of listing features raised conversion "immediately", with no figure or sample size. A reply gives one example, "on-device AI reads your receipt" becoming "you're in the shop, do you still have milk?", also with no data. Test the headline with the feature list kept below it, and judge it on paid conversion per paywall viewer. A second founder (X post, 2026-11-06) says a paywall headline built from the goal the user tapped in onboarding doubled conversion from 5% to 10%, for example "Start losing weight today" after the goal "lose weight". In a reply, the founder says it ran for some weeks over more than 1,000 customers or views and that the goal line was the only change, and gives no arm sizes, no metric definition and no retention figure (single report, unverified). A reply asks whether buyers on the new headline stayed as long, and no answer was captured. If you test it, keep the generic headline as the control, keep price, trial and plan lines the same in both arms, and read paid conversion per paywall viewer, then refund rate and first renewal rate by arm.
- A goal-driven headline needs three decisions before it ships. Write one phrase per goal option that reads well in the template, because the option label alone may not. Decide what shows when the user skipped the step, picked several goals or picked "other", and use the generic headline for all three. Do not state a health or weight result as a promise, because Guideline 1.4.1 reviews medical apps that could give inaccurate information with greater scrutiny, and a call to start ("Start ... today") is safer than a result (inference).
- A goal the user tapped in your own onboarding may drive your own paywall copy, but data from HealthKit or another health source may not be used for marketing under Guideline 5.1.3(i), and Guideline 5.1.2(ii) says data collected for one purpose "may not be repurposed without further consent".
Say in the privacy policy that onboarding answers personalise the app, and check the wording with
promise-audit(the guideline text does not settle whether this counts as repurposing, so this is a precaution). - RevenueCat Paywalls can fill the line at runtime.
Create a custom variable such as
goal_phrasewith a default of the generic headline, write{{ custom.goal_phrase }}in the headline text, and pass the value when the paywall is shown. In Flutter that iscustomVariables: {'goal_phrase': CustomVariableValue.string(phrase)}onRevenueCatUI.presentPaywall(...)orPaywallView(...), which needspurchases_ui_flutter9.12.0 or later. In SwiftUI it is.customPaywallVariables(["goal_phrase": .string(phrase)]). When no value is passed, the editor default is shown, so a skipped goal falls back to the generic headline by itself (RevenueCat docs, read 2026-11-07). The pages read give no minimum SDK version for iOS, so check the changelog before relying on it. RevenueCat Experiments can test paywall copy and is limited to Pro and Enterprise plans, and the pages read do not say how to split by a runtime variable, so the simplest control is two offerings, one with the variable and one without (inference, not tested). - Paragraphs on the paywall. Keep each plan to a price, a period and one concrete line.
- Abstract value claims. Anchor the price to something real instead ("€49 is three takeaways").
- Fake countdowns or a price that only appears after tapping.
- A one-time offer whose claims are not true. A countdown offer is legitimate only when the shown state persists so the offer never reappears for that user, the timer does not reset on reopen or relaunch, and claims such as "lowest price we've offered" are true for that storefront's price history. In the EU, Annex I point 7 of the Unfair Commercial Practices Directive (2005/29/EC) bans in all circumstances, with no harm test, falsely stating that a product will only be available for a very limited time in order to elicit an immediate decision.
- A discount, countdown or other promotion in a Live Activity. Apple's Human Interface Guidelines say "Don't use a Live Activity to display ads or promotions" (read 2026-10-25), and Guideline 4.5.3 bars using Live Activities to spam or send unsolicited messages. One reply says big apps do it without consequence (single report), which shows uneven enforcement and is not permission.
- Social proof that is not real. In the US, 16 CFR 465.2 makes it an unfair or deceptive practice for a business to write, create or sell a consumer review or testimonial that materially misrepresents that the reviewer exists or used the product, and 465.4 bars compensation for reviews that express a particular sentiment (eCFR, read 2026-10-25). Apple's side is in Flutter paywall and review timing. Use quotes and ratings that can be shown to a regulator, and say where an invited review came from.
- Check a rating badge on the paywall against the live store rating before release.
The iTunes Search API returns it, for example https://itunes.apple.com/lookup?id=APP_ID&country=us, in
averageUserRatinganduserRatingCount(public JSON, a read-only request). One indie's paywall shows "4.7 App Store" while the US listing returned 4.41 from 17 ratings on 2026-11-06, and a second shows "4.9" against 4.69 from 202 ratings (the badges are from April 2026 screenshots, so the difference is a caveat and not proof). I found no Apple rule on rating badges, so reading a higher badge as misleading is an inference. Show the number from the store's data or write the date and storefront next to a fixed number.
Audit checklist (use before each release)
- First successful action happens within 30 seconds.
- Rating prompt fires after a clear win in the main app, never during onboarding and not before the paywall (see Flutter paywall and review timing).
- Paywall fires after a success event, not on launch.
- Plans visible: Weekly, Yearly, Lifetime (if applicable).
- Free trial CTA prominent; cancel path documented in-app.
- Native iOS:
Transaction.updatesis listened to at launch and every transaction is finished after delivery. - Native Android: purchases are acknowledged within 3 days and
queryPurchasesAsyncruns at startup. - Restore Purchases link is on the paywall (App Review Guideline 3.1.1 requires a restore mechanism for restorable purchases, and the paywall placement builds trust).
- The paywall fits the smallest and the largest phone you support and an iPad, and a long paywall keeps its main button visible while scrolling (a vendor list of 101 paywall tests, Helium X article of 2026-08-17, items 7, 24 and 25, unsourced advice with no measured effect, but each is a layout failure you can see on a device).
- While the purchase call is awaiting the store, the screen shows progress and the close control is disabled, and both return on any result, including
.pending(Ask to Buy or a payment that needs approval), because a pending purchase can stay unresolved for days and completes later throughTransaction.updatesorPurchasesUpdatedListener. The disabled close applies only to the window between the tap and the call returning (my reading of item 6 in the same list, an inference), because disabling close until a pending purchase resolves would lock the user out.
Onboarding flow reference
A high-performing onboarding structure to pair with the order above:
- Value screens or an instant first win, with progress indicators and Skip.
- Goal and motivation questions ("why are you here?", multi-select chips) so the experience feels tailored early. Store each answer so a later screen can use it. The paywall headline is one use (see the goal-driven headline test in the anti-patterns above), and the stored answer must tolerate multi-select and a skipped step.
- Personalized result, recommendations or community previews based on the answers.
- Optional account creation, one-tap social or pre-filled, with a visible Skip.
- Soft premium upgrade with clear benefits and trial (this is the "after value" slot from the order above).
- Celebration / "creating your space" animation → main app.
Apple's Human Interface Guidelines on onboarding (read 2026-10-23, last changed June 10, 2024) set the limits for this list. They say to design a flow that is "fast, fun, and optional", to "Teach through interactivity", and to "Postpone nonessential setup flows or customization steps" with reasonable defaults. They say to put a permission request inside onboarding only when the app needs that access before it can function, and otherwise to ask when the person first uses the feature that needs it. They say to let people experience the app before asking for a rating or a purchase. A concept mock or a design showcase is design evidence and not conversion evidence, so check a flow against shipped apps and measured results before copying it.
A result gated behind the paywall must come from the user's real input. Do not show a fabricated score or a fake loading analysis to drive a purchase. One founder (X post, October 2026, self-reported) describes a long analysis animation followed by "unlock your rating" and says the sunk cost of about 20 questions raises conversion. Treat that as a risk of a misleading claim (my inference) and keep the paywall honest about what unlocks. A positive example: one gym app (Liftoff, screen recording, X post 2026-10-23, no conversion figure) asks for one real input, shows the rank result free, and only then shows the paywall. Its timed "Compiling user profile" screen still falls under the fake-analysis rule above, because its real work is unknown.
Treat signup as deferrable. Duolingo's iOS onboarding grew from 6 screens in 2018 to 24 in 2023-2024 and 20 in 2026, observed by Zach Witzel (Helium) in dated screenshots from August 2026. Third-party teardowns describe its order as language, goal and motivation questions, then a first lesson, then signup. So Duolingo asks its questions before it delivers value, and it is no example of "value first". Duolingo's own word on this is a 2017 First Round Review interview, where Gina Gotthilf says moving the signup screen back "a few steps" raised daily active users by about 20%, without saying where it moved to. The 2025 and 2026 screenshots also show an add-widget step after the notification permission. Duolingo's own blog says only that it tested a widget promotion after learners finished a lesson. A reply on the post reports a 3-step full-screen paywall with a close button after the outcome-promise step, which is not in the screenshots and is unverified. None of this is published test data, and the flow may differ by cohort and date.
One planner walked end to end on a device (Ellie 4.2.0, iOS, Greek storefront, 2026-10-30, first-hand, one walk, no conversion data):
- Four questions come first: the user's role, what is going on for them, where they heard of the app, and, in the evening, whether to plan today or tomorrow. Each answer shows up on the next screen: the role picks the example tasks, and the hour picks the day.
- The user then types the one task for tomorrow and a few put-off ones, and sees their own day built from them before any request.
- Account creation follows with no skip, framed as keeping that work ("Save your day"), and the paywall comes after it.
- The paywall shows two plans, yearly preselected with "2 months free" and its monthly equivalent, one Subscribe button, and a line under it that restates the charge for the selected plan. The store's lifetime plan is not on it. Price objections are answered below the plans: a student discount and a short letter from the developer on why it costs what it does.
- A close button is there from the start. Closing offers 3 free days with nothing to pay and no payment details, after which the app turns view-only and keeps the user's tasks. The app has no free plan, so every path ends in a plan or view-only.
- The walk used an Apple ID that had already taken the app's store trial, so the paywall showed no trial line, and the close offer may be shown only to users who cannot get the store trial.
After the plan decision, the same walk showed:
- Starting the free days opens one screen that gives their exact end, date and time ("They end Monday, 2 Nov at 23:12.").
- The notification request comes next, after value and after the plan decision, never before the paywall. It is primed with a preview notification built from the user's own task ("Time for "Finish the Q4 plan"") and "Ellie can remind you when a task starts.", with "Turn on notifications" and "Not now".
- An optional calendar step follows (Apple, Google, Outlook, "You can do this later too", "Skip for now").
- The app opens on the user's own day with the onboarding task already in place, and each screen shows one coach mark on its first visit, closed with "Got it".
- During the free days, Settings shows a "3-Day Trial" badge and an upgrade row, and the account page repeats the end date, the no-charge sentence and "See plans".
- Log out and Delete account sit under the plans on the paywall itself.
- Signing in to an existing account dropped the tasks typed during onboarding, while a new account kept them. If your onboarding builds something before the account step, decide on purpose what happens to it when the user signs in to an older account.
To check a reference flow rather than its screenshots, walk it on a device and record per screen the exact copy, which answer reappears later, where the account and the paywall sit, which plan is preselected, what the trial line says, and what every exit does, including the close button and the links under the plans. A gallery shows screens, not what closing the paywall does. Use a fresh account, because signing in to one that already pays or has a trial skips the paywall, and say when the device's store account cannot get the trial.
Execution details that matter: always a visible Skip or back, pre-select popular options to cut decision fatigue, show real social-proof numbers, keep the whole flow under 30-45 seconds. Track onboarding completion rate, time to first meaningful action, day-1 retention, and first-session conversion.
One founder's numbers, from a single account (October 2026, a screenshot of $12,698 in 28-day revenue, unverified): 12-13 onboarding screens, a 90% completion target, and under 80% treated as a sign something is wrong. He does not say how completion is defined, and this is not a benchmark.
Treat the first onboarding as hypothesis one and chart the funnel by cohort: onboarding start, abandonment screen, paywall reached, trial started, paid. A promotional X article (October 2026, by the makers of an app builder) quotes Cal AI as having run 123 A/B experiments, 160 paywall designs, 424 variants and 61 onboarding paywall experiments, with monthly revenue up more than 3x and trial-to-paid up 31%. These are unverified secondhand figures, which the article itself marks "reportedly", so use them as a reported example and not as a benchmark.
Measure
- Before reading any paywall result, trigger each placement on a test device and confirm its event reaches the analytics log with a nonzero viewer count. A rate divided by zero viewers looks like a flat test. One reply on a founder's post (October 2026, single unverified anecdote) describes three tests run on an app whose paywall event never fired.
- Paid conversion is weekly unique buyers divided by unique paywall viewers.
- Keep trial starts on a separate line and never count them as paid.
- Keep trial starts, trial conversions (the first paid renewal after a trial) and paid introductory offer starts (pay up front or pay as you go) on three separate lines, and never add them together.
Report a paid introductory offer start as revenue, not as a trial conversion.
In RevenueCat webhooks they are
INITIAL_PURCHASEwithperiod_typeTRIAL,RENEWALwithis_trial_conversiontrue, andINITIAL_PURCHASEwithperiod_typeINTRO(event types page, read 2026-10-20). Dashboard labels such as "Trial Convert" and "Intro Offer Start" came from an unnamed tool in a source screenshot and are not RevenueCat event names, so map them to the documented fields before counting. - Read active trials and new trial starts next to revenue. Revenue on a given day mostly comes from trials started a trial-length earlier, so a rising revenue day with falling active trials predicts a weaker next week (inference from subscription arithmetic). One founder's Day 12 and Day 13 posts (October 2026, single report, screenshots not verified) show the lag: Day 13's whole $199.96 was four yearly trial conversions while active trials fell to 26.
- Bucket weekly when daily paywall views are under about 20, because daily rates are noise.
- Annotate every price, offer and onboarding change on the chart, and exclude the developer's own country or test devices.
- Never report a partial-week point as a result. One indie's chart headlined a dashed, incomplete week at 22.2%. An earlier capture of the same chart read 14.1% for its then-partial point against 12.2% once the week completed, an inference from two captures with unconfirmed week boundaries.
- When a founder reports a one-day jump, attribute it from that day's transaction list. Read each row's product, price and type (new subscription, trial start, trial conversion, cancelled trial), and add the rows to the day total before crediting a feature. A 28-day tile also moves when old days roll out of the window (unverified inference from the tile label, not checked against RevenueCat docs).
- Report a 95% interval with each rate. For example, 23 buyers out of 104 viewers is 22% with a range of about 15-31%.
- Fix the number of paywall viewers per arm before a test starts, and do not stop on a good-looking day, because stopping early produces false wins. At a two-sided 5% significance level and 80% power, a 5% baseline needs about 31,000 viewers per arm to detect a 10% relative lift, about 8,200 for 20% and about 1,500 for 50%. A 10% baseline needs about 14,800, 3,800 and 700. A small app cannot reach these numbers for small changes, so test large changes (price, offer, paywall position) and treat anything below the planned count as a direction, not a result. (Computed 2026-10-23 with the standard pooled two-proportion sample-size formula, not a tool's output.) Check it with a calculator before quoting it.
- Before changing a price because conversion is low, split paywall conversion by acquisition source (each ad creative, organic post, search, referral). If one source converts far better than another at the same price, price is not the first suspect. Change price and traffic source in different weeks, because changing both at once hides which one moved the number. Source: one founder's X post and two agreeing replies (October 2026, no data), so this is a cheap check and not a finding.
- Change trial length, the trial reminder and the paywall timeline in different releases too. One build-in-public founder shipped all three in one release, and a reply pointed out they could not tell which one reduced cancellations (single reply, no data).
- For a retention test, define "cancel" before the test starts.
Use
CANCELLATIONwithcancel_reasonUNSUBSCRIBE("fires when a user unsubscribes, not when the subscription expires") for a user who turned auto-renew off, and excludeCUSTOMER_SUPPORTandBILLING_ERROR, since refunds can fireCANCELLATIONwhile auto-renew is still on (RevenueCat event types page, read 2026-11-02). Compare the same weekly cohorts with and without the change, and read the paid-renewal rate at the first renewal, because a yearly plan shows its first real cancel decision a year later. A retention claim without a cohort, a plan length and a cancel definition is not a result. - Treat a vendor's test list as a backlog and not as evidence. One 101-item list (Helium, X article, 2026-08-17) gives no sample, period or revenue figure for any item, and its customer quotes are anonymous. Its numbers that you could be tempted to plan on are unsourced: "70-80%" of conversions through onboarding, "10-20%" from centering a paywall on a feature, and a customer test that "made more than 15-times Helium's costs". The only sourced onboarding timing figure in this file is RevenueCat's 50.6% of download-to-paid conversions on Day 0, and it measures something different.
- Price tests are the item that list stresses most.
Test the price and the annual discount rate separately from the plan layout, and test the main storefronts, because the list says Apple's default regional prices leave value on the table (unsourced).
Per-territory prices are set with
asc-ppp-pricing. Show a trial only to a user who is eligible, since Apple limits each person to one introductory offer per subscription group andisEligibleForIntroOfferalready returns that, so "remove the trial for existing users" is partly enforced by the store (the list's "existing users" is ambiguous). - Vary the CTA text and the testimonials by language and region (an unsourced idea from the same list), and have
translation-auditcheck each language so a test copy is not a machine translation drift.
When in doubt
Deliver the first win fast, then show the paywall in the same session. RevenueCat's State of Subscription Apps 2026 (115,000+ apps) found 50.6% of download-to-paid conversions happen on Day 0 and 78-90% of trials start on Day 0, depending on category. The same report found hard paywalls convert 10.7% download-to-paid by Day 35 vs 2.1% for freemium, with nearly identical one-year retention. Moving the paywall late costs conversions, so A/B test placement instead of assuming later is better.
Sources
- https://developer.apple.com/app-store/review/guidelines/#in-app-purchase
- https://superwall.com/docs/campaigns-standard-placements
- https://www.revenuecat.com/docs/tools/paywalls/displaying-paywalls
- https://x.com/samuel_yostt/status/2109698766530048174
- https://x.com/frederickjames/status/2111137088871555182
- https://developer.android.com/google/play/billing/subscriptions
- https://www.revenuecat.com/state-of-subscription-apps
- https://www.revenuecat.com/blog/growth/subscription-app-trends-benchmarks-2026
- https://firstpagesage.com/seo-blog/saas-free-trial-conversion-rate-benchmarks/
- https://x.com/zzwitz/status/2109310052343644367 (quotes https://x.com/zzwitz/status/2091879951897166069)
- https://firstround.com/review/the-tenets-of-a-b-testing-from-duolingos-master-growth-hacker/
- https://relaunch.ai/blog/duolingo-onboarding-teardown-7-b-tests-behind-their-9-conver.html
- https://www.appcues.com/blog/gradual-engagement-mobile-app-first-screen
- https://blog.duolingo.com/widget-feature
- https://revyl.com/atlas/duolingo/
- https://x.com/eglitisX/status/2112412118213640419
- https://developer.apple.com/help/app-store-connect/manage-subscriptions/set-up-introductory-offers-for-auto-renewable-subscriptions/
- https://www.revenuecat.com/docs/integrations/webhooks/event-types-and-fields
- https://x.com/itsbongoo/status/2112401557946069175
- https://x.com/GeorgeLampro20/status/2112452949561463082
- https://x.com/zakisbuilding/status/2112823780821049807
- https://x.com/devmelv/status/2112632240593158297
- https://x.com/chddaniel/status/2112392363725537783 (quotes https://x.com/chhddavid/status/2112113481495318700)
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

