Designing Paywalls That Don't Drive Users Away
The Monetization Paradox
Every indie developer faces the same impossible question: how do you make money from your app without making people hate it? Show paywalls too aggressively and users uninstall. Show them too rarely and you can't pay rent. The entire monetization landscape is littered with apps that got one side of this wrong — either leaving money on the table or leaving users feeling manipulated.
I build two indie apps, BrainFit (a brain training RPG) and BloomCard (a garden-themed flashcard app), and both need to sustain themselves financially. Over the past year, I've developed a paywall philosophy that treats monetization as a user experience problem rather than a revenue optimization problem. The result is a system built around three pillars: celebration paywalls, feature gates, and cooldown managers.
This post breaks down every decision — the specific numbers, the trigger points, the cooldown logic, and the reasoning behind each choice.
Three Types of Paywalls
Most apps have one paywall: a screen that says "upgrade to Pro." It shows up at some point, the user dismisses it or doesn't, and that's the entire strategy. I think this is fundamentally wrong. Not every moment in an app has the same emotional temperature, and the paywall should match the moment.
I use three distinct paywall types, each designed for a different psychological context.
1. Celebration Paywalls
Celebration paywalls appear at moments of genuine achievement. The user just did something worth celebrating, and the paywall rides the emotional high of that accomplishment. This is critical — the paywall doesn't create the positive emotion, it joins it.
In BrainFit, celebration paywalls trigger at four specific moments:
- Planet evolution: When a user's brain area score hits a threshold and their planet visually evolves to the next stage (there are 5 stages: stardust, asteroid, planet, star system, galaxy). This is a dramatic visual moment — the entire screen transforms.
- Attendance milestones: 7-day, 14-day, and 30-day streaks. These are natural celebration points where the user feels invested.
- Returning user: When someone comes back to the app after being away. This is a recovery moment — the user chose to return, which signals latent interest.
- First weekly report: The first time a user sees their personalized performance analytics. It's a moment of insight and self-reflection.
BloomCard has a broader celebration trigger set because the app has more natural milestone moments:
- First bloom: The first time a card reaches full bloom status (stability >= 60). This is the core loop paying off for the first time.
- Streak milestones: 7, 14, 30, 60, and 100 days. More granular than BrainFit because study streaks are the primary engagement metric in a flashcard app.
- Collection complete: When a user unlocks all flowers in a rarity tier. Free users have access to 16 of 54 flower species, so hitting collection milestones signals deep engagement.
- Level milestones: Levels 5, 10, and 20 in the XP system.
- Study milestones: 100, 500, and 1,000 total card reviews. These represent serious commitment.
- All quests complete: Finishing all weekly quests. This triggers at most once per week.
- Return user: Same concept as BrainFit — triggered after completing a study session post-return.
- First extra study complete: When a user voluntarily reviews cards beyond what's due. This signals someone who's engaged enough to study extra.
The key insight about celebration paywalls is that they feel less like interruptions and more like natural transitions. The user is already pausing to acknowledge an achievement. Adding a "here's what Pro could do for you" message in that pause feels organic rather than intrusive.
2. Feature Gate Paywalls
Feature gates are the most traditional paywall type — the user tries to access a Pro feature and hits a wall. But the implementation details matter enormously.
BrainFit has 9 gated features, and I made a deliberate decision about which ones allow ad-based temporary access:
| Feature | Ad Access | |---------|-----------| | BQ Area Detail (brain score breakdown) | Yes | | BQ Growth Detail (progress over time) | Yes | | Decoration (planet customization) | Yes | | Game Detail Stats | No | | Senior Mode Extended | No | | Weekly Report | No | | Pro Decorations | No | | Challenge Mode | No | | Custom Training Plans | No |
The logic behind ad access follows a simple rule: features that let users sample Pro value get ad access. Features that represent ongoing Pro benefits don't. BQ Area Detail and BQ Growth Detail give users a taste of the analytics depth they're missing. Decorations let them try customization once. But Challenge Mode, Custom Training Plans, and Weekly Reports are ongoing features — letting users ad-unlock them repeatedly would undermine the subscription value.
BloomCard's feature gates are more usage-based:
| Feature | Free Limit | Ad Reward | |---------|-----------|-----------| | TTS (text-to-speech) | 10/day | +5 uses | | Minigame | 1/day | +1 play | | APKG import | 1/month | +1 import |
This "limited free usage with ad extension" model works well for utility features. Users get enough free usage to understand the value, and ads provide a pressure release valve before the hard paywall. The limits are generous enough that casual users may never hit them, while power users bump into them regularly.
3. Play Limit Paywalls
These are the hardest paywalls to get right because they directly gate the core experience. In BrainFit, free users get 3 games per day. New users (first 7 days) get 7 games per day to let them explore during the honeymoon period.
The newbie grace period was a significant decision. Without it, new users hit the play limit before they've even tried all six brain areas. With 32 total minigames across 6 areas, 3 games per day means it would take nearly 11 days to try each game once. The 7-game limit during the first week compresses that exploration phase, letting users discover their favorite games before the limit tightens.
BloomCard's limit paywalls trigger on TTS usage, deck count, extra study limits, and when users try to access Pro-only community decks. These are less aggressive than BrainFit's play limit because the core study loop in BloomCard is unlimited — you can always review your due cards. The limits apply to auxiliary features that enhance the experience rather than gating the main activity.
The Cooldown Manager
Here's where most monetization systems fail. Even with perfectly designed paywalls, showing them too frequently creates fatigue. Users start dismissing them reflexively, and each dismissal trains them to ignore future paywalls. Worse, repeated paywalls create a negative association with the app itself.
The PaywallCooldownManager is the single most important component in the entire monetization system. It controls when paywalls can and cannot appear, overriding trigger logic when the user has already been shown enough.
BrainFit's Cooldown Rules
BrainFit uses two cooldown rules:
-
Daily maximum: 3 paywalls per day. After the third paywall in a calendar day, no more paywalls appear regardless of trigger conditions. The user can hit play limits, reach milestones, access Pro features — none of it will generate a paywall until the next day.
-
Celebration source-specific permanent limit: 1 per source, ever. Each celebration trigger can only show a paywall once in the app's lifetime. If you saw a paywall for your first planet evolution, you'll never see another paywall for planet evolution again. This applies per trigger source, not per paywall type — so you'll still see a paywall for your attendance milestone, but only one for each milestone tier (7, 14, 30 days).
The permanent limit for celebrations is possibly the most counter-intuitive decision in the system. Conventional wisdom says you should show paywalls at every high-emotion moment. But I found that repeating celebration paywalls transforms those joyful moments into "oh, here comes the upsell again" moments. Showing it once preserves the surprise element. The user thinks "oh interesting, Pro has these features" rather than "ugh, this again."
BloomCard's Cooldown Rules
BloomCard's cooldown system is more nuanced, reflecting lessons learned from BrainFit:
-
Session maximum: 1 paywall per session. Once a user sees a paywall during their current app session, they won't see another one until they close and reopen the app. This is more aggressive than a daily limit because it protects the user's current flow state.
-
Daily maximum: 2 paywalls per day. Even across sessions, no more than 2 paywalls per day. This is lower than BrainFit's 3 because BloomCard sessions tend to be shorter (a quick study session vs. extended gameplay), so the same number of paywalls would feel more dense.
-
Type-specific dismiss cooldowns. When a user dismisses a paywall, the cooldown varies by type:
- Celebration dismissal: 48-hour cooldown. After dismissing a celebration paywall, no celebration paywalls will appear for 48 hours. This is long because celebration paywalls should feel special, not recurring.
- Limit dismissal: 24-hour cooldown. After dismissing a limit paywall, no limit paywalls will appear for 24 hours. This is shorter because limit paywalls are contextually important — the user is trying to do something and being told they can't.
The type-specific cooldown was added after observing user behavior in BrainFit. Users who dismissed a celebration paywall were unlikely to convert if shown another celebration paywall soon after. But users who dismissed a limit paywall sometimes converted the next day when they hit the same limit again. The 24-hour window lets the need resurface while still giving breathing room.
Rewarded Ads: The Pressure Release Valve
Both apps offer rewarded ads as an alternative to subscription conversion. The implementation is identical across both apps: 5 ads per day, with a minimum 3-minute interval between ads.
The 5-per-day limit serves two purposes. First, it prevents users from gaming the system by watching unlimited ads to effectively get Pro for free. Five ad views per day generates meaningful ad revenue without eliminating the upgrade incentive. Second, it protects the user experience — watching more than 5 video ads per day would make the app feel like an ad platform.
The 3-minute interval is a UX constraint. Without it, a user hitting a limit could watch 5 ads back-to-back in under 3 minutes, which feels terrible. The interval forces natural spacing, and in practice, users rarely notice it because they're doing other things between ad views.
BrainFit places rewarded ads on features like BQ detail views and decorations. BloomCard places them across 4 screens: study completion, garden (when water drops are below 50), extra study, and feature gates. The placement strategy follows the same principle — ads appear where users are likely to want a small boost, not where they're deeply engaged in the core activity.
The Local Trial Service
Both apps include a returning user trial: when a user comes back after 3 or more days of absence, they receive a 3-day free Pro trial. This serves multiple purposes:
-
Re-engagement hook: The user left and came back. Something brought them back. Giving them the full Pro experience during their return window maximizes the chance they'll rediscover the app and stay.
-
Pro value demonstration: Many users never try Pro features because they don't know what they're missing. The trial forces exposure to Pro functionality in a natural context — the user is just using the app normally, but everything is unlocked.
-
Conversion window: After 3 days of Pro, reverting to free feels like losing something. Loss aversion is a stronger motivator than potential gain. Users who experienced Pro and valued it will convert at a much higher rate than users who only saw a paywall description.
The 3-day duration was chosen carefully. One day isn't enough to experience all Pro features. Seven days is so long that users adapt to Pro as the baseline and feel resentful when it ends. Three days is enough to see the value but short enough that the trial ending feels prompt rather than punitive.
In BrainFit, the trial is managed by LocalTrialService, which tracks absence duration and trial state locally. In BloomCard, it lives in the rewards feature module, using SharedPreferences to track pending_return_days_away and app_return_days_away.
Subscription Tiers
Both apps offer the same three-tier structure: Monthly, Annual (default selection), and Lifetime.
Making Annual the default selection isn't arbitrary. Annual subscribers have dramatically better retention than monthly subscribers — they've made a larger upfront commitment, and the sunk cost effect keeps them engaged. The paywall UI emphasizes the annual plan with a dynamically calculated discount percentage compared to monthly pricing. BloomCard shows the exact savings amount, making the value proposition concrete rather than abstract.
Lifetime is included for users who hate subscriptions on principle. These users will never convert to monthly or annual, so lifetime captures revenue that would otherwise be zero. The lifetime price is set high enough that it represents roughly 2-3 years of annual pricing — high enough to protect recurring revenue but low enough to feel like a deal for committed users.
BrainFit additionally offers Family plans (monthly and annual) because brain training is often a family activity. Family plans allow multiple users on a single subscription, which increases household conversion rates. BloomCard doesn't currently need family plans because flashcard study is inherently individual.
Source Tracking and Analytics
Every paywall display in both apps includes a source parameter that tracks exactly which trigger point led to the paywall. This isn't just for analytics — it fundamentally shapes how I iterate on the system.
By tracking sources, I can answer questions like:
- Which celebration moment has the highest conversion rate?
- Do users who dismiss limit paywalls convert later through feature gate paywalls?
- Is the returning user trial actually driving conversions, or are those users converting anyway?
- What's the average number of paywall views before conversion?
Without source tracking, paywalls are a black box. With it, each trigger point becomes an independently measurable experiment. I can adjust cooldown timers, add or remove triggers, and modify the trial duration based on actual conversion data rather than intuition.
The Upsell Ecosystem
Paywalls are just one piece of the monetization surface. Both apps maintain passive "upsell points" that remind users of Pro without interrupting their flow:
- Profile Pro badge: A visual indicator that Pro exists, shown on the profile screen.
- Settings subscription section: A dedicated area where users can explore Pro at their own pace.
- Post-activity Pro preview: After completing a study session (BloomCard) or game (BrainFit), a subtle preview of what Pro analytics would show for that session.
- Feature gate remaining count badges: Small badges showing "3/10 TTS uses remaining today" that create awareness without blocking.
These passive upsells work in concert with active paywalls. They build familiarity with Pro's value proposition over time, so when a paywall does appear, the user already has context for what they'd be getting. The paywall becomes a decision point rather than a discovery moment.
The community marketplace in BloomCard has its own monetization layer I describe in this post — download quotas, creator rewards, and water drop economics. That system interacts with the paywall system through Pro benefits like unlimited downloads and 1.5x creator rewards, creating additional conversion pressure from the community angle.
Numbers That Shaped the Design
Let me lay out the specific numbers behind each system and why they're set where they are:
Play limits (BrainFit):
- Free: 3 games/day. Low enough to create upgrade pressure, high enough to form a daily habit (one game per brain area pair).
- Newbie (first 7 days): 7 games/day. Enough to try all 6 areas plus a favorite in one session.
Feature gates (BloomCard):
- TTS: 10/day free. Language learners need TTS constantly. 10 uses covers a short session but not a full study day.
- Minigame: 1/day free. Enough to experience the feature, not enough to make it a daily habit without Pro.
- APKG import: 1/month. Importing decks is an onboarding action, not a recurring one. Monthly allows one tryout.
Cooldowns (BrainFit):
- 3/day max. Users typically have 1-2 natural trigger moments per session. 3/day allows for an unusually active day without overflow.
- Celebration: permanent 1x per source. Preserves the specialness of milestone moments.
Cooldowns (BloomCard):
- 1/session max. Protects flow state during study sessions, which are the core value delivery moment.
- 2/day max. Two sessions per day is typical for engaged users. One paywall per session means two per day is the natural ceiling.
- 48h celebration cooldown. Celebration paywalls are emotional — spacing them widely prevents emotional manipulation fatigue.
- 24h limit cooldown. Limit paywalls are functional — users need to be reminded of limits when they encounter them, but not within the same day.
Rewarded ads (both apps):
- 5/day. Generates meaningful ad revenue without making ads feel like the primary experience.
- 3-min interval. Prevents ad binge behavior while remaining invisible during normal usage patterns.
Return trial (both apps):
- 3+ days absence triggers eligibility. Three days is long enough to indicate genuine lapse, not just a busy weekend.
- 3-day trial duration. Long enough to taste Pro, short enough that expiration feels natural.
What I Got Wrong Initially
The current system is the result of multiple iterations. Some early decisions were wrong:
I initially had no cooldown in BrainFit. Every trigger fired a paywall. Users who evolved a planet, hit a streak milestone, and then tried a Pro feature would see three paywalls in under a minute. The daily cap of 3 was the first fix, and the celebration permanent limit was the second.
BloomCard's first version used a daily cooldown only. Session-based cooldowns came after observing that users who studied twice a day were seeing two paywalls in rapid succession during a single study session if they triggered one at the start and one at the end. The session limit fixed this.
The dismiss cooldown was originally uniform (24h for all types). I split it into type-specific cooldowns after noticing that celebration paywall conversion rates dropped to near zero when shown within 24 hours of a previous celebration dismissal, while limit paywall conversion rates remained meaningful at 24 hours.
The newbie period in BrainFit was originally 3 days with 5 games/day. Users were still churning during the exploration phase. Extending to 7 days with 7 games gave them enough runway to find their groove.
The Philosophy Behind It All
If I had to distill this entire system into one principle, it would be: monetization should feel like a natural part of the app's rhythm, not a foreign intrusion.
Celebration paywalls work because the user is already pausing to reflect. Feature gates work because the user is actively seeking more. Play limits work because they create natural session boundaries that are actually healthy for the user (nobody should play brain training games for 3 hours straight). Cooldown managers work because they treat the user's attention as a finite, precious resource rather than an infinite well to draw from.
The irony is that a restrained paywall system probably generates more lifetime revenue than an aggressive one. Users who feel respected stay longer. Users who stay longer eventually convert. And users who convert from a place of genuine desire rather than frustration have dramatically better retention as paying customers.
The system isn't perfect, and I'm still iterating. But the framework — celebration over interruption, gates over walls, cooldowns over frequency — has proven robust enough to sustain two indie apps while keeping users engaged rather than annoyed. That's the balance I was looking for.