App Store Review Rejections
Overview
App Review rejects on a small set of recurring guideline violations. Per Apple's own transparency reporting, performance/completeness (2.1) is the #1 cause, and privacy (5.1.x) is the leading policy cause. This skill maps the rejection classes that a free game/app with banner ads + a Remove-Ads IAP + CloudKit + Game Center realistically hits, to a concrete pre-submission fix. These examples assume a free app with banner ads + a Remove-Ads IAP + CloudKit + Game Center; the guideline classes apply broadly — skip sections that don't fit your app's feature set.
It is the content companion to asc-api-automation (which drives who/how each ASC
call gets made); this says why a build gets bounced and how to pre-empt it.
When to use
- Before any TestFlight→App Store submission (
asc-api-automationgot the build up; this gates whether it passes review). - A Resolution Center message arrived citing "Guideline X.Y" — find the row, apply the fix.
- Auditing a new app/game for submission-readiness.
- NOT for the mechanics of submitting or distributing (that's
asc-api-automation).
Quick reference — rejection class → fix (weighted to these apps)
| Guideline | Why it bounces a puzzle-game-with-ads | Pre-submit fix here |
|---|---|---|
| 2.1 App Completeness | Crash on reviewer's device/OS, dead-end flow, placeholder content, ad fails to load → blank space, debug/test ad shown in the prod build | Run the build on a clean device + the oldest supported OS. Ensure ads degrade gracefully (no empty frame on no-fill). Release and TestFlight should read the same production ad unit ID — don't switch to a Google test ad unit ID for TestFlight, that's a Google policy violation risk (invalid traffic) if it ever slips into a public release; instead register each tester's device as a Google test device (AdMob console → Test devices) so it gets test ads on the prod ID. Verify ads actually render, not a blank no-fill frame. No <TRANSLATE> / lorem strings. |
| 2.3.1 Hidden features | Shipping dormant code / hidden toggles reviewers can reach | No DEBUG-only surfaces (debug menus) reachable in Release. |
| 2.3.3 Screenshots | Screenshots don't match the actual app, wrong dimensions, contain device frames Apple disallows, alpha channel; the marketing copy or version number rendered inside the screenshot is itself metadata | Do not upload snapshot-test baselines directly — they have an alpha channel + wrong dims. Use real device/sim captures at exact spec sizes, regenerated fresh per release. Also check the text baked into the image: a claim like "Zero tracking" or "No third-party SDKs" is a metadata claim App Review can compare against PrivacyInfo.xcprivacy (e.g. NSPrivacyTracking: true contradicts it) — false claims are rejectable independent of the app's actual behavior; a version number rendered in the screenshot can also simply go stale. |
| 2.3.10 Irrelevant metadata | Mentioning Android / "also on Google Play", other platform names in description/keywords | Strip platform references from every shipped locale's metadata. |
| 3.1.1 In-App Purchase | Remove-Ads unlock sold outside IAP; no "Restore Purchases" control; price/benefit unclear | Remove-Ads must be a StoreKit IAP with a visible Restore Purchases control (implementation → storekit2-iap-defaults). Apple's wording is "you should have a restore mechanism," but it is enforced in practice as mandatory — non-consumable must restore on reinstall. |
| 4.3(a)/(b) Spam / saturation | Highest latent risk — saturated genres (puzzle, utility) face 4.3(b) "indistinguishable from what's already available" risk. (Apple's enumerated 4.3(b) examples are flashlight/sound-effects/wallpaper/timer/fortune-telling — puzzle games aren't named; the risk is inferred from saturation, not an explicit callout.) A thin clone gets bounced as spam. | Lead with genuine differentiation (design system, content hub, Game Center, cross-platform). Distinct app name/icon/screenshots per app; never ship two near-identical binaries under different names (4.3(a) = same app under multiple Bundle IDs). |
| 4.0 / 4.2 Minimum functionality | Too simple, feels like a web wrapper or template | Native features (haptics, Game Center, iCloud resume, widgets if any) demonstrate platform depth. |
| 5.1.1(v) Account deletion / data | App "supports account creation" but offers no in-app deletion path | Apple's text triggers the deletion requirement only for apps that "support account creation". If the app has no app-specific account-creation flow (identity via iCloud / Game Center), 5.1.1(v) likely doesn't apply — confirm for your app. But Apple publishes NO explicit iCloud/Game-Center exemption, so don't assert one as fact. Still: provide a way to clear the user's CloudKit data + a reachable privacy-policy URL. If rejected on 5.1.1(v), reply to Review that the app creates no app-specific account and data-clearing is available, rather than claiming a blanket exemption. |
| 5.1.1 Privacy policy | Missing/unreachable privacy policy URL in ASC + in-app | Privacy policy URL set in App Privacy + reachable; covers ads (AdMob) + analytics data. |
| 5.1.2 Data Use — ATT | The AdMob trap. App accesses ASIdentifierManager.advertisingIdentifier (IDFA) or presents the ATT prompt via UMP but lacks NSUserTrackingUsageDescription, or never shows the prompt at all |
ATT is required when the app accesses IDFA (ASIdentifierManager.advertisingIdentifier) or presents the ATT prompt via UMP. AdMob can serve limited/non-personalized ads without accessing IDFA — in that case ATT is not required (though UMP/GDPR consent may still apply). When ATT is required: NSUserTrackingUsageDescription present in every shipped locale, ATT prompt shown via UMP before personalized ads. Ensure each new app in a multi-app repo has its own ATT primer coordinator component — it is a submission blocker if missing. If you do NOT access IDFA, declare so and don't link to it. Note: reviewers sometimes cite 2.1 (Information Needed) instead of 5.1.2 when they simply can't find where the prompt fires — the sim-verify checklist item below covers both. |
| Privacy-label parity | App Privacy "nutrition" answers in ASC contradict PrivacyInfo.xcprivacy / actual SDK behavior (AdMob collects identifiers + usage data) |
ASC App Privacy answers must match the committed PrivacyInfo.xcprivacy and AdMob's declared collection. Keep them in sync (apple-three-piece-analytics). |
| Age rating / 2.3.6 | Ads can serve mature content but rating says 4+ (1.3 is the Kids Category, not age-rating honesty) | Set AdMob max ad content rating appropriately; age rating must cover ad content. |
| Export compliance (ASC upload step, not a Guideline number) | Build held "Processing" pending the ITSAppUsesNonExemptEncryption / export-compliance answer — the Guidelines text has no "export" section; 2.5 is Software Requirements, unrelated to this |
Answer export compliance in ASC (uses standard crypto only) — user-owned — a build sits in "Processing" until a human answers it, so it is a release-day blocker, not an automation step (asc-api-automation covers what the API can drive). |
Pre-submission checklist (run before flipping a build to "Submit for Review")
- Clean-device + oldest-OS smoke run; no crash, no blank ad frame, no debug surface.
- L10n gate green for every shipped locale — 0
<TRANSLATE>(default set →ai-translated-localization; rejection-grade for 2.1/2.3). - ATT:
NSUserTrackingUsageDescriptionlocalized for every shipped locale; sim-verify the ATT prompt actually fires on a fresh install (drive it with an interactive simulator drive, e.g. idb / simctl tap + screenshot — reviewers reject on the runtime prompt being absent, not just the Info.plist key); ATT primer present in every shipped app. - Restore-Purchases button visible; Remove-Ads restores on reinstall.
- ASC App Privacy answers ==
PrivacyInfo.xcprivacy== AdMob's declared data use. - Screenshots are real captures at spec dimensions (not snapshot baselines).
- Privacy-policy URL set and reachable; no other-platform mentions in any locale's metadata.
- Per-app distinct name/icon/screenshots; differentiation visible in the first screenshot (4.3).
Common mistakes
- Trusting "it compiled / TF accepted it." Upload success ≠ review pass; the gates above are orthogonal to a green build.
- Re-using snapshot PNGs as store screenshots — wrong dims + alpha → 2.3.3.
- Adding the ad SDK but skipping ATT — the single most common ads-app 5.1.2 bounce.
- Filling App Privacy by guesswork — must mirror the actual SDK +
PrivacyInfo.xcprivacy, or it's a 5.1.x mismatch. - Shipping a sibling app as a near-clone — 4.3 spam; sharing code is fine, but each product must have a distinct identity.
Sources
Apple App Store Review Guidelines (developer.apple.com) + Apple App Store
Transparency Report (performance = top rejection cause); Google AdMob iOS privacy
strategies (ATT / UMP / NSUserTrackingUsageDescription). Re-verify guideline
numbers against the live Guidelines before quoting them in a Resolution Center
reply — Apple renumbers.
Related skills
asc-api-automation— how to submit via the ASC REST API once a build exists; this skill covers what content has to be true for that submission to pass review.storekit2-iap-defaults— 3.1.1 implementation: the Remove-Ads IAP and its Restore Purchases control.monetization-sdk-integration— 5.1.2 ATT / PrivacyInfo consequences of shipping AdMob.ai-translated-localization— the L10n flow that keeps every shipped locale's metadata and ATT string complete.