RORK LABJP
RORKMAX — Rork Max generates pure Swift instead of React Native, enabling true native apps across iPhone, iPad, Watch, TV, Vision Pro, and iMessageAPPLE — Rork's 2026 direction has a clear theme of native empowerment across the Apple ecosystemEXPO — Standard builds run on React Native and Expo, so you're left with a real project structure and code you can keep working onFUNDING — Rork recently raised $15M and now sees over 743,000 monthly visits with 85% growthPRICING — Rork is free to start, with paid plans from $25/month and Rork Max at $200/monthCROSS — Rork builds iOS, Android, and web from a single prompt, finished off with a bit of follow-up tweakingRORKMAX — Rork Max generates pure Swift instead of React Native, enabling true native apps across iPhone, iPad, Watch, TV, Vision Pro, and iMessageAPPLE — Rork's 2026 direction has a clear theme of native empowerment across the Apple ecosystemEXPO — Standard builds run on React Native and Expo, so you're left with a real project structure and code you can keep working onFUNDING — Rork recently raised $15M and now sees over 743,000 monthly visits with 85% growthPRICING — Rork is free to start, with paid plans from $25/month and Rork Max at $200/monthCROSS — Rork builds iOS, Android, and web from a single prompt, finished off with a bit of follow-up tweaking
Articles/Business
Business/2026-04-28Advanced

How to Make Ads and Subscriptions Coexist in a Rork App: A Solo Developer's Hybrid Revenue Model

I used to think ads and subscriptions don't mix. After a year of experiments on my own apps, I learned that with the right boundary design, a hybrid produces nearly 1.7x the revenue of either model alone. Here's the model I'm shipping, with implementation code and real numbers.

Rork504app monetization6AdMob69subscription28indie development30

Premium Article

For a long time, I was skeptical of putting both ads and subscriptions into the same app. The reasoning seemed obvious: "if you've already annoyed users with ads, layering a subscription on top just speeds up the exit."

After a year of experiments on my own apps, I changed my mind. With the right boundary design, ads and subscriptions don't fight — and the combined monthly revenue ran roughly 1.7x what either model produced alone. Most of the apps I'm building with Rork right now use a hybrid configuration.

This piece walks through the hybrid revenue model I actually run as a solo developer, with the design intent behind each decision and the implementation I hand-add on top of the React Native code Rork generates. Ad gating and subscription-state synchronization sit just outside what Rork writes for you automatically — and getting that seam right is, in my experience, what separates a hybrid that earns from one that annoys.

"Ads or subscription" is the wrong frame

The "ads or subscription" debate only makes sense if you treat all your users as one group. Real app users vary wildly across willingness to pay, frequency of use, and tolerance for ads.

Heavy ad tolerance, "I will never pay" users. Hate ads but won't pay a few hundred yen a month. Will pay monthly but balk at annual. Will buy annual outright. Will pay once for a lifetime unlock and nothing after.

I can clearly see at least these five segments in my own apps. Picking one plan means abandoning four of them. The hybrid model is a direct response to that segmentation.

Here are the real numbers from one of my wallpaper apps. It's a single example from a single app, but it's a useful starting point for reasoning about whether the design holds up.

User segmentShareMonthly revenue per user (rough)Contribution to total
Non-paying (ads only)~80%10–25 JPY~35% of total
Subscribers~8%280–480 JPY~50% of total
One-time buyers~4%~120 JPY equivalent, first month only~8% of total
Active on ads only~8%15–30 JPY~7% of total

What I most want this table to say is that half the revenue comes from the 8% who subscribe, and the other half from the thin, steady accumulation across the non-paying base. Optimize for only one and your design throws the other away. The hybrid exists to catch both at once.

Don't draw the boundary along features

The classic mistake is to split by feature: "Feature A is free with ads, Feature B is subscription only." From the user's view, this reads as "you keep adding things I can't use unless I pay."

I draw the boundary on two axes: frequency and quality.

Frequency-wise, an example: "save up to three wallpapers per day for free, beyond the fourth either watch a rewarded ad or upgrade." The feature itself is open to everyone — only the cap is paywalled, with two ways to lift it. The ad-tolerant and the subscription-friendly each have a home.

Quality-wise: "free is standard resolution, subscription is 4K." This isn't taking a feature away — it's offering an upgrade for those who want higher quality.

