You can have a perfect app and be rejected, for a missing disclosure line, a promise you can't keep, or a health claim you didn't realise you made. Rejection is more often a wording problem than a code problem. The content can stay; the framing is what gets reviewed.
The concept
App Review is a human reading your listing and tapping through your app for a few minutes, pattern-matching against a guideline list. Your job is to make the correct pattern obvious.
The account is the long pole
Nothing happens until your developer account is active. Apple's Developer Program is $99/year and enrolment can take days (longer for an organisation, which needs a business identifier). The Paid Apps agreement, required to sell anything, is separate and needs bank and tax details.
📐 Enrol on day one of your project. It's $99 and it removes the single longest external dependency from your critical path. Every day it sits in review while you build is free.
The listing kit
Draft everything as a document first, versioned, reusable, and it doesn't time out like a web form:
| Field | Note |
|---|---|
| App name (30 chars) | Weighted heavily for search, don't waste it on just your brand. Brand: Keyword |
| Subtitle (30) | A second search field and a positioning line |
| Keywords (100) | Comma-separated, no spaces, singular, no repeats of name/subtitle |
| Promotional text (170) | Updatable any time without review, use for offers |
| Description (4000) | Skimmable with section headers; nobody reads past line three |
| Screenshots | Required sizes, with captions, the single biggest lever on conversion |
| Category | Where your users search, with a pre-decided fallback |
| Age rating | Answer honestly |
| Privacy label | Must match your actual data collection |
| Review note | A private message to the human reviewer |
⭐ Rejection is usually a wording problem
Certain framings get scrutinised regardless of what your app does. Write a risk-word list for your domain, avoid-these / use-these-instead, before you submit. Ten minutes, and it prevents a rejection cycle:
| Domain | Triggers review | Safer |
|---|---|---|
| Health/mental health | treat, cure, therapy, clinically proven, "beat depression" | build, support, philosophy-based, wellbeing, for hard days |
| Fitness/nutrition | lose X lbs, medically, prescription | track, log, support your goals |
| Finance | guaranteed returns, investment advice | educational, informational |
| Dating | verified real people | community guidelines, reporting tools |
| Kids | educational outcomes, IQ | play, practise, explore |
If review flags the framing, the content usually stays, you soften the wording and sometimes switch to a category that draws less scrutiny (Education/Lifestyle over Health). Have that fallback pre-decided.
Requirements that arrive with capabilities
Each capability drags a mandatory requirement behind it (Chapter 7):
| You added | You now must ship |
|---|---|
| Accounts | In-app account deletion, not "email us" |
| Subscriptions | Restore Purchases |
| Subscriptions | Full disclosure block: title, length, price, trial, auto-renew terms, 24h cancellation, working Terms + Privacy links |
| Any data collection | Privacy Policy URL + accurate privacy label |
| Sign in with Apple offered | Must offer it alongside other social logins |
The subscription disclosure block is among the most common rejections and it's pure copy, entirely avoidable.
The review note
Four jobs, in order: pre-empt the likely objection · point to your mitigation · remove friction (demo credentials if there's a login/paywall) · give them a human to contact. "Reviewer couldn't access the app" is a self-inflicted rejection.
Rejection is a conversation
You reply in the Resolution Center. Many rejections resolve by explaining or making a small wording change. Don't panic-resubmit an unchanged build, that just costs days. Budget for one rejection cycle, especially on any sensitive framing.
📐 Best practice
Enrol on day one.
Draft the listing as a versioned document.
Use the app name for keywords, not just your brand.
Write a risk-word list for your domain.
Pre-decide a category fallback.
Ship every capability's matching requirement, deletion, restore, disclosure.
Make the privacy label match reality, including what your SDKs collect.
Write a review note that pre-empts, mitigates, and gives access.
Screenshots with captions, at every required size.
Verify Privacy and Support URLs in incognito.
⚠️ Enforce dev-flags-off in the build, not on a checklist (Chapter 33).
Budget two review cycles.
💀 Common mistakes
Enrolling late. The longest external dependency, discovered at the end.
Wasting the app name on the brand. Findable only by people who already know you.
Health/finance/etc. claims in the copy.
Missing subscription disclosure block. Very common rejection.
No Restore Purchases; no account deletion. Both mandatory with their capability.
Privacy label doesn't match behaviour, including an SDK that collects data you didn't declare.
Reviewer can't get past a login or paywall. Put credentials in the note.
Broken Privacy/Support URL, usually a branch mismatch (Chapter 34).
A dev flag ships, giving away the product.
Fabricated reviews, fake urgency, fake countdowns. Rejected, and detectable.
Mockup screenshots showing features you don't have.
Reusing a build number. Instant upload rejection.
The professional workflow
1. ENROL day one · sign the Paid Apps agreement (bank + tax)
2. DRAFT THE LISTING as a document
name · subtitle · keywords · promo · description · category(+fallback) ·
age rating · privacy label · review note
3. RISK-WORD LIST for your domain
4. IN-APP REQUIREMENTS
Restore Purchases · full disclosure block · Terms+Privacy links ·
account deletion · no fake urgency / fabricated proof
5. PRIVACY LABEL matched to real collection (incl. SDKs)
6. SCREENSHOTS at every size, with captions; icon 1024
7. VERIFY Privacy + Support URLs in incognito
8. BUILD — dev flags OFF (enforced in CI); increment the build number
9. TESTFLIGHT on a real device; complete a real sandbox purchase
10. SUBMIT — budget one rejection cycle; reply, don't panic-resubmit
Tools, websites & costs
| Need | Tool | Cost |
|---|---|---|
| Developer account | Apple Developer Program | $99/yr |
| Store management | App Store Connect | $0 |
| Screenshots | Simulator capture | $0 |
| Screenshot framing | Shots, Previewed, Figma | $0-20 |
| ASO research | AppFollow, Sensor Tower, AppTweak | Free tiers |
| Privacy policy | Termly, iubenda | $0-10/mo |
| Guidelines | App Store Review Guidelines | Free, read once, properly |
| Beta distribution | TestFlight | Free |
Alternatives & trade-offs
iOS first vs both stores. Ship where your customer pays (Chapter 37). One store first halves your submission, QA and support surface.
Individual vs organisation account. Individual is faster to enrol and shows your name publicly. Organisation shows a company name, needs a business identifier, and takes longer. Choose by whether the public developer name matters.
Category choice. Where your users search vs where scrutiny is lowest. Pick the search-optimal category with a pre-decided lower-scrutiny fallback for the sensitive case.
Promotional text vs description. Promo text updates without review, put anything time-sensitive there and keep the description evergreen.
Full worldwide vs phased release. Phased/gradual rollout limits the blast radius of a bad build (mobile can't hotfix). Worth it once you have volume.
Checklist
- Developer account enrolled day one; Paid Apps agreement signed
- Listing drafted as a versioned document
- App name uses keywords, not just the brand
- Keywords: no spaces, singular, no name/subtitle repeats
- Description is skimmable
- Category chosen, with a fallback
- Risk-word list written for my domain
- Every capability's matching requirement shipped
- Privacy label matches actual collection, including SDKs
- Privacy + Support URLs verified in incognito
- Screenshots at all sizes, with captions
- Dev flags off, enforced by the build
- Review note pre-empts the objection and includes access
- Tested on TestFlight on a real device; real purchase completed
- Budgeted two review cycles
📓 Case Study: surviving review with a sensitive framing
Project: SOLIS, which targeted an audience described as "fighting depression", a high-risk framing for review (health-claims scrutiny).
The listing was a document, copy-paste-ready with character limits noted. The app name recommendation was deliberate, "Apple weights the app name heavily for search, so don't waste it on just the brand", using the format Brand: Keyword. And the promotional text was flagged as the updatable-without-review field, reserved for offers.
⭐ A risk-word guardrail section was written specifically for the depression angle:
Avoid (read as medical claims): treat, cure, heal, diagnose, therapy, clinically proven, "beat depression," "fix your anxiety."
Use instead: build resilience, steady your mind, self-improvement, philosophy-based, for hard days, calm, discipline, wellbeing.
If Review flags the wellbeing framing, pivot the category to Lifestyle/Education and soften the sensitive subtitles, the content can stay; the framing is what gets reviewed.
That last line is the thesis: Apple isn't objecting to a lesson about difficult days; it objects to language positioning the app as treatment. Same content, different frame, different outcome. A pre-decided category fallback meant a rejection could be answered correctly rather than in a panic.
Three defensive artifacts backed the framing: a wellbeing/crisis-resources page reachable in-app and on the site, a one-line non-medical disclaimer in the description, and a review note that pre-empted the objection, "a philosophy-based self-improvement app… does not provide medical treatment… a wellbeing disclaimer with crisis resources is included… all content is viewable without an account. Contact: support@…", doing all four jobs: pre-empt, mitigate, remove friction, offer contact.
Capability requirements were handled, some late. Account deletion was built and verified (fresh account → deleted → database back to zero). But two subscription requirements were missing until the final days: a "7-day money-back guarantee" was on the paywall, which the platform (not the developer) controls, removed and replaced with the honest "nothing is charged until the trial ends." And the full Guideline 3.1.2 disclosure block, trial length, both prices, auto-renew and cancellation terms, working Terms and Privacy links, was missing entirely, which is one of the most common subscription rejections and pure avoidable copy (Chapter 27).
⚠️ Deviation 1: the dev flag that gives away the product was never disabled. A flag unlocking the entire paid course for free appeared on four separate checklists and was still on. It belonged in a CI assertion, not a list (Chapter 33).
⚠️ Deviation 2: screenshots and the final privacy-label update were never done, both open items at the last entry, both submission blockers.
🚩 Unvalidated. The app was submittable and never submitted, so whether the guardrails would have survived actual review is untested. What the case study demonstrates is how to prepare for a sensitive review, the risk-word list, the fallback, the review note, not that it passed.
Lessons
- Rejection is usually a wording problem. The content stays; the framing is reviewed.
- Enrol on day one. $99 removes the longest external dependency.
- Write the listing as a document. Versioned, reusable, doesn't time out.
- The app name is an ASO asset, not a brand statement.
- Write a risk-word list for your domain. Ten minutes; prevents a cycle.
- Pre-decide your category fallback before you're stressed and rejected.
- Capabilities drag requirements. Accounts → deletion; subscriptions → restore + disclosure.
- The disclosure block is pure copy and a very common rejection.
- Never promise what the platform controls. The trial is your guarantee.
- The review note is a message to a human. Pre-empt, mitigate, remove friction, offer contact.
- Automate the catastrophic checks. A dev flag giving away the product belongs in CI, not a checklist.