App Store Rejection Diagnostics
SkillCommunicationThis skill helps your AI work through app review rejections and blocked submissions. When an app is rejected or an appeal is needed, your AI can read the rejection message, identify the underlying problem, and produce a matching fix plus a draft appeal.
Available today. Use it from your connected AI after setup.
No other account needed.
After adding the skill, paste the rejection message you received and ask your AI to diagnose it. It will walk you from the message to a fix and, if needed, a draft appeal.
Then ask your AI: use the App Store Rejection Diagnostics skill
What your AI can do with it
- Turn an App Review rejection message into a diagnosis of what went wrong
- Suggest fixes matched to the specific guideline behind the rejection
- Work through a blocked submission systematically
- Draft an appeal when a rejection needs to be contested
What this skill tells your AI
The instructions your AI receives, as published by comeonoliver/skillshub in skills/CharlesWiltgen/Axiom/axiom-app-store-diag/SKILL.md and read by ahel’s review.
Overview
Systematic App Store rejection diagnosis and remediation. 9 diagnostic patterns covering the most common rejection categories including technical, metadata, privacy, business, subjective, and safety violations.
Core principle Most App Store rejections fall into well-known categories. Reading the rejection message carefully and mapping to the correct guideline prevents the #1 mistake: fixing the wrong thing and getting rejected again for the same reason.
Most developers waste 1-2 weeks on rejection cycles because they skim the rejection message, assume the cause, and "fix" something that wasn't the problem. This skill provides systematic diagnosis from rejection message to targeted fix.
Red Flags — Suspect Submission Issue
If you see ANY of these, suspect a submission issue and use this skill:
-
Rejection message cites a specific guideline number
-
"Binary Rejected" without clear guideline (technical gate failure)
-
Same app rejected multiple times for different reasons
-
"Metadata Rejected" (no code change needed)
-
Rejection mentions "privacy" or "data collection"
-
Rejection mentions "login" or "authentication"
-
Reviewer asks for demo account or more information
-
❌ FORBIDDEN "The reviewer is wrong, let's just resubmit"
- Re-read the rejection. App Review is right 95% of the time.
- Resubmitting without changes wastes 3-7 days per cycle.
- If you genuinely disagree, use the appeal process (Pattern 7).
Mandatory First Steps
ALWAYS do these BEFORE changing any code:
- Read the FULL rejection message — Don't skim. Copy the exact text. Note every guideline number cited.
- Identify rejection type:
- "App Rejected" → Guideline violation, code/content fix needed
- "Metadata Rejected" → ASC metadata issue, no build needed
- "Binary Rejected" → Technical gate (SDK, manifest, encryption)
- "Removed from Sale" → Post-approval enforcement
- Check the specific guideline — Look up the exact number in app-store-ref
- Screenshot the rejection — Save for team communication and appeal reference
- Check App Review messages in ASC — Sometimes they ask for information, not reject
What this tells you
| Rejection Type | What Changed | Next Step |
|---|---|---|
| "App Rejected" + Guideline 2.1 | App crashed or had placeholders | Pattern 1 |
| "Metadata Rejected" | Screenshots or description wrong | Pattern 2 |
| "App Rejected" + Guideline 5.1 | Privacy policy or manifest gaps | Pattern 3 |
| "App Rejected" + Guideline 4.8 | Missing Sign in with Apple | Pattern 4 |
| "App Rejected" + Guideline 3.x | Business/monetization violation | Pattern 5 |
| "Binary Rejected" / no guideline | SDK, signing, or encryption issue | Pattern 6 |
| Reviewer seems incorrect | Genuine misunderstanding | Pattern 7 |
| Guideline 1.x cited | Safety/content issue | Pattern 9 |
| Guideline 4.1-4.3 cited | Design/originality issue | Pattern 8 |
MANDATORY INTERPRETATION
Before changing ANY code, identify ONE of these:
- If "App Rejected" with guideline number → Map to specific pattern (1-5)
- If "Metadata Rejected" → Fix in ASC, no build required (Pattern 2)
- If "Binary Rejected" → Technical gate failure (Pattern 6)
- If multiple guidelines cited → Fix ALL cited issues, not just the first one. Both binary AND metadata can be rejected simultaneously — binary issues need a new build, metadata issues can be fixed in ASC. Fix both before resubmitting.
- If reviewer asks for information → Reply in ASC before making code changes
If rejection reason is unclear or contradictory
- STOP. Do NOT start fixing code yet
- Reply to App Review in ASC asking for clarification
- Include screenshots or video showing the feature working
- Wait for response before making changes
Decision Tree
App Store rejection?
│
├─ What does the rejection say?
│ │
│ ├─ Cites Guideline 2.1?
│ │ ├─ App crashed during review? → Pattern 1 (check crash logs)
│ │ ├─ Placeholder content found? → Pattern 1 (search project)
│ │ ├─ Broken links? → Pattern 1 (verify URLs)
│ │ └─ Missing demo credentials? → Pattern 1 (provide in review notes)
│ │
│ ├─ Cites Guideline 2.3?
│ │ ├─ Screenshots don't match app? → Pattern 2 (retake screenshots)
│ │ ├─ Description promises missing features? → Pattern 2 (update text)
│ │ └─ Keywords contain trademarks? → Pattern 2 (remove keywords)
│ │
│ ├─ Cites Guideline 5.1?
│ │ ├─ Privacy policy missing/inaccessible? → Pattern 3 (add/fix policy)
│ │ ├─ Purpose strings missing? → Pattern 3 (add to Info.plist)
│ │ ├─ Privacy manifest incomplete? → Pattern 3 (update PrivacyInfo)
│ │ └─ Tracking without ATT? → Pattern 3 (implement ATT)
│ │
│ ├─ Cites Guideline 4.8?
│ │ ├─ Third-party login without SIWA? → Pattern 4 (add SIWA)
│ │ ├─ SIWA button hidden or broken? → Pattern 4 (fix prominence)
│ │ └─ Exception applies? → Pattern 4 (verify exemption)
│ │
│ ├─ Cites Guideline 3.x?
│ │ ├─ Digital content without IAP? → Pattern 5 (implement StoreKit)
│ │ ├─ Subscription issues? → Pattern 5 (fix terms/value)
│ │ └─ Loot box odds not disclosed? → Pattern 5 (add disclosure)
│ │
│ ├─ "Binary Rejected" / no guideline?
│ │ ├─ Wrong SDK version? → Pattern 6 (update Xcode)
│ │ ├─ Privacy manifest missing? → Pattern 6 (add PrivacyInfo)
│ │ ├─ Encryption not declared? → Pattern 6 (add ITSAppUsesNonExemptEncryption)
│ │ └─ Invalid signing? → Pattern 6 (regenerate provisioning)
│ │
│ ├─ "I believe the reviewer is wrong"?
│ │ └─ → Pattern 7 (Appeal Process)
│ │
│ ├─ Cites Guideline 1.x?
│ │ └─ Safety/content issue → Pattern 9
│ │
│ └─ Cites Guideline 4.1-4.3?
│ └─ Design/originality issue → Pattern 8
Pattern Selection Rules (MANDATORY)
Before proceeding to a pattern:
- Copy the exact rejection text — Word for word, including guideline numbers
- Match guideline number to pattern — Don't guess, map directly
- If multiple guidelines cited — Fix ALL of them before resubmitting
- If no guideline number — Likely Binary Rejected, start with Pattern 6
- If unsure — Reply to reviewer for clarification first
Apply ONE pattern at a time
- Identify the correct pattern from the rejection message
- Implement the complete fix for that pattern
- If multiple guidelines cited, fix each one before resubmitting
- DO NOT resubmit after fixing only one of multiple cited issues
FORBIDDEN
- Resubmitting without changes hoping for a different reviewer
- Skimming the rejection and guessing the fix
- Fixing only the first cited guideline when multiple are cited
- Arguing emotionally in App Review messages
- Disabling privacy features to avoid Guideline 5.1
Diagnostic Patterns
Pattern 1: Guideline 2.1 — App Completeness
Time cost 3-7 days per rejection cycle
Symptom
- Rejection citing "App Completeness"
- Crashes during review
- Placeholder content found
- Broken links (support URL, privacy policy, in-app links)
- Missing demo credentials for login-required apps
Common causes
- App crashes on reviewer's device (different OS version, different device class)
- Placeholder text or images visible in any screen
- Broken links (support URL, privacy policy, in-app links)
- Missing demo credentials for login-required apps
- Backend service was down during review window
Diagnosis
# 1. Check crash logs in App Store Connect
# Xcode Organizer > Crashes > Filter by version
# 2. Search for placeholder strings
grep -r "Lorem\|TODO\|FIXME\|placeholder\|sample\|test data" \
--include="*.swift" --include="*.storyboard" --include="*.xib" .
# 3. Verify all URLs resolve
curl -sI "https://your-support-url.com" | head -1
curl -sI "https://your-privacy-policy-url.com" | head -1
# 4. Test on latest shipping iOS
# Check ASC for specific iOS version reviewer used (noted in rejection)
Fix
// ❌ WRONG — Demo credentials that expire
// Review Notes: "Login: test@test.com / password123"
// (If this account expires or gets locked, instant rejection)
// ✅ CORRECT — Permanent demo credentials
// Review Notes:
// "Demo Account: demo@yourapp.com / ReviewDemo2024!
// This account has pre-populated sample data.
// Account will not expire during review period."
// ❌ WRONG — Placeholder still in code
Text("Lorem ipsum dolor sit amet")
// ✅ CORRECT — Real content in every screen
Text("Welcome to YourApp. Get started by creating your first project.")
Verification
- Submit to TestFlight first, test every screen on multiple devices
- Verify ALL URLs load successfully (including privacy policy from within the app)
- Ensure demo credentials work and won't expire
- Test on the specific iOS version mentioned in rejection (check rejection message or ASC Activity → Build → review device info)
- Monitor backend uptime during review window (don't deploy during review)
- Check ASC crash logs (Xcode Organizer → Crashes) for the specific device and OS version the reviewer used
Pattern 2: Guideline 2.3 — Metadata Issues
Time cost 1-3 days (metadata fix, no build needed)
Symptom
- "Metadata Rejected" — no code change required
- Screenshots don't match current app UI
- Description promises features not in the app
- Keywords contain trademarked or competitor names
Common causes
- Screenshots show old UI or features that no longer exist
- Description promises features not yet implemented
- Keywords contain trademarked terms or competitor names
- App name implies functionality that doesn't exist
- Category selection doesn't match app's primary function
Diagnosis
Compare every screenshot to current app UI. Read description word by word — does each claim exist in the app? Check keywords against Apple's trademark list.
Checklist:
☐ Every screenshot matches current build
☐ Every feature mentioned in description exists and works
☐ No trademarked terms in keywords (e.g., "Instagram", "Uber")
☐ App icon appropriate for all audiences
☐ Age rating matches actual content
☐ Category selection accurate
☐ "What's New" text matches actual changes
Fix
Update metadata directly in App Store Connect. No new build needed for metadata-only rejections.
✅ Take fresh screenshots FROM THE SUBMITTED BUILD (not dev build)
✅ Remove any features from description that aren't fully functional
✅ Replace trademarked keywords with generic equivalents
("photo sharing" not "Instagram-like")
✅ Ensure "What's New" describes changes in this specific version
Verification
- Take screenshots on the exact build version submitted
- Have someone outside the team read the description and verify each claim
- Search keywords for any trademarked terms
Pattern 3: Guideline 5.1 — Privacy Violations
Time cost 3-10 days (code + manifest + policy changes)
Symptom
- Rejection citing privacy policy, data collection, purpose strings, or tracking
- Privacy manifest missing required reason API declarations
- Third-party SDK collects data not disclosed
Common causes
- Privacy policy missing or not accessible from within the app
- Privacy policy doesn't match actual data collection
- Missing purpose strings for permission requests
- Privacy manifest (PrivacyInfo.xcprivacy) missing required reason API declarations
- Third-party SDK collects data not disclosed in privacy nutrition labels
- App tracks users without ATT (App Tracking Transparency) consent
Diagnosis
// 1. Check: Is privacy policy URL in ASC AND accessible from within the app?
// Both are required. In-app access is commonly missed.
// 2. Check purpose strings
// ❌ WRONG — Generic purpose string
"NSCameraUsageDescription" = "Camera access needed"
// ✅ CORRECT — Specific purpose string explaining why
"NSCameraUsageDescription" = "Take photos for your profile picture and upload to your account"
// 3. Generate privacy report
// Xcode: Product → Archive → Generate Privacy Report
// This shows aggregate data from all frameworks and your code
// 4. Check privacy manifest
// Verify PrivacyInfo.xcprivacy exists in your app target
// AND in every framework target that uses required reason APIs
Fix
Purpose strings (Info.plist)
<!-- Every permission MUST have a specific, honest purpose string -->
<key>NSCameraUsageDescription</key>
<string>Take photos for your profile picture and upload to your account</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>Show nearby restaurants on the map and calculate delivery distance</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>Select photos from your library to attach to messages</string>
Privacy manifest (PrivacyInfo.xcprivacy)
<!-- Required if you use any "required reason" APIs -->
<!-- UserDefaults, file timestamp, disk space, system boot time, etc. -->
<dict>
<key>NSPrivacyAccessedAPITypes</key>
<array>
<dict>
<key>NSPrivacyAccessedAPIType</key>
<string>NSPrivacyAccessedAPICategoryUserDefaults</string>
<key>NSPrivacyAccessedAPITypeReasons</key>
<array>
<string>CA92.1</string>
</array>
</dict>
</array>
</dict>
Privacy policy requirements
Your privacy policy MUST specifically list:
☐ What data is collected (every type)
☐ How data is collected (automatically, user-provided)
☐ All uses of collected data
☐ Third-party sharing (who, why)
☐ Data retention period
☐ How users can request deletion
☐ Contact information for privacy inquiries
App Tracking Transparency
// Required if app tracks users across other companies' apps/websites
import AppTrackingTransparency
func requestTrackingPermission() {
ATTrackingManager.requestTrackingAuthorization { status in
switch status {
case .authorized:
// Enable tracking (analytics, ad attribution)
break
case .denied, .restricted, .notDetermined:
// Disable ALL tracking
// Remove IDFA access, disable third-party analytics that track
break
@unknown default:
break
}
}
}
Verification
- Generate Privacy Report (Product > Archive > Generate Privacy Report) and verify all APIs declared
- Test privacy policy link from within the app (not just browser)
- Verify every permission request has a specific, honest purpose string
- Audit all third-party SDKs for undisclosed data collection
- Test ATT flow: deny tracking, verify app works correctly without it
Pattern 4: Guideline 4.8 — Missing Sign in with Apple
Time cost 3-7 days (implementation + resubmit)
Symptom
- Rejection citing Guideline 4.8
- App has third-party login but no Sign in with Apple (SIWA)
Common causes
- App has Google/Facebook/Twitter login but no SIWA
- SIWA button exists but doesn't work
- SIWA not offered at equal prominence (hidden or secondary)
- SIWA flow doesn't handle credential revocation
Diagnosis
The rule is simple: If your app uses ANY third-party or social login service, you MUST offer Sign in with Apple as an equivalent option.
Exceptions (SIWA not required):
- App exclusively uses your company's own accounts
- App is for education (managed Apple IDs)
- App requires government or institution ID
- App is a client for a third-party service (e.g., email client)
Fix
import AuthenticationServices
// ✅ CORRECT — SIWA at same prominence as other login options
struct LoginView: View {
var body: some View {
VStack(spacing: 16) {
// Sign in with Apple — MUST be at same visual level
SignInWithAppleButton(.signIn) { request in
request.requestedScopes = [.fullName, .email]
} onCompletion: { result in
switch result {
case .success(let authorization):
handleAuthorization(authorization)
case .failure(let error):
handleError(error)
}
}
.signInWithAppleButtonStyle(.black)
.frame(height: 50)
// Other login options at same size/prominence
GoogleSignInButton()
.frame(height: 50)
}
}
func handleAuthorization(_ authorization: ASAuthorization) {
guard let credential = authorization.credential
as? ASAuthorizationAppleIDCredential else { return }
let userIdentifier = credential.user
let fullName = credential.fullName
let email = credential.email
// Note: fullName and email only provided on FIRST sign-in
// Store them immediately — they won't be provided again
// Send to your backend for account creation/login
}
}
// ✅ Handle credential revocation (required for account deletion support)
func checkCredentialState() {
let provider = ASAuthorizationAppleIDProvider()
provider.getCredentialState(forUserID: storedUserIdentifier) { state, error in
switch state {
case .authorized:
break // User is still signed in
case .revoked:
// User revoked credentials — sign out immediately
signOut()
case .notFound:
// Credential not found — show sign-in
showLogin()
@unknown default:
break
}
}
}
Verification
- SIWA button is visually equal to other login buttons (same size, same screen)
- Full SIWA flow works: sign in, account creation, credential check
- Handle revocation: user can revoke in Settings > Apple ID > Sign-In & Security
- Test account deletion flow (required since June 2022)
Pattern 5: Guideline 3.x — Business/Monetization
Time cost 3-14 days (may require architectural changes)
Symptom
- Rejection citing business guidelines
- IAP requirements not met
- Subscription doesn't provide ongoing value
- External payment for digital content
Common causes
- Digital content unlocked without IAP (using external payment for in-app features)
- Subscription doesn't provide ongoing value (one-time content sold as subscription)
- Loot box or random item purchase odds not disclosed
- Deceptive subscription flow (dark patterns, misleading free trial)
- IAP metadata incomplete or not submitted for review
Diagnosis
The key question: Is any digital content or feature unlocked without Apple IAP?
Digital goods/features → MUST use Apple IAP
Examples: premium features, virtual currency, ad removal, content
packs, subscription access to digital content
Physical goods/services → MAY use external payment
Examples: physical merchandise, ride-sharing, food delivery,
person-to-person services
Certain categories → MAY use external payment (3.1.3 exceptions)
Examples: "reader" apps (Kindle, Netflix, Spotify), one-to-one
real-time services
Fix
// ❌ WRONG — Unlocking features via external payment
func unlockPremium(receiptFromServer: String) {
// Bypass Apple IAP → rejection
UserDefaults.standard.set(true, forKey: "isPremium")
}
// ✅ CORRECT — StoreKit 2 for all digital goods
import StoreKit
func purchasePremium() async throws {
let product = try await Product.products(for: ["com.app.premium"]).first!
let result = try await product.purchase()
switch result {
case .success(let verification):
let transaction = try checkVerified(verification)
// Unlock feature
await transaction.finish()
case .pending:
// Payment pending (Ask to Buy, etc.)
break
case .userCancelled:
break
@unknown default:
break
}
}
// ✅ Loot box disclosure (required if random items for purchase)
struct LootBoxView: View {
var body: some View {
VStack {
Text("Mystery Box — $4.99")
Text("Contents are random. Odds:")
.font(.caption)
// MUST disclose odds before purchase
VStack(alignment: .leading) {
Text("Common item: 60%")
Text("Rare item: 30%")
Text("Legendary item: 10%")
}
.font(.caption2)
.foregroundStyle(.secondary)
}
}
}
Verification
- ALL digital content/features use Apple IAP (StoreKit 2)
- IAP products submitted and approved in ASC before app submission
- Subscription terms clearly communicated before purchase screen
- Free trial duration and auto-renewal price clearly visible
- Loot box odds disclosed before any purchase
- No external payment links for digital goods (unless "reader" app exception applies)
Pattern 6: Binary Rejected — Technical Gates
Time cost 1-3 days (build configuration fix)
Symptom
- "Binary Rejected" with no specific guideline
- Automated rejection during processing
- Build stuck in "Processing" state
Common causes
- Built with outdated SDK version (must meet Apple's minimum)
- Privacy manifest (PrivacyInfo.xcprivacy) missing or invalid
- Encryption compliance not declared (ITSAppUsesNonExemptEncryption)
- Invalid signing or provisioning profile
- Missing required device capabilities in Info.plist
- App uses private or deprecated APIs
- App binary too large without on-demand resources
Diagnosis
# 1. Check Xcode and SDK version
xcodebuild -version
# Must be current or previous major Xcode version
# 2. Check processing logs in ASC
# App Store Connect → My Apps → [App] → Activity → Build → Processing Log
# 3. Verify encryption declaration
grep -c "ITSAppUsesNonExemptEncryption" Info.plist
# Must exist and be set to YES or NO
# 4. Check provisioning
security cms -D -i embedded.mobileprovision 2>/dev/null | head -20
# Verify not expired
# 5. Check for private API usage
# Xcode: Product → Archive → Distribute App → Validate App
# This catches most private API issues before submission
Fix
<!-- Encryption compliance (Info.plist) -->
<!-- If app uses ONLY standard HTTPS (URLSession, etc.) -->
<key>ITSAppUsesNonExemptEncryption</key>
<false/>
<!-- If app uses custom encryption beyond HTTPS -->
<key>ITSAppUsesNonExemptEncryption</key>
<true/>
<!-- Then upload export compliance documentation in ASC:
App Store Connect → My Apps → [App] → App Information →
Export Compliance Information → Upload documentation
You may also need to file an annual self-classification
report with the US Bureau of Industry and Security (BIS) -->
Encryption decision flow:
- Does your app use ONLY standard OS-provided HTTPS (URLSession, Alamofire)? → Set
false, done - Does your app call OpenSSL, libsodium, or custom crypto directly? → Set
true, upload BIS docs - Does your app implement proprietary encryption protocols? → Set
true, upload BIS docs - Unsure? → Run
strings YourApp | grep -i "openssl\|libcrypto\|CCCrypt"to check
# Validate before submitting
# Xcode: Product → Archive → Distribute App → Validate App
# Catches ~80% of binary rejection causes
# Clean build if signing issues
rm -rf ~/Library/Developer/Xcode/DerivedData
# Re-download provisioning profiles in Xcode Preferences → Accounts
Verification
- Run "Validate App" in Xcode Organizer before submitting
- Verify Xcode version meets Apple's current requirements
- Check PrivacyInfo.xcprivacy exists and is included in the app bundle
- Verify ITSAppUsesNonExemptEncryption key is present
- Ensure provisioning profile is not expired
- Test app on physical device with release configuration
Pattern 7: Appeal Process
Time to resolve 3-14 days
When to use
- You genuinely believe the reviewer misunderstood your app
- You believe the wrong guideline was applied
- Your app complies and you have evidence
Shortened here. Read the whole file on GitHub.
Signals
- GitHub stars
- 63
- Forks
- 22
- Last commit
- Jun 2026
Advanced
- Catalog kind
- skill
- Gateway key
axiom-app-store-diag- Source
- github.com/comeonoliver/skillshub