# App Store Review Rejections

> Use when preparing an App Store submission, diagnosing an App Review rejection / Resolution Center message, or hardening a free game/app with ads + Remove-Ads IAP + CloudKit + Game Center against the rejection classes it realistically hits. Covers guideline 2.1 / 2.3.x (incl. 2.3.6 age rating) / 3.1.1 / 4.0 / 4.2 / 4.3 / 5.1.1 / 5.1.2 plus ASC export compliance, the ATT-vs-AdMob trap, privacy-label parity, and a pre-submit checklist.

- Skill: `wei18/app-store-review-rejections` (Agent Skill)
- Install (CLI): `npx skillmds@latest add wei18/app-store-review-rejections`
- Raw SKILL.md: https://api.skillmd.com/api/skills/wei18/app-store-review-rejections/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: wei18 (https://skillmd.com/u/wei18)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/wei18/app-store-review-rejections

---


# 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-automation` got 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")

1. Clean-device + oldest-OS smoke run; no crash, no blank ad frame, no debug surface.
2. L10n gate green for every shipped locale — 0 `<TRANSLATE>` (default set → `ai-translated-localization`; rejection-grade for 2.1/2.3).
3. ATT: `NSUserTrackingUsageDescription` localized 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.
4. Restore-Purchases button visible; Remove-Ads restores on reinstall.
5. ASC App Privacy answers == `PrivacyInfo.xcprivacy` == AdMob's declared data use.
6. Screenshots are real captures at spec dimensions (not snapshot baselines).
7. Privacy-policy URL set and reachable; no other-platform mentions in any locale's metadata.
8. 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.

