●RORKMAX — Rork Max generates pure Swift instead of React Native, enabling true native apps across iPhone, iPad, Watch, TV, Vision Pro, and iMessage●APPLE — Rork's 2026 direction has a clear theme of native empowerment across the Apple ecosystem●EXPO — Standard builds run on React Native and Expo, so you're left with a real project structure and code you can keep working on●FUNDING — Rork recently raised $15M and now sees over 743,000 monthly visits with 85% growth●PRICING — Rork is free to start, with paid plans from $25/month and Rork Max at $200/month●CROSS — Rork builds iOS, Android, and web from a single prompt, finished off with a bit of follow-up tweaking●RORKMAX — Rork Max generates pure Swift instead of React Native, enabling true native apps across iPhone, iPad, Watch, TV, Vision Pro, and iMessage●APPLE — Rork's 2026 direction has a clear theme of native empowerment across the Apple ecosystem●EXPO — Standard builds run on React Native and Expo, so you're left with a real project structure and code you can keep working on●FUNDING — Rork recently raised $15M and now sees over 743,000 monthly visits with 85% growth●PRICING — Rork is free to start, with paid plans from $25/month and Rork Max at $200/month●CROSS — Rork builds iOS, Android, and web from a single prompt, finished off with a bit of follow-up tweaking
Designing Subscription Revenue in Rork Max — What to Let StoreKit 2 Handle, and What to Own Yourself
A practical, experience-driven look at building a monthly subscription app on the Swift code Rork Max generates: freemium boundaries, paywall timing, how to read churn, the unit-economics floor, and App Store review — from an indie developer's perspective.
Since 2014 I have built apps as a solo developer, and for most of that time my income came from AdMob. I placed banners and interstitials in wallpaper and relaxation apps, then watched eCPM drift by country and hour and tuned it daily. For a long stretch, that grind paid the bills.
But ad revenue carries a particular kind of instability. Rates spike in December and sag in summer, and a month's number moves by forces that have little to do with how good the app itself is. At some point I started asking whether I could shift to receiving value directly from the people who actually use the app. Subscriptions are one answer to that question.
This article is a working set of notes for designing monthly subscriptions as a business on top of the Swift code Rork Max generates. Rather than a tidy success story, I want to share where to lean on the machine and where you have to keep your own hands on the wheel.
Why put a subscription next to your ads
Ads and subscriptions have fundamentally different shapes of revenue.
Ads are variable income proportional to impressions. If a million impressions halve next month, so does the revenue. A subscription, by contrast, is stock revenue that compounds as long as a converted user keeps paying. Last month's paying members become this month's baseline with no extra effort.
What ad operations taught me painfully is that you can barely move per-user revenue yourself — the ad market sets eCPM. With subscriptions, you design both the value you offer and the price. For an indie developer, that is the decisive difference.
You don't have to abandon ads. A two-layer structure is realistic: ads for free users, a subscription for those who feel the value. This piece focuses only on the subscription layer.
What Rork Max should build, and what you must own
Rork Max generates native Swift apps. It scaffolds the StoreKit 2 purchase flow — product loading, the buy button, the paywall screen — with surprising accuracy. Reaching an App Store release without owning a Mac or Xcode is hard to believe if you remember how this used to work.
One caution, though: treating generated code as a finished, ship-it-as-is product is dangerous. The heart of subscriptions is not the UI — it is never getting the entitlement state wrong.
Three things I always keep in my own hands. First, the logic that resolves entitlement uniquely when a purchase, renewal, cancellation, or refund occurs. Second, a verification flow that restores correctly across app restarts and device migrations. Third, reconciliation with App Store Server Notifications if you run a backend. Generated code tends to simplify exactly here, so this is where I aim my sharpest review.
✦
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
✦Where to observe StoreKit 2's Transaction.updates and how to derive entitlement state (working Swift included)
✦Drawing the freemium line and timing the paywall (realistic 3-5% onboarding and 5-10% limit-reached conversion benchmarks)
✦Using LTV ÷ CAC to decide which app deserves scaling, informed by years of AdMob revenue work
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.
StoreKit 2 has a clear design philosophy: subscribe to the Transaction.updates async sequence and rebuild current entitlement from verified transactions. Here is a minimal core.
import StoreKit@MainActorfinal class SubscriptionStore: ObservableObject { @Published private(set) var products: [Product] = [] @Published private(set) var activeEntitlement: String? = nil private let productIDs = ["pro_monthly", "pro_yearly"] private var updatesTask: Task<Void, Never>? init() { // Start listening right at launch. Skip this and you drop // background renewals and purchases made on another device. updatesTask = listenForTransactions() Task { await refresh() } } func loadProducts() async { do { products = try await Product.products(for: productIDs) } catch { products = [] } // on failure, show no purchase path } func purchase(_ product: Product) async throws { let result = try await product.purchase() switch result { case .success(let verification): let transaction = try checkVerified(verification) await transaction.finish() // forget finish and updates re-fire forever await refresh() case .userCancelled, .pending: break @unknown default: break } } // Rebuild the valid entitlement from the *current facts* func refresh() async { var current: String? = nil for await result in Transaction.currentEntitlements { guard let transaction = try? checkVerified(result) else { continue } if transaction.revocationDate == nil { current = transaction.productID } } activeEntitlement = current } private func listenForTransactions() -> Task<Void, Never> { Task.detached { [weak self] in for await result in Transaction.updates { guard let self, let transaction = try? await self.checkVerified(result) else { continue } await transaction.finish() await self.refresh() } } } private func checkVerified<T>(_ result: VerificationResult<T>) throws -> T { switch result { case .unverified: throw StoreError.failedVerification case .verified(let safe): return safe } }}enum StoreError: Error { case failedVerification }
The single most important point: do not hold activeEntitlement as a flag set at the instant the buy button was tapped. Always rebuild entitlement from currentEntitlements. That makes you resilient to the real-world churn of cancellations, refunds, family sharing, and second devices. My first subscription judged access by a purchase-time flag, and a refunded user kept their paid features. Checking revocationDate prevents exactly that.
Forgetting transaction.finish() is another classic trap. Without finishing, the transaction is treated as incomplete and re-fires through updates on every launch.
What to give away free, and what to charge for
Freemium design is the work of splitting features along a line. Treating it as "squeeze the free tier and they'll pay" usually fails. In my experience, a user who never felt the value for free leaves without even noticing the paid option exists.
If I had to name one principle: let people succeed once, for free. For a scheduling app, let them experience a full optimization at least once. For a journal app, let them write without limits for the first week. Then put the "better the longer you use it" features — limits, sync, export — on the paid side for those who want to keep going.
Two tiers are the easiest to operate: a monthly price and an annual price discounted by roughly two months. Annual reduces cancellation opportunities to once a year and lifts LTV directly. Add a third, higher tier only when it serves a clearly different customer — API access, team features. Every tier adds friction to the choice, so when in doubt I prefer to start with two.
When to show the paywall
A paywall's results depend more on when you show it than on what it says. Throwing a full-screen price wall at launch is the surest way to lose people.
I use three moments in practice.
1. Just after onboarding (soft)
- After one taste of value: "to keep going..."
- Always leave a skip
- Expected conversion: 3-5% of new users
2. The instant a free limit is hit (contextual)
- When intent to continue is strongest
- Show that you can unlock it right now
- Expected conversion: 5-10% of users who hit the limit
3. A return path for users gone a few days (re-engagement)
- From a notification, offered with a free trial
- Expected conversion: 2-3% of returners
These numbers reflect my own operating sense and move a lot by genre and app maturity. The point is not to treat them as fixed truth, but to measure your own app and replace them. One tendency is fairly stable, though: value-led paywall copy tends to outperform price-led copy. "Hand off your daily planning" consistently beat "1,980 yen a month" in my own tests.
See churn as reasons, not a number
Staring only at a churn percentage makes your countermeasures abstract. I split cancellations into categories of reason instead.
People who never quite felt the value, people who couldn't accept the price, people who moved to a competitor, people soured by a bug. They are all "churn," but the effective response differs entirely. The value gap responds to first-week experience design; price dissatisfaction responds to annual pricing or a time-limited thank-you price. Bug-driven churn, alone, will never be stopped by adding features — crash-rate monitoring and immediate fixes are the only answer.
The order of magnitude of LTV is set by churn. As a rough guide, 10% monthly churn means about 10 months average retention; 4% means about 25 months. At 1,980 yen a month and 70% margin, that is roughly 14,000 yen LTV versus 35,000 yen. Cutting churn by half more than doubles LTV. Often, designing so existing users don't leave moves revenue more than shipping one more feature.
The unit-economics floor
My yardstick for "should I grow this app" is LTV ÷ CAC.
CAC — customer acquisition cost — is what you spent on ads and production divided by the paying members it added. Unless LTV exceeds CAC, the more you spin the wheel the deeper the loss. A ratio above 3 is generally called healthy. I am a little more conservative: before an indie developer pours money into ads, I want at least 3, ideally 5.
This is where the AdMob years pay off. When you know in your bones how ad rates move by country and hour, you can compare free-user ad revenue and paid-conversion revenue on the same footing. A free user's ad ARPU is on the order of a few yen a month, while one paying member is 1,980 yen. Even at a few percent conversion, that is why subscriptions become the center of gravity.
When I model numbers, I forbid myself optimistic conversion rates. I plan assuming new-user paid conversion won't exceed 5%, and treat anything beyond that as a happy surprise. That posture has kept me sane over the long run.
Subscription disclosure that passes App Store review
Correct technology can still fail on disclosure. Subscription review has clear display requirements, and underestimating them costs you a week or two on a rejection.
At minimum, the paywall must state price, billing period, the fact of auto-renewal, and how to cancel — prominently. If you offer a trial, spell out "new subscribers only, auto-renews monthly after the period, cancel anytime." Put guidance toward the cancellation path inside the app. Include subscription terms in your privacy policy and terms of service. These are the substantive requirements behind Apple's Guideline 4.8.
In the Japanese market I also keep premium-display law in mind: if you show a regular price next to a discounted one, always attach the condition of that discount (time-limited, campaign). The same goes for any "thank-you price" wording. Writing conditions honestly is both review insurance and basic courtesy to the people choosing to pay.
The next move
If I were building a first subscription today, I would start by writing down one thing: the single success a user gets for free. Not a feature table — what they receive in the first few minutes. Once that is decided, the paywall's position and the paid-side features fall into place on their own.
Rork Max lays the foundation astonishingly fast, but the correctness of entitlement state and the drawing of the value line stay in the builder's hands. I am still searching for my own best answers, but I'd be glad to share what became visible as I shifted the shape of my revenue from ads to subscriptions, with anyone walking the same road. Thank you for reading.
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.