The Shelf / App Store / iOS Paywall Playbook
iOS Paywall Playbook
The same paywall setup we put on every app we ship, plus the two Apple rejections that shaped it.
The job: put a paywall on your iOS subscription app that follows Apple's rules and is built to convert — where it shows, what it says, how the price is presented, how the code is wired — without working any of it out yourself or learning App Review's rules the expensive way.
Most paywall advice is a listicle. This is the working setup we put on every subscription app we ship. It only changes when a test proves something better, or a reviewer proves us wrong. Both have happened. The file remembers.
What it does
Hand it to your agent and it builds your paywall, or checks the one you have, against the standard: the four places a paywall should show (after onboarding, at app open, when a paid action is tapped, and after someone lapses), one clear offer instead of a wall of plans, honest pricing with the per-week math and a savings badge that adds up, and ten mistakes to stay away from. The search commands run over your own app's code and come back pointing at the exact file and line.
The part that cost us
Two things the paywall-advice world calls standard got a real app of ours rejected. One was the free-trial switch on the paywall itself (Apple's rule 3.1.2(c)). The other was the "wait, don't go" offer that pops up when someone backs out of buying — that one is rule 5.6, and ours was turned down even though it stated every term up front. Apple's own wording is quoted in the compliance file, next to what we shipped instead to get through. Also in there: the full 12-point checklist of what a subscription screen has to say, including the quiet one that bounces apps — the terms and privacy links are there, but printed so small and gray the reviewer can't find them.
What's inside
SKILL.md— the playbook: where the paywall shows, how it's built, how the price reads, the numbers to judge yourself against, the subscription code, the search commands, the mistake listreferences/apple-compliance.md— both rejections, told properly, plus the 12-point checklistQUICKSTART.md— how to load it into Claude Code, claude.ai, or Codex, with a first prompt to run- The field report on this page — a real audit run, yours to read before you pay
Who it's for
Solo iOS developers and small teams shipping subscription apps. If your app gets downloads and no money, the leak is almost always where the paywall shows or what it says. This finds which.
Why not a free directory download
Free skill directories hold thousands of files nobody has ever run. This one has shipped real apps, eaten two real rejections, and gets updated when the evidence changes — the version number on the tag means something. Field-tested, documented, issued as-is.
FIELD REPORT real output, not a promise
Setup: the playbook's audit pass run against a shipped contract-review app in our own portfolio (anonymized). Placement-coverage greps first, then the compliance hard-ban check. This is the audit output format the skill produces — findings drawn from the real, documented audit.
Placement coverage
| Placement | Status | Evidence |
|---|---|---|
| Onboarding paywall | ✅ Present | Presented post-onboarding, before auth |
| Session-start | ❌ Missing | `rg 'scenePhase |
| Action-gated | ⚠️ Partial | Hard gates on export/compare existed; no free-first-action taste of the core feature. Changed to one free scan before the gate, with the paywall card copy updated to say so |
| Win-back (lapsed) | ❌ Missing | No App Store Connect win-back offers configured — flagged as a store-side task, not code |
Compliance hard-bans
- Post-cancel surface: the app auto-presented a "recovery" sheet when the user cancelled the native purchase sheet — fully disclosed (price, auto-renewal terms, legal links), which we then believed made it safe. A sibling app's rejection under Guideline 5.6 proved otherwise: the trigger is the violation, disclosure doesn't cure it. Removed; cancel now returns to the same paywall with nothing popped.
- Trial toggle: none present. ✅
- Billed-amount conspicuousness: annual price is the largest pricing element; trial stated subordinately with explicit "then $X automatically" language. ✅
Pricing presentation findings
- Savings badge computed in
Decimal— rendered "SAVE 0%" at runtime. The mock/screenshot mode hid it; only a live simulator run of the real paywall surfaced it. Recomputed inDoubleper the playbook formula; badge then rendered the true percentage. - Loss-aversion anchor was a bare struck-through price — relabeled "at weekly rate" (honest-label rule, avoids the 3.1.2 misleading-pricing read).
- CTA copy reframed from "7-Days free" to "1-Week free" (reads as one unit of the billing period, not a countdown).
Outcome
Four placement/compliance gaps and two pricing-presentation bugs found and fixed in one audit pass; the removed post-cancel sheet was the same pattern that had already caused a documented rejection elsewhere in the portfolio. Re-audited across subsequent builds: zero drift.
SERVICE RECORD living gear — updated as the factory learns
v1.1.0 — 2026-08-25
Field update from six weeks of shipping subscription updates across the portfolio. The headline: the session-start snippet is hardened with three guards, each one a bug we actually shipped — the big one being that system sheets bounce scenePhase, so the old bare .active check could pop the paywall right after a purchase-sheet cancel (the exact Guideline 5.6 pattern this playbook bans; if you installed v1.0.0's snippet, apply the old == .background guard). New method content: hide a plan card whose product the store didn't return (and fall the selection back), the warning that an App Store Connect–side offer change is invisible until a binary ships copy for it, the "lock the number, never the reasoning" gating pattern, the free-first-taste action gate, brand-tunable session-start cadence, a sharpened first-purchase unlock audit (grep the helper's call sites, not its definition), a cold-daemon entitlements disambiguation, a new audit grep for the bounce guard, a sharpened simulator caveat (a bare simctl launch plus fallback price strings screenshots as a working paywall), and a new anti-pattern on metered freemium coverage.
v1.0.0 — 2026-07-17
First issue. Ported from the factory's internal skill: sanitized for general use, methodology intact, field report captured from a real run.
Every update ships free to owners — your locker always serves the latest version.
QUESTIONS
Do I need a paywall service like Superwall or RevenueCat?›
No. It uses Apple's own subscription tools (StoreKit 2) and SwiftUI, nothing else. The thinking behind it comes from published Superwall material and the apps we've shipped, but there's no other tool you need to buy or install.
Are the rejection stories real?›
Yes. Both happened to an app in our own portfolio. Apple's reviewer wording is quoted, along with what that app changed and resubmitted with.
Does this only work in Claude Code?›
No. It's a plain text file. The QUICKSTART shows how to load it into Claude Code, a claude.ai project, or Codex.
Do the numbers guarantee I'll convert that well?›
No, and we won't pretend otherwise. They're published figures to hold your own results against, so you know whether the paywall needs work. This fixes the paywall. The rest is your app.