When you cut along these two axes, users rarely feel funneled. In my data, conversion to subscription is noticeably higher than the feature-split approach.

Implementing the daily frequency cap

A frequency boundary that exists only as a concept falls apart in the code. Here's the minimal daily counter I run in React Native (the shape Rork generates). It resets when the local date changes, and once the free cap is exceeded it reports whether the unlock path is "ad" or "subscription."

// useDailyQuota.ts — minimal management of daily free usage
import AsyncStorage from "@react-native-async-storage/async-storage";
 
const FREE_DAILY_LIMIT = 3;
 
function todayKey() {
  // Slice the day on the device-local date (slicing on UTC drifts at night)
  const d = new Date();
  return `quota:${d.getFullYear()}-${d.getMonth() + 1}-${d.getDate()}`;
}
 
export async function getUsedCount(): Promise<number> {
  const raw = await AsyncStorage.getItem(todayKey());
  return raw ? parseInt(raw, 10) : 0;
}
 
export async function consumeOne(): Promise<void> {
  const key = todayKey();
  const used = await getUsedCount();
  await AsyncStorage.setItem(key, String(used + 1));
}
 
// Report whether the cap is exceeded, and if so whether "ad" or "subscription" unlocks it
export async function checkQuota(isSubscriber: boolean) {
  if (isSubscriber) return { blocked: false, unlockBy: "subscription" as const };
  const used = await getUsedCount();
  if (used < FREE_DAILY_LIMIT) return { blocked: false, unlockBy: "free" as const };
  return { blocked: true, unlockBy: "ad" as const };
}

What I deliberately avoid here is holding the count server-side. In the early stage of solo development, device-local works fine. Routing through a server means a network call on every launch, and a user who hits the wall offline gets confused. Start with AsyncStorage, and add server validation only once abuse becomes a problem you can't ignore — that's the order I recommend.

Why slice the date on the device? Because slicing on UTC resets the count at 9 p.m. for users in Japan. I actually shipped this once — "the cap comes back early, but only at night" — and only noticed when a review pointed it out. Small thing, but it goes straight to the trustworthiness of your frequency design.

Thank you for reading this far.

Continue Reading

What follows includes implementation code, benchmarks, and practical content we hope you'll find useful. This site runs without ads — server and development costs are supported entirely by members like you. If it's been helpful, we'd be truly grateful for your support.

WHAT YOU'LL LEARN
Drawing the ads-vs-subscription boundary along frequency and quality so users never feel funneled, with the implementation behind it
Startup state-synchronization code that prevents the classic accident of loading ads before the subscription check resolves and showing ads to paying users
The two-layer structure that earns revenue from the 80 percent who never pay, plus day-by-day offer logic that targets the first-30-day conversion window
Secure payment via Stripe · Cancel anytime

Unlock This Article

Get full access to the rest of this article. Buy once, read anytime. This site is ad-free — your support goes directly toward keeping it running.

or
Unlock all articles with Membership →
Share

Thank You for Reading

Rork Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • Copy-paste ready implementation code
  • New advanced guides published daily
  • $5/mo or $10 for lifetime access
View Membership →

Related Articles

Business2026-04-11
Every Step to Monetizing an App You Built with Rork
A complete walkthrough of building an app with Rork and monetizing it on the App Store and Google Play. Covers AdMob, subscriptions, and one-time purchases — with a roadmap to reaching ¥100K/month as an indie developer.
Business2026-05-23
Minimal Customer Support Architecture for Solo Rork Devs — Running Inquiries for Multiple Apps Alone
The minimum-viable customer support stack I run as a solo developer maintaining a dozen apps with 50M cumulative downloads — in-app form with auto-attached diagnostics, Gmail filtering, reply templates, and the escalation rules that keep me under thirty minutes a day.
Business2026-05-14
AdMob Mediation Dropped My eCPM by 30% After I Set It Up — What Went Wrong and How I Fixed It
My eCPM dropped 30% the morning after enabling AdMob mediation. Drawing from 12 years of indie app development and over 50 million downloads, here are the three pitfalls I found in Rork apps and how I recovered.
📚RECOMMENDED BOOKS
Build a Large Language Model (From Scratch)
Sebastian Raschka
LLM Dev
Prompt Engineering for LLMs
Berryman & Ziegler
Prompting
AI Engineering
Chip Huyen
AI Eng
* Contains affiliate links
See all →