
Axiom Shipping
- 890 installs
- 1.1k repo stars
- Updated August 3, 2026
- charleswiltgen/axiom
axiom-shipping is an agent skill that runs App Store Connect submission checklists, rejection fixes, privacy manifests, and appeals for developers shipping iOS and macOS apps.
About
axiom-shipping is an MIT-licensed agent skill from charleswiltgen/axiom that guides preparing any iOS or macOS app for App Store submission and handling rejections afterward. The skill covers submission checklists, metadata requirements including screenshots descriptions and keywords, privacy manifests and nutrition labels, age ratings and content classification, export compliance and encryption declarations, EU DSA trader status, account deletion and Sign in with Apple requirements, and build upload processing. Agents must use axiom-shipping when preparing to submit an app, responding to App Store rejection for any guideline, writing appeals, or answering privacy manifest questions. The checklist-driven workflow reduces missed compliance steps that commonly trigger review delays. Use it before first submission, after a rejection letter arrives, or when updating privacy manifests for a new SDK dependency.
- Mandatory trigger: use when preparing ANY app for submission or handling rejections
- Quick-reference routing to app-store-submission and app-store-ref companion docs in the axiom repo
- Covers metadata, screenshots, keywords, privacy manifests, and nutrition labels
- Addresses age ratings, export encryption, EU DSA trader status, and Sign in with Apple
- Includes build upload issues, first-time submission, and App Review appeals plus WWDC25 Connect changes
Axiom Shipping by the numbers
- 890 all-time installs (skills.sh)
- +40 installs in the week ending Aug 5, 2026 (Skillselion tracking)
- Ranked #31 of 248 Release Management skills by installs in the Skillselion catalog
- Security screen: MEDIUM risk (skills.sh audit)
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/charleswiltgen/axiom --skill axiom-shippingAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 890 |
|---|---|
| repo stars | ★ 1.1k |
| Security audit | 1 / 3 scanners passed |
| Last updated | August 3, 2026 |
| Repository | charleswiltgen/axiom ↗ |
How do you fix an App Store rejection?
Run App Store Connect submission, rejection fixes, privacy manifests, and appeals with checklist-driven agent guidance for iOS/macOS apps.
Who is it for?
iOS and macOS developers submitting to App Store Connect who need checklist-driven compliance for privacy manifests, metadata, and rejections.
Skip if: Android Play Store publishers or web-only SaaS teams with no native Apple app distribution.
When should I use this skill?
A developer prepares an iOS or macOS app for App Store submission, receives a rejection, or needs privacy manifest and nutrition label guidance.
What you get
Submission checklist completion, privacy manifest updates, metadata fixes, and appeal draft for App Store Connect.
- submission checklist
- privacy manifest guidance
- rejection remediation plan
Files
Shipping & App Store
You MUST use this skill when preparing to submit ANY app, handling App Store rejections, or working on release workflow.
When to Use
Use this skill when you encounter:
- Preparing an app for App Store submission
- App Store rejection (any guideline)
- Metadata requirements (screenshots, descriptions, keywords)
- Privacy manifest and nutrition label questions
- Age rating and content classification
- Export compliance and encryption declarations
- EU DSA trader status
- Account deletion or Sign in with Apple requirements
- Build upload and processing issues
- App Review appeals
- WWDC25/WWDC26 App Store Connect changes
- First-time submission workflow
Quick Reference
| Symptom / Task | Reference |
|---|---|
| How do I submit my app? | See skills/app-store-submission.md |
| Pre-flight checklist | See skills/app-store-submission.md |
| First-time submission | See skills/app-store-submission.md |
| Encryption compliance | See skills/app-store-submission.md |
| Accessibility Nutrition Labels | See skills/app-store-submission.md |
| Metadata field requirements | See skills/app-store-ref.md |
Product Page Header, Asset Library, search visuals OS27 | See skills/app-store-ref.md (Part 11) |
Retention Messaging (subscription cancellation flow) OS27 | See skills/app-store-ref.md (Part 11) |
Group / volume subscription selling (ABM, ASM, volume pricing) OS27 | See skills/app-store-ref.md (Part 11) |
| Guideline number lookup | See skills/app-store-ref.md |
| Privacy manifest schema | See skills/app-store-ref.md |
| Age rating tiers | See skills/app-store-ref.md |
| EU DSA compliance | See skills/app-store-ref.md |
| WWDC25/WWDC26 ASC changes | See skills/app-store-ref.md |
| App was rejected | See skills/app-store-diag.md |
| Guideline 2.1/4.2/4.3 rejection | See skills/app-store-diag.md |
| Writing an appeal | See skills/app-store-diag.md |
| Repeated rejections | See skills/app-store-diag.md |
| App Review Guidelines reference | See skills/app-review-guidelines.md |
| Expert review checklist | See skills/expert-review-checklist.md |
| Crash data in App Store Connect | See skills/app-store-connect-ref.md |
| TestFlight crash reports | See skills/app-store-connect-ref.md |
| ASC metrics dashboards | See skills/app-store-connect-ref.md |
| Beta tester crash report | See skills/testflight-triage.md |
| Production corpus triage (Sentry, ASC — multiple grouped issues) | See skills/production-triage.md + triage-analyzer agent or /axiom:triage |
| Crash log symbolication (.ips / MetricKit / .crash) | See axiom-tools (skills/xcsym-ref.md) or /axiom:analyze-crash; skills/testflight-triage.md for the full TF workflow |
| Automate App Store Connect | See skills/asc-mcp.md |
| Submit build programmatically | See skills/asc-mcp.md |
| Manage TestFlight via MCP | See skills/asc-mcp.md |
| ITMS signing error on upload | See axiom-security (skills/code-signing-diag.md) |
| Certificate/profile mismatch | See axiom-security (skills/code-signing-diag.md) |
| Code signing setup | See axiom-security (skills/code-signing.md) |
| App Clips (size tiers, invocation, AASA, launch experience) | See skills/app-clips.md |
| App Clip entitlements / size / data-sharing reference | See skills/app-clips-ref.md |
| Apple Pay / Wallet / Tap to Pay payments | See axiom-payments suite |
| Shipping update with Claude model-ID change (4.6 → 4.7, etc.) | See `claude-api` skill (external) + this skill for submission |
| Switching cloud AI provider in-app (OpenAI → Claude, etc.) | See `claude-api` skill (external) + this skill for submission |
Routing Logic
1. Pre-Submission Preparation → app-store-submission
Triggers:
- "How do I submit my app?"
- "What do I need before submitting?"
- Preparing for first submission
- Pre-flight checklist needed
- Screenshot requirements
- Metadata completeness check
- Encryption compliance questions
- Accessibility Nutrition Labels
- Privacy manifest requirements for submission
Why app-store-submission: Discipline skill with 8 anti-patterns, decision trees, and pressure scenarios. Prevents the mistakes that cause 90% of rejections.
Reference: skills/app-store-submission.md
---
2. Metadata, Guidelines, and API Reference → app-store-ref
Triggers:
- "What fields are required in App Store Connect?"
- "What's the max length for app description?"
- Specific guideline number lookup
- Privacy manifest schema details
- Age rating tiers and questionnaire
- IAP submission metadata
- EU DSA compliance details
- Build upload methods
- WWDC25 and WWDC26 changes to App Store Connect
Why app-store-ref: 11-part reference covering every metadata field, guideline, and compliance requirement with exact specifications.
Reference: skills/app-store-ref.md
---
3. Rejection Troubleshooting → app-store-diag
Triggers:
- "My app was rejected"
- "Guideline 2.1 rejection"
- "Binary was rejected"
- Guideline 4.2 or 4.3 rejection (app too simple, web wrapper, spam, duplicate)
- Guideline 1.x rejection (objectionable content, UGC moderation, Kids category)
- How to respond to a rejection
- Writing an appeal
- Understanding rejection messages
- Third or repeated rejection
- Resolution Center communication
Why app-store-diag: 9 diagnostic patterns mapping rejection types to root causes and fixes, including subjective rejections (4.2/4.3, 1.x). Includes appeal writing guidance and crisis scenario for repeated rejections.
Reference: skills/app-store-diag.md
---
4. Privacy & Security Compliance → security-privacy-scanner (Agent)
Triggers:
- "Scan my code for privacy issues before submission"
- Hardcoded API keys or secrets
- Missing privacy manifest
- Required Reason API declarations
- ATS violations
Why security-privacy-scanner: Autonomous agent that scans for security vulnerabilities and privacy compliance issues that cause rejections.
Invoke: Launch security-privacy-scanner agent or /axiom:audit security
---
5. IAP Review Issues → iap-auditor (Agent)
Triggers:
- IAP rejected or not working
- Missing transaction.finish()
- Missing restore purchases
- Subscription tracking issues
Why iap-auditor: Scans IAP code for the patterns that cause StoreKit rejections.
Invoke: Launch iap-auditor agent
---
6. Screenshot Validation → screenshot-validator (Agent)
Triggers:
- "Check my App Store screenshots"
- "Are my screenshots the right dimensions?"
- "Validate screenshots before submission"
- "Review my marketing screenshots"
- Screenshot content or dimension questions
Why screenshot-validator: Multimodal agent that visually inspects each screenshot for placeholder text, wrong dimensions, debug artifacts, broken UI, and competitor references. Catches issues that manual review misses.
Invoke: Launch screenshot-validator agent or /axiom:audit screenshots
---
7. Programmatic ASC Access → asc-mcp
Triggers:
- "Automate App Store Connect"
- "Submit build programmatically"
- "Manage TestFlight from Claude"
- "Respond to reviews via API"
- "Set up asc-mcp"
- "Distribute to TestFlight groups via MCP"
- "Create a new version without opening ASC"
Why asc-mcp: Workflow-focused skill teaching Claude to use asc-mcp MCP tools for release pipelines, TestFlight distribution, review management, and feedback triage — all without leaving Claude Code.
Reference: skills/asc-mcp.md
---
8. Post-Submission Monitoring → app-store-connect-ref
Triggers:
- "How do I view crash data in App Store Connect?"
- "Where are my TestFlight crash reports?"
- "How do I read ASC metrics dashboards?"
- Post-release crash investigation
- Downloading crash logs from ASC
Why app-store-connect-ref: ASC navigation for crash dashboards, TestFlight feedback, performance metrics, and data export workflows.
Reference: skills/app-store-connect-ref.md
---
9. Beta Crash Triage → testflight-triage
Triggers:
- Beta tester reports a crash
- Crash appears in Organizer or App Store Connect
- Crash logs need symbolication
- Post-release crash investigation (single file or Organizer)
Why testflight-triage: Systematic crash triage from symbolication through root cause analysis. Uses xcsym as the first step (parse → discover dSYMs → symbolicate → categorize with pattern_tag → emit structured JSON).
Reference: skills/testflight-triage.md. For the xcsym subcommand/exit-code reference, see axiom-tools (skills/xcsym-ref.md). For the one-call agent workflow, /axiom:analyze-crash.
---
10a. Production Corpus Triage → production-triage / triage-analyzer
Triggers:
- "Triage my Sentry crashes"
- "What are the top crash families in production?"
- "Show me which issues to fix first from App Store Connect"
- Multiple grouped issues from an aggregator (Sentry, ASC) — dozens of issues, not a single file
- "Which of these crashes are real bugs vs noise?"
- Corpus-level hang triage ("Are my ANR reports real blocks?")
Why production-triage: Corpus-level triage requires fetching from an aggregator, classifying each issue, noise-flagging suspension false-positives, and clustering into root-cause families. testflight-triage covers the Organizer/single-file path; production-triage covers the aggregate/multi-issue path.
Reference: skills/production-triage.md (fetch + NormalizedReport schema + flag-never-hide rule). Agent: triage-analyzer or /axiom:triage sentry / /axiom:triage asc.
---
10. Distribution Signing Issues → code-signing / code-signing-diag
Triggers:
- ITMS-90035 Invalid Signature on upload
- ITMS-90161 Invalid Provisioning Profile
- "No signing certificate found" when archiving
- Certificate expired before submission
- Archive succeeds but export/upload fails
- Profile doesn't match bundle ID
- Entitlement mismatch on upload
Why code-signing: Distribution signing errors are the #1 cause of upload failures. Diagnosing with CLI tools takes 5 minutes. code-signing-diag has 6 decision trees mapping ITMS errors to root causes.
Reference: See axiom-security (skills/code-signing-diag.md) (troubleshooting) or See axiom-security (skills/code-signing.md) (setup)
---
11. App Clips → app-clips
Triggers:
- Adding an App Clip target, or choosing an invocation method
- "What's the App Clip size limit?" / build exceeds maximum size
- Associated domains / AASA for App Clip links
- App Store Connect default and advanced launch experiences
- Handing App Clip data off to the full app on upgrade
- "My App Clip link does nothing"
Why app-clips: App Clips ship embedded in the full app and live under tight size (10/15/100 MB), entitlement, and capability limits. The discipline covers the size tiers, entitlements, AASA, and data handoff; the reference has the tables.
Reference: skills/app-clips.md, skills/app-clips-ref.md
---
Decision Tree
digraph shipping {
"Shipping question?" [shape=diamond];
"Rejected?" [shape=diamond];
"Post-submission monitoring?" [shape=diamond];
"Beta crash triage?" [shape=diamond];
"Automate via MCP?" [shape=diamond];
"Screenshot review?" [shape=diamond];
"Need specific specs?" [shape=diamond];
"IAP issue?" [shape=diamond];
"Want code scan?" [shape=diamond];
"Signing error?" [shape=diamond];
"skills/app-store-submission.md" [shape=box, label="app-store-submission\n(pre-flight checklist)"];
"skills/app-store-ref.md" [shape=box, label="app-store-ref\n(metadata/guideline specs)"];
"skills/app-store-diag.md" [shape=box, label="app-store-diag\n(rejection troubleshooting)"];
"skills/app-store-connect-ref.md" [shape=box, label="app-store-connect-ref\n(ASC dashboards/metrics)"];
"skills/testflight-triage.md" [shape=box, label="testflight-triage\n(beta crash triage)"];
"security-privacy-scanner" [shape=box, label="security-privacy-scanner\n(Agent)"];
"iap-auditor" [shape=box, label="iap-auditor\n(Agent)"];
"screenshot-validator" [shape=box, label="screenshot-validator\n(Agent)"];
"skills/asc-mcp.md" [shape=box, label="asc-mcp\n(MCP tool workflows)"];
"axiom-security/code-signing" [shape=box, label="axiom-security\n(distribution signing)"];
"Shipping question?" -> "Rejected?" [label="yes, about to submit or general"];
"Rejected?" -> "skills/app-store-diag.md" [label="yes, app was rejected"];
"Rejected?" -> "Post-submission monitoring?" [label="no"];
"Post-submission monitoring?" -> "skills/app-store-connect-ref.md" [label="yes, crash data/metrics"];
"Post-submission monitoring?" -> "Beta crash triage?" [label="no"];
"Beta crash triage?" -> "skills/testflight-triage.md" [label="yes, beta crash/symbolication"];
"Beta crash triage?" -> "Automate via MCP?" [label="no"];
"Automate via MCP?" -> "skills/asc-mcp.md" [label="yes, programmatic ASC access"];
"Automate via MCP?" -> "Screenshot review?" [label="no"];
"Screenshot review?" -> "screenshot-validator" [label="yes, validate screenshots"];
"Screenshot review?" -> "Need specific specs?" [label="no"];
"Need specific specs?" -> "skills/app-store-ref.md" [label="yes, looking up field/guideline"];
"Need specific specs?" -> "IAP issue?" [label="no"];
"IAP issue?" -> "iap-auditor" [label="yes"];
"IAP issue?" -> "Want code scan?" [label="no"];
"Want code scan?" -> "Signing error?" [label="no"];
"Want code scan?" -> "security-privacy-scanner" [label="yes, scan for privacy/security"];
"Signing error?" -> "axiom-security/code-signing" [label="yes, ITMS/cert/profile error"];
"Signing error?" -> "skills/app-store-submission.md" [label="no, general prep"];
}Simplified:
1. App was rejected? → skills/app-store-diag.md 2. Post-submission crash data/metrics? → skills/app-store-connect-ref.md 3. Beta crash triage/symbolication (Organizer or single file)? → skills/testflight-triage.md 4. Production corpus triage (Sentry/ASC, multiple grouped issues)? → skills/production-triage.md + triage-analyzer agent 5. Automate ASC via MCP tools? → skills/asc-mcp.md 6. Validate screenshots? → screenshot-validator (Agent) 7. Need specific metadata/guideline specs? → skills/app-store-ref.md 8. IAP submission issue? → iap-auditor (Agent) 9. Want pre-submission code scan? → security-privacy-scanner (Agent) 10. ITMS signing/certificate/profile error on upload? → See axiom-security (skills/code-signing-diag.md) 11. General submission preparation? → skills/app-store-submission.md 12. App Clip (size tiers, invocation, AASA, data handoff)? → skills/app-clips.md, skills/app-clips-ref.md
Platform-specific submission
- watchOS 26 SDK requirement, 64-bit, independent-app submission → See axiom-watchos (skills/platform-basics.md)
Anti-Rationalization
| Thought | Reality |
|---|---|
| "I'll just submit and see what happens" | 40% of rejections are Guideline 2.1 (completeness). app-store-submission catches them in 10 min. |
| "I've submitted apps before, I know the process" | Requirements change yearly. Privacy manifests, age rating tiers, EU DSA, Accessibility Nutrition Labels are all new since 2024. |
| "The rejection is wrong, I'll just resubmit" | Resubmitting without changes wastes 24-48 hours per cycle. app-store-diag finds the root cause. |
| "Privacy manifests are only for big apps" | Every app using Required Reason APIs needs a manifest since May 2024. Missing = automatic rejection. |
| "I'll add the metadata later" | Missing metadata blocks submission entirely. app-store-ref has the complete field list. |
| "It's just a bug fix, I don't need a full checklist" | Bug fix updates still need What's New text, correct screenshots, and valid build. app-store-submission covers it. |
| "I'll just eyeball the screenshots myself" | Human review misses dimension mismatches (even 1px off = rejection), subtle placeholder text, and debug indicators. A single missed issue costs 24-48 hours in resubmission. screenshot-validator catches it in 2 minutes. |
| "I'll just do it in the ASC web dashboard" | If asc-mcp is configured, MCP tools are faster for bulk operations — distributing builds, responding to reviews, creating versions. asc-mcp has the workflow. |
| "Upload failed with ITMS error, let me re-archive" | ITMS signing errors are configuration — wrong cert, expired profile, missing entitlement. Re-archiving with the same config produces the same result. code-signing-diag has the fix. |
| "It's just a model ID swap (Claude 4.6 → 4.7)" | 4.6 → 4.7 removed temperature, top_p, top_k, and prefill from the Messages API. Build succeeds; runtime returns HTTP 400 after submission. Read claude-api (external) and test the live endpoint before uploading. |
| "My App Clip can be 100 MB, so I'll add an App Clip Code too" | The 100 MB tier (iOS 17+) is digital-invocation-only; adding any NFC/QR/App Clip Code drops the limit to 15 MB. See skills/app-clips.md. |
External Resources
Cloud Claude migration (`claude-api` skill, ships outside Axiom) — mandatory before shipping any Claude model-ID change. Opus 4.7 removed temperature, top_p, top_k, and prefill from the Messages API; code that built successfully on 4.6 returns HTTP 400 at runtime. An App Store update that ships this regression is an expedited-review situation. The claude-api skill automates the migration (model ID swap, sampling-param removal, prefill replacement) and enforces prompt caching from day one. Treat it as part of your pre-flight checklist, not a side reference.
When NOT to Use (Conflict Resolution)
Do NOT use axiom-shipping for these — use the correct skill instead:
| Issue | Correct Skill | Why NOT axiom-shipping |
|---|---|---|
| Build fails before archiving | axiom-build | Environment/build issue, not submission |
| SwiftData migration crash | axiom-data | Schema issue, not App Store |
| Privacy manifest coding (writing the file) | axiom-build | security-privacy-scanner handles code scanning |
| StoreKit 2 implementation (writing IAP code) | axiom-integration | in-app-purchases / storekit-ref covers implementation |
| Performance issues found during testing | axiom-performance | Profiling issue, not submission |
| Accessibility implementation | axiom-accessibility | Code-level accessibility, not App Store labels |
axiom-shipping is for the submission workflow, not code implementation:
- Preparing metadata and compliance → axiom-shipping
- Writing the actual code → domain-specific skill (axiom-build, axiom-data, etc.)
- App was rejected → axiom-shipping
- Code changes to fix rejection → domain-specific skill, then back to axiom-shipping to verify
Example Invocations
User: "How do I submit my app to the App Store?" → See skills/app-store-submission.md
User: "My app was rejected for Guideline 2.1" → See skills/app-store-diag.md
User: "What screenshots do I need?" → See skills/app-store-ref.md
User: "What fields are required in App Store Connect?" → See skills/app-store-ref.md
User: "How do I fill out the age rating questionnaire?" → See skills/app-store-ref.md
User: "Do I need an encryption compliance declaration?" → See skills/app-store-submission.md
User: "My app keeps getting rejected, what do I do?" → See skills/app-store-diag.md
User: "How do I appeal an App Store rejection?" → See skills/app-store-diag.md
User: "My app was rejected for Guideline 4.2 minimum functionality" → See skills/app-store-diag.md
User: "Rejected for being a web wrapper / duplicate app" → See skills/app-store-diag.md
User: "Rejection for user-generated content without moderation" → See skills/app-store-diag.md
User: "Kids category compliance rejection" → See skills/app-store-diag.md
User: "Scan my code for App Store compliance issues" → Launch security-privacy-scanner agent
User: "Check my IAP implementation before submission" → Launch iap-auditor agent
User: "Check my App Store screenshots in ~/Screenshots" → Launch screenshot-validator agent
User: "Are my screenshots the right dimensions?" → Launch screenshot-validator agent
User: "Triage my Sentry crashes" → Launch triage-analyzer agent (or /axiom:triage sentry)
User: "What are the top crash families in production right now?" → Launch triage-analyzer agent (or /axiom:triage sentry)
User: "Show me which ASC issues to fix first" → Launch triage-analyzer agent (or /axiom:triage asc)
User: "How do I find crash data in App Store Connect?" → See skills/app-store-connect-ref.md
User: "Where are my TestFlight crash reports in ASC?" → See skills/app-store-connect-ref.md
User: "What's new in App Store Connect this year?" → See skills/app-store-ref.md
User: "I need to set up DSA trader status for the EU" → See skills/app-store-ref.md
User: "What are Accessibility Nutrition Labels?" → See skills/app-store-submission.md
User: "This is my first app submission ever" → See skills/app-store-submission.md
User: "Submit this build to App Store programmatically" → See skills/asc-mcp.md
User: "Set up asc-mcp for App Store Connect" → See skills/asc-mcp.md
User: "Distribute build 42 to my beta testers via MCP" → See skills/asc-mcp.md
User: "Respond to negative App Store reviews from Claude" → See skills/asc-mcp.md
User: "ITMS-90035 Invalid Signature when uploading" → See axiom-security (skills/code-signing-diag.md)
User: "My provisioning profile expired and I can't upload" → See axiom-security (skills/code-signing-diag.md)
User: "How do I add an App Clip?" / "What's the App Clip size limit?" / "My App Clip link does nothing" → See skills/app-clips.md
App Clips — Reference
Reference tables for App Clip size tiers, entitlements, invocations, AASA format, data sharing, and restrictions. For the discipline (architecture decisions, gotchas, debugging), see skills/app-clips.md.
Size limits
Uncompressed App Clip binary, after app thinning, per variant, measured against the minimum deployment target:
| Minimum deployment target | Limit | Conditions |
|---|---|---|
| iOS 15 and earlier | 10 MB | — |
| iOS 16+ | 15 MB | — |
| iOS 17+ | 100 MB | Digital invocations only; reliable internet; no iOS < 17 support |
Physical invocations (App Clip Code, QR, NFC) cap the clip at 15 MB regardless of deployment target. Authoritative source: App Store Connect ▸ Reference ▸ Maximum build file sizes.
Exception (testing only): the App Store Connect-generated App Clip demo link can use the 100 MB limit even with physical invocations. This is a demo/preview affordance — production physical invocations still cap at 15 MB.
Bundle and target
- App Clip bundle ID: `<ParentBundleID>.Clip` (exact).
- App Clip is a separate target embedded in the full app; both ship in one archive.
- Shared code via a common framework or shared source membership — counts against the size budget.
Entitlements
| Target | Entitlement | Value |
|---|---|---|
| App Clip | com.apple.developer.parent-application-identifiers | [ <TeamID>.<ParentBundleID> ] |
| App Clip | com.apple.developer.on-demand-install-capable | true |
| Full app | com.apple.developer.associated-appclip-app-identifiers | added automatically by Xcode at archive time |
Both targets also need Associated Domains for App Clip links (see below).
Invocation methods
| Method | Type | Size impact |
|---|---|---|
| App Clip Code | Physical | 15 MB cap |
| NFC tag | Physical | 15 MB cap |
| QR code | Physical | 15 MB cap |
| Safari Smart App Banner | Digital | 100 MB eligible (iOS 17+) |
| Maps | Digital | 100 MB eligible (iOS 17+) |
| Messages | Digital | 100 MB eligible (iOS 17+) |
| Spotlight | Digital | 100 MB eligible (iOS 17+) |
https://appclip.apple.com/... default link | Digital | 100 MB eligible (iOS 17+) |
Associated Domains and AASA
Entitlement entry (both the App Clip and, for full-app Universal Links, the app):
appclips:example.comAASA file at https://example.com/.well-known/apple-app-site-association (HTTPS, valid JSON, no redirects, answers Apple's AASA-Bot / CFNetwork fetch):
{
"appclips": {
"apps": ["ABCDE12345.com.example.MyApp.Clip"]
}
}For Universal Links into the full app, the same file also carries the standard applinks section.
App Store Connect launch experience
- Default experience (required): header image, subtitle (≤ 56 characters), call-to-action verb (e.g. Open / View / Play). Plus the URL the experience opens.
- Advanced experiences: per-URL or per-place cards (Maps place cards, multi-location). Configured in App Store Connect.
Data sharing with the full app
| Mechanism | Notes |
|---|---|
| App Group shared container | Files and shared UserDefaults both targets can read |
| Keychain (access group) | App Clip ↔ app keychain sharing, iOS 15.4+ |
| Sign in with Apple | Re-establish identity in the full app |
| CloudKit public database | Read-only from the App Clip (iOS 16+); no private/shared containers |
Write handoff data before prompting the upgrade; read it on first launch of the full app.
Restrictions
Capabilities an App Clip does not have:
- No background execution — no
BGTaskScheduler, no Background Modes, no background URLSession, no background Bluetooth. - Ephemeral notifications by default — ~8 hours per launch; for multi-day functionality you can explicitly request standard notification permission.
- No persistent identity — device name and
identifierForVendorboth return an empty string. - No ATT / SKAdNetwork — no App Tracking Transparency, no attribution kit.
- Restricted frameworks — App Intents, HealthKit, HomeKit, Contacts, EventKit, Core Motion, MediaPlayer, PhotoKit, Speech, Nearby Interaction, and others are unavailable at runtime; verify a framework's App Clip availability before depending on it.
- No standalone submission — always submitted embedded in the full app.
App Clip Live Activities
An App Clip may present a Live Activity via its own widget-extension target that contains only the Live Activity (no static/timeline widgets). See axiom-integration (skills/live-activities.md).
Resources
WWDC: 2020-10174, 2020-10120, 2021-10013, 2022-10097, 2023-10178
Docs: /appclip, /appclip/creating-an-app-clip-with-xcode, /appclip/configuring-the-launch-experience-of-your-app-clip, /appclip/associating-your-app-clip-with-your-website, /appclip/sharing-data-between-your-app-clip-and-your-full-app
Skills: skills/app-clips.md, skills/app-store-submission.md, axiom-integration (skills/live-activities.md)
App Clips — Lightweight, Install-Free App Slices
An App Clip is a small slice of your app a user can launch instantly — from a website link, App Clip Code, NFC tag, QR code, Maps, Messages, or Spotlight — without installing the full app. It's a separate Xcode target embedded inside your full app's archive, not a standalone submission, and it lives under tight size and capability limits. Get the size tier, entitlements, and data-handoff right and an App Clip is a powerful acquisition funnel; get them wrong and it won't build, won't invoke, or gets rejected.
Core mental model
The App Clip is a second target whose bundle ID is <ParentBundleID>.Clip. You build and submit it with the full app (one archive, App Store Connect ties them together). The App Clip shares code with the full app via a framework or shared sources, but it is heavily constrained: a hard binary-size ceiling, a denylist of frameworks, ephemeral notifications, and no persistent identity. When the user wants more, they upgrade to the full app — and any data the App Clip stored must hand off cleanly.
When to Use This Skill
- Adding an App Clip target to an existing app
- Choosing an invocation method (and understanding how it caps your size budget)
- Configuring associated domains and the AASA file for App Clip links
- Setting up the App Store Connect default and advanced launch experiences
- Handing off App Clip data to the full app on upgrade
- Debugging "App Clip won't invoke" or "build exceeds maximum size"
For the entitlement/restriction/size tables and the AASA format, see skills/app-clips-ref.md. App Clips ship with the parent app — see skills/app-store-submission.md for the submission flow and skills/app-review-guidelines.md for review rules.
App Clip size limits — the make-or-break constraint
The uncompressed App Clip binary (after app thinning, per variant) must not exceed the limit for its minimum deployment target:
| Minimum deployment target | Size limit | Conditions |
|---|---|---|
| iOS 15 and earlier | 10 MB | — |
| iOS 16+ | 15 MB | — |
| iOS 17+ | 100 MB | Digital invocations only (website / Spotlight), reliable-internet contexts, and no support for iOS < 17 |
The 100 MB tier is exclusive to digital invocations. The moment you support a physical invocation — App Clip Code, QR code, or NFC tag — you're capped at 15 MB again. (App Store Connect's "Maximum build file sizes" reference is the authoritative source.)
One exception, for testing only: the App Clip demo link that App Store Connect generates can exercise the 100 MB limit even from physical invocations (App Clip Codes, NFC, QR). That's a demo/preview affordance — your shipping physical invocations still cap at 15 MB, so don't let a 100 MB clip "working" via the demo link convince you it's production-ready.
Critical Gotchas
| Gotcha | Why it bites | Fix |
|---|---|---|
| Counting on the 100 MB tier with an NFC/QR/App Clip Code | Physical invocations cap you at 15 MB | Use only digital invocations for the 100 MB tier, or stay ≤ 15 MB |
Bundle ID isn't <ParentBundleID>.Clip | App Store Connect won't associate the clip | Name it exactly <ParentBundleID>.Clip |
| AASA not served correctly | App Clip links don't invoke | Serve apple-app-site-association with an appclips key; the server must answer Apple's AASA-Bot / CFNetwork fetch |
| Using a denylisted framework | App Clip won't build / is rejected | App Intents, HealthKit, Contacts, etc. are unavailable in App Clips — guard or drop them |
| Expecting persistent identity | App Clips get an empty-string device name and an empty-string identifierForVendor; no ATT/SKAdNetwork | Don't rely on device identity or attribution in the clip |
| Notifications that linger | App Clips get ephemeral notifications by default (8 hours per launch) | For multi-day flows, explicitly request standard notification permission |
| Data doesn't survive upgrade | App Clip and full app are separate sandboxes | Hand off via a shared App Group / Keychain before the user upgrades |
Part 1 — Target and archive structure
Add an App Clip target to your project (File ▸ New ▸ Target ▸ App Clip). Xcode embeds it inside the full app target so they archive together. Share code through a common framework or shared source membership — but every shared file still counts against the App Clip's size budget, so keep the clip's dependency graph lean.
Part 2 — Entitlements
Three entitlements wire the clip to its parent:
- App Clip target —
com.apple.developer.parent-application-identifierslisting the full app's App ID, andcom.apple.developer.on-demand-install-capable. - Full app target —
com.apple.developer.associated-appclip-app-identifiers, which Xcode adds automatically when you archive.
If these don't line up, App Store Connect won't recognize the pairing and TestFlight/review will fail. See skills/app-clips-ref.md for the exact key/value shapes.
Part 3 — Invocations (and how they cap your size)
App Clips launch from: App Clip Codes, NFC tags, QR codes, Safari Smart App Banners, Maps, Messages, Spotlight, and default https://appclip.apple.com/... links. The split that matters for your binary budget:
- Physical (App Clip Code, NFC, QR) → 15 MB ceiling.
- Digital (website link, Spotlight) → eligible for the 100 MB tier on iOS 17+.
Design the invocation strategy before you architect the clip — it sets your size budget.
Part 4 — Associated domains and AASA
Add an Associated Domains entitlement with an appclips: prefix entry (appclips:example.com). Serve an apple-app-site-association (AASA) file at https://example.com/.well-known/apple-app-site-association with an appclips section listing your App Clip's app ID and URL patterns. The file must be valid JSON served over HTTPS with no redirects, and your server must respond to Apple's AASA-Bot user agent (and CFNetwork). A 404 or a redirect here is the #1 cause of "the App Clip link does nothing."
Part 5 — App Store Connect launch experiences
- Default experience — a header image, a ≤56-character subtitle, and a call-to-action verb (e.g. "Open", "View", "Play"). Required; it's what users see in the App Clip card.
- Advanced experiences — per-URL or per-location cards (e.g. Maps place cards, multi-location businesses). Configure these in App Store Connect to tailor the card to the specific invocation.
Part 6 — Handing data off to the full app
The App Clip and full app are separate sandboxes. To carry state across an upgrade, write it somewhere both can read:
- App Group shared container (files, shared
UserDefaults) - Keychain with an access group (iOS 15.4+ allows the App Clip and app to share keychain items)
- Sign in with Apple (re-establish identity in the full app)
- CloudKit public database (read-only from the clip)
Write the handoff data before prompting the upgrade, and read it on first launch of the full app.
Part 7 — Restrictions
App Clips can't use: App Intents, HealthKit, HomeKit, Contacts, EventKit, Core Motion, and several other frameworks (full list in skills/app-clips-ref.md). They get ephemeral notification authorization by default (8 hours from each launch), though you can explicitly request standard permission for functionality that spans more than a day. They have no access to ATT or SKAdNetwork, and both the device name and identifierForVendor return an empty string. Build the clip assuming no persistent identity and no long-lived background presence.
Part 8 — App Clip + Live Activities
An App Clip can show a Live Activity. It requires its own widget-extension target that contains only the Live Activity (no static/timeline widgets). This is a useful pattern for order/arrival status during an install-free flow — see axiom-integration (skills/live-activities.md) for the ActivityKit side.
Common Mistakes
- Forgetting the 100 MB tier (iOS 17+) is digital-invocation-only — any NFC/QR/App Clip Code drops you to 15 MB.
- Adding an NFC/QR/App Clip Code invocation while relying on the 100 MB budget.
- Naming the clip's bundle ID anything other than
<ParentBundleID>.Clip. - A misconfigured or redirecting AASA file — the App Clip link silently does nothing.
- Reaching for App Intents / HealthKit / Contacts inside the clip.
- Expecting persistent identity (device name and
identifierForVendorare empty strings), ATT, or background execution. - Writing data only to the clip's own container, then losing it on upgrade.
Resources
WWDC: 2020-10174, 2020-10120, 2021-10013, 2022-10097, 2023-10178
Docs: /appclip, /appclip/creating-an-app-clip-with-xcode, /appclip/configuring-the-launch-experience-of-your-app-clip, /appclip/associating-your-app-clip-with-your-website, /appclip/sharing-data-between-your-app-clip-and-your-full-app, /appclip/choosing-the-right-functionality-for-your-app-clip
Skills: skills/app-clips-ref.md, skills/app-store-submission.md (submitting with the parent app), skills/app-review-guidelines.md, axiom-integration (skills/live-activities.md — App Clip Live Activities)
App Review Guidelines Index
Verified against Apple's published guidelines (February 6, 2026 revision).
Section 1: Safety
| Guideline | Topic |
|---|---|
| 1.1 | Objectionable Content |
| 1.1.1 | Defamatory, discriminatory, or mean-spirited content |
| 1.1.2 | Realistic portrayals of people or animals being killed/maimed/tortured/abused |
| 1.1.3 | Depictions encouraging weapons use against people/animals |
| 1.1.4 | Pornographic material (immediate removal) |
| 1.1.5 | Religious/cultural/ethnic commentary that fosters prejudice |
| 1.1.6 | False information, fake functionality ("for entertainment" does NOT excuse this) |
| 1.1.7 | Capitalizing on recent events (tragedies, conflicts, epidemics) |
| 1.2 | User-Generated Content — must have filtering, reporting, blocking, contact info, age verification |
| 1.3 | Kids Category — no third-party analytics/advertising, COPPA/GDPR-Kids compliance |
| 1.4 | Physical Harm |
| 1.4.1 | Medical apps: disclose limitations, link to real medical help |
| 1.4.2 | Drug dosage calculators: recognized institutions only |
| 1.4.3 | Tobacco, e-cigarettes, vape, illegal drug use encouragement |
| 1.4.4 | DUI/checkpoint apps that encourage reckless behavior |
| 1.4.5 | Activities that risk physical harm (bets, dares, body modification) |
| 1.5 | Developer Information — program membership must be current |
| 1.6 | Data Security — ATS required, justified exceptions only |
Section 2: Performance
| Guideline | Topic |
|---|---|
| 2.1 | App Completeness — no crashes, broken links, placeholders, missing demo accounts |
| 2.2 | Beta/Demo/Trial — use TestFlight, not "beta" in app name or bundle ID |
| 2.3 | Accurate Metadata |
| 2.3.1 | No hidden/undocumented features; no misleading descriptions |
| 2.3.2 | No concealed features |
| 2.3.3 | Screenshots must reflect actual app experience on correct device |
| 2.3.5 | Use accurate App Store category |
| 2.3.6 | Age rating must match actual content |
| 2.3.7 | App name max 30 chars; no keyword stuffing in name/subtitle |
| 2.3.8 | Metadata must be age-appropriate; "For Kids"/"For Children" reserved for Kids category |
| 2.4 | Hardware Compatibility — must work with current OS |
| 2.5 | Software Requirements |
| 2.5.1 | Only public APIs |
| 2.5.2 | Self-contained; no code downloads that change functionality |
| 2.5.3 | No viruses, malware, code injection (immediate removal) |
| 2.5.4 | Multitasking must use proper background modes |
| 2.5.5 | Must be fully functional on IPv6-only networks |
| 2.5.6 | Web browsing must use WebKit (alternative engine entitlement available) |
| 2.5.9 | Request only necessary permissions |
| 2.5.11 | SiriKit/HealthKit must actually use the declared feature |
| 2.5.17 | Matter integration must use Apple's framework; third-party components CSA-certified |
| 2.5.18 | No display advertising in extensions, App Clips, widgets, notifications, keyboards, watchOS |
Section 3: Business
For Apple Pay / Wallet / Tap to Pay specifically, see axiom-payments/skills/apple-pay-vs-iap.md for the IAP boundary and axiom-payments/skills/payments-diag.md for entitlement and integration rejection patterns.
| Guideline | Topic |
|---|---|
| 3.1.1 | In-App Purchase required for digital goods/services. Loot box odds must be disclosed before purchase. NFTs: may sell via IAP, ownership must not unlock features. |
| 3.1.2 | Subscriptions: ongoing value, 7-day minimum period, cross-device, transparent terms (price, duration, auto-renewal, cancellation). Schedule 2 of DPLA requires ToS/PP on purchase screen. |
| 3.1.3(a-e) | External payments: reader apps, multiplatform, enterprise, person-to-person, physical goods |
| 3.1.4 | No artificial barriers between IAP and web purchase options |
| 3.1.5 | Cryptocurrency: wallets require organization enrollment, exchanges need licensing, no on-device mining, no crypto rewards for tasks |
| 3.2.2(viii) | Binary options trading apps prohibited |
| 3.2.2(ix) | Loan apps: max 36% APR including fees, no full repayment required within 60 days |
Section 4: Design
| Guideline | Topic |
|---|---|
| 4.0 | General design standards (HIG compliance) |
| 4.1 | Copycats — apps confusingly similar to existing apps (4.1(b): impersonation = removal from Developer Program) |
| 4.2 | Minimum Functionality — no web wrappers, no single-media apps, must have lasting value |
| 4.2.6 | Template/app-generation-service apps rejected unless submitted by content provider |
| 4.3 | Spam — no duplicate apps from same developer |
| 4.4.1 | Keyboard extensions must include next-keyboard switching |
| 4.5.4 | Push notifications: no advertising, marketing, or spam |
| 4.7 | Mini apps, streaming games, chatbots, emulators: must provide universal link index, age restrictions, content filtering |
| 4.8 | Sign in with Apple required when ANY third-party/social login offered (exceptions: company-internal, education, government, client apps for specific services) |
| 4.10 | Cannot monetize built-in capabilities (push, camera, gyroscope, Apple Music, iCloud storage, Screen Time APIs) |
Section 5: Legal
| Guideline | Topic |
|---|---|
| 5.1.1(i) | Privacy policy required in App Store Connect AND within app |
| 5.1.1(ii) | Permission requests must explain purpose with benefit to user |
| 5.1.1(iii) | Don't require unnecessary personal info |
| 5.1.1(v) | Account deletion must be offered if account creation supported |
| 5.1.1(vi) | Surreptitiously discovering passwords (removal from Developer Program) |
| 5.1.2(i) | No sharing with third parties without consent; ATT required for tracking |
| 5.1.3 | Health data must not be stored in iCloud; no false HealthKit data |
| 5.1.4 | Kids Category requirements (COPPA) |
| 5.1.5 | Location Services must have clear purpose |
| 5.2 | Intellectual Property — no unauthorized copyrighted material |
| 5.3 | Gaming/Gambling — real-money gambling requires licensing |
| 5.4 | VPN Apps — must use NEVPNManager API |
| 5.5 | Developer Code of Conduct |
| 5.6 | Telecommunications |
Zero-Tolerance Guidelines (Immediate Removal Risk)
| Guideline | Consequence |
|---|---|
| 1.1.4 | Pornographic content → immediate removal |
| 2.5.3 | Viruses/malware → immediate removal |
| 4.1(b) | App impersonation → removal from Developer Program |
| 5.1.1(vi) | Surreptitious password discovery → removal from Developer Program |
Top 10 Rejection Causes
| Rank | Guideline | Issue | % of Rejections |
|---|---|---|---|
| 1 | 2.1 | App Completeness (crashes, placeholders, broken flows) | ~40% |
| 2 | 5.1.1(i) | Privacy policy missing/inadequate | — |
| 3 | 2.1 | Incomplete review info (missing demo accounts) | — |
| 4 | 2.3.3 | Screenshots don't match app | — |
| 5 | 4.0 | Substandard UI / HIG violations | — |
| 6 | 4.2 | Web wrapper / insufficient functionality | — |
| 7 | 2.3.1 | Misleading metadata | — |
| 8 | 4.2 | Insufficient lasting value | — |
| 9 | 4.1 | Copycat app | — |
| 10 | 4.3 | Repeated similar apps | — |
Sensitive App Types Requiring Extra Documentation
| Type | Requirements |
|---|---|
| Kids apps with third-party ads | Links to ad policies, proof of human review |
| Medical hardware integration | Regulatory clearance for all regions |
| Third-party content/trademarks | Authorization documentation |
| Gambling, VPN, real money gaming | Licensing documentation |
| Banking, crypto, healthcare, air travel | Must be submitted by legal entity (not individuals) |
App Store Connect Reference
Overview
App Store Connect (ASC) provides crash reports, TestFlight feedback, and performance metrics for your apps. This reference covers how to navigate ASC to find and export crash data for analysis.
ASC vs Xcode Organizer
| Task | Best Tool |
|---|---|
| Quick crash triage during development | Xcode Organizer |
| Team-wide crash visibility | App Store Connect |
| TestFlight feedback with screenshots | App Store Connect |
| Historical metrics and trends | App Store Connect |
| Downloading crash logs for analysis | Either (ASC has better export) |
| Symbolication | Xcode Organizer |
---
Navigating to Crash Data
Path to Crashes
App Store Connect
└── My Apps
└── [Your App]
└── Analytics
└── CrashesDirect URL pattern: https://appstoreconnect.apple.com/analytics/app/[APP_ID]/crashes
Crashes Dashboard Sections
1. Filters bar — Platform, Version, Date Range, Compare 2. Crash-Free Users graph — Daily percentage trend line 3. Crash Count by Version — Bar chart comparing versions 4. Top Crash Signatures — Ranked by share percentage, shows exception type and function name
Key Metrics Explained
| Metric | What It Means |
|---|---|
| Crash-Free Users | Percentage of daily active users who didn't experience a crash |
| Crash Count | Total number of crash reports received |
| Crash Rate | Crashes per 1,000 sessions |
| Affected Devices | Number of unique devices that crashed |
| Crash Signature | Grouped crashes with same stack trace |
Filtering Options
| Filter | Use Case |
|---|---|
| Platform | iOS, iPadOS, macOS, watchOS, tvOS |
| Version | Drill into specific app versions |
| Date Range | Last 7/30/90 days or custom range |
| Compare | Compare crash rates between versions |
| Device | Filter by iPhone model, iPad, etc. |
| OS Version | Find OS-specific crashes |
---
Viewing Individual Crash Reports
Crash Signature Detail
Each crash signature shows:
- Header — Exception type and affected device/crash share counts, first seen date
- Exception Information — Type (e.g., EXC_BAD_ACCESS), codes, address
- Crashed Thread — Stack frames with binary, function, and offset
- Distribution — Breakdown by iOS version and device model
Downloading Crash Logs
1. Click on a crash signature 2. Look for Download Logs button (top right) 3. Select format:
- .ips (JSON format, iOS 15+)
- .crash (text format, legacy)
4. Use crash-analyzer agent to parse: /axiom:analyze-crash
---
TestFlight Feedback
Path to Feedback
App Store Connect
└── My Apps
└── [Your App]
└── TestFlight
└── FeedbackFeedback Entry Contents
Each feedback submission includes:
| Field | Description |
|---|---|
| Screenshot | What the tester saw (often most valuable) |
| Comment | Tester's description of the issue |
| App Version | Exact TestFlight build number |
| Device Model | iPhone 15 Pro Max, iPad Air, etc. |
| OS Version | iOS 17.2.1, etc. |
| Battery Level | Low battery can affect behavior |
| Available Disk | Low disk can cause write failures |
| Network Type | WiFi vs Cellular |
| Locale | Language and region settings |
| Timestamp | When submitted |
Feedback Filtering
| Filter | Use Case |
|---|---|
| Build | Focus on specific TestFlight builds |
| Date | Recent feedback first |
| Has Screenshot | Find visual issues quickly |
Limitation: No Reply
TestFlight feedback is one-way. You cannot respond to testers through ASC. For follow-up:
- Contact through TestFlight group email
- Add in-app feedback mechanism
- Include your email in TestFlight notes
---
Metrics Dashboard
Path to Metrics
App Store Connect
└── My Apps
└── [Your App]
└── Analytics
└── MetricsAvailable Metrics Categories
| Category | What It Shows |
|---|---|
| Crashes | Crash-free users, crash count, top signatures |
| Hang Rate | Main thread hangs > 250ms |
| Disk Writes | Excessive disk I/O patterns |
| Launch Time | App startup performance |
| Memory | Peak memory usage, terminations |
| Battery | Energy usage during foreground/background |
| Scrolling | Scroll hitch rate |
Terminations (Non-Crash Kills)
The Metrics dashboard shows terminations that don't produce crash reports:
| Termination Type | Cause |
|---|---|
| Memory Limit | Jetsam killed app for memory pressure |
| CPU Limit (Background) | Exceeded background CPU quota |
| Launch Timeout | App took too long to launch |
| Background Task Timeout | Background task exceeded time limit |
Comparing Versions
Use the Compare filter to see:
- Did crash rate improve or regress?
- Which version introduced a spike?
- Performance trends over releases
---
Exporting Data
Manual Export
1. Navigate to Crashes or Metrics 2. Use date range filter to select period 3. Click Export (if available) or download individual crash logs
App Store Connect API
For automated export, use the App Store Connect API:
# Get crash diagnostic insights
GET /v1/apps/{id}/perfPowerMetrics
# Authentication requires API key from ASC
# Users and Access → Keys → App Store Connect APIAPI capabilities:
| Endpoint | Data |
|---|---|
perfPowerMetrics | Performance and power metrics |
diagnosticSignatures | Crash signature aggregates |
diagnosticLogs | Individual crash logs |
betaTesters | TestFlight tester info |
betaFeedback | TestFlight feedback entries |
MCP-Powered Access
If asc-mcp is configured, you can access ASC data programmatically from Claude Code:
| Manual ASC Action | asc-mcp Tool |
|---|---|
| View crash metrics | metrics_app_perf, metrics_build_diagnostics |
| Download crash logs | metrics_get_diagnostic_logs |
| List TestFlight testers | builds_get_beta_testers |
| View app reviews | reviews_list, reviews_stats |
| Respond to reviews | reviews_create_response |
| Check build status | builds_get_processing_state |
| Export sales data | analytics_sales_report (requires vendor_number) |
Setup and workflows: See axiom-shipping (skills/asc-mcp.md)
Xcode Cloud Integration
If using Xcode Cloud, crash data integrates with CI/CD:
- View crashes per workflow run
- Compare crash rates between branches
- Automated alerts on crash spikes
---
Best Practices
Daily Monitoring
1. Check crash-free users percentage 2. Review any new crash signatures 3. Monitor for version-to-version regressions
Crash Triage Priority
| Priority | Criteria |
|---|---|
| P0 - Critical | >1% of users affected, data loss risk |
| P1 - High | >0.5% affected, user-facing impact |
| P2 - Medium | <0.5% affected, workaround exists |
| P3 - Low | Rare, edge case, no impact |
Correlating with Releases
After each release:
1. Wait 24-48 hours for crash data to populate 2. Compare crash-free rate to previous version 3. Investigate any new top crash signatures 4. Check TestFlight feedback for user reports
---
Common Questions
Why don't I see crashes in ASC?
| Cause | Fix |
|---|---|
| Too recent | Wait 24 hours for processing |
| No users yet | Need active installs to report |
| User opted out | Requires device analytics sharing |
| Build not distributed | Must be TestFlight or App Store |
Why are crashes unsymbolicated?
ASC crashes should auto-symbolicate if you uploaded dSYMs during distribution. dSYM files contain the debug symbols that map memory addresses back to function names and line numbers.
Verify dSYMs were uploaded: 1. Xcode → Window → Organizer → Archives → select build 2. Right-click → "Show in Finder" → right-click .xcarchive → "Show Package Contents" 3. Check dSYMs/ folder contains .dSYM bundles
Manual symbolication workflow:
# 1. Download .ips file from ASC (Crashes → signature → Download Logs)
# 2. Find the binary UUID from the crash report
grep --after-context=2 "Binary Images" crash.ips
# Look for: 0x100000000 - 0x100ffffff MyApp arm64 <UUID>
# 3. Locate matching dSYM on your machine
mdfind "com_apple_xcode_dsym_uuids == <UUID>"
# 4. Symbolicate an address
atos -arch arm64 -o MyApp.app.dSYM/Contents/Resources/DWARF/MyApp \
-l 0x100000000 0x100045abc
# Output: -[UserManager currentUser] (UserManager.m:42)Common symbolication failures:
| Symptom | Cause | Fix |
|---|---|---|
| All addresses unsymbolicated | dSYMs not uploaded | Re-upload from Xcode Organizer |
| Only your code unsymbolicated | dSYM UUID mismatch | Rebuild from same commit |
| System frameworks unsymbolicated | Normal for device-specific | Use atos with device support files |
| Bitcode builds unsymbolicated | Apple recompiled binary | Download dSYMs from ASC: Xcode → Organizer → Download Debug Symbols |
See crash-analyzer agent for automated parsing: /axiom:analyze-crash
ASC vs Organizer: Which stack trace is better?
Both show the same data, but:
- Organizer integrates with Xcode projects (click to jump to code)
- ASC better for team-wide visibility and historical trends
---
Field Diagnostics with MetricKit
For device-level crash diagnostics, hang call stacks, and custom telemetry beyond ASC's aggregated dashboards, see axiom-performance (skills/metrickit-ref.md).
Key difference: ASC shows aggregated trends for team visibility. MetricKit provides per-device diagnostics you can correlate with your own telemetry.
---
Related
Skills: axiom-shipping (skills/testflight-triage.md) (Xcode Organizer workflows), axiom-shipping (skills/asc-mcp.md) (programmatic ASC access via MCP)
Agents: crash-analyzer (automated crash log parsing)
Commands: /axiom:analyze-crash
---
Resources
WWDC: 2020-10076, 2020-10078, 2021-10203, 2021-10258
Docs: /app-store-connect/api, /xcode/diagnosing-issues-using-crash-reports-and-device-logs
App Store Rejection Diagnostics
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" / "resubmit and hope for a different reviewer"
- Re-read the rejection. App Review is right 95% of the time.
- Resubmitting without changes wastes 3-7 days per cycle.
- App Review keeps the full rejection history on your submission. A new reviewer opens the case and sees every prior citation. Unchanged resubmissions are flagged and escalated to a senior reviewer who re-checks each previously cited issue — you do not get a clean slate, you get more scrutiny.
- If you genuinely disagree, use the appeal process (Pattern 7).
- If the pressure is a deadline ("we can't lose our place in line"), the legitimate answer is expedited review (see Pattern 7), not an unchanged resubmission.
Apple Pay / Wallet / Tap to Pay Rejections
Payment-related rejections route to the axiom-payments suite for the root cause, then back here for the appeal workflow:
- Section 3.1.1 / 3.1.3(e) misuse (IAP-vs-Apple-Pay rail) →
axiom-payments/skills/apple-pay-vs-iap.mdfor the boundary rule, thenaxiom-payments/skills/payments-diag.md§ "App Store Rejection Patterns" for the specific rejection-text mapping - Tap to Pay entitlement-related submission failures ("Submitted" stuck, distribution entitlement not re-requested) →
axiom-payments/skills/payments-diag.md§ "Tap to Pay Entitlement Stuck" - Apple Pay on the Web AUG violations (parity rule, primary-option rule, prohibited categories) →
axiom-payments/skills/apple-pay-vs-iap.md§ "Web — Acceptable Use Guidelines" - HIG button violations (Mark used as button, custom Apple Pay branding, Tap to Pay button used for non-payment) →
axiom-payments/skills/apple-pay.mdandtap-to-pay.md
Once root cause is identified, return here for appeal workflow (Pattern 7 below) and Resolution Center communication.
Mandatory First Steps
ALWAYS do these BEFORE changing any code:
1. Read the FULL rejection message — Don't skim. Copy the exact text. Note every guideline number cited. 2. 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
3. Check the specific guideline — Look up the exact number in app-store-ref 4. Screenshot the rejection — Save for team communication and appeal reference 5. 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:
1. If "App Rejected" with guideline number → Map to specific pattern (1-5) 2. If "Metadata Rejected" → Fix in ASC, no build required (Pattern 2) 3. If "Binary Rejected" → Technical gate failure (Pattern 6) 4. 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. 5. 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 (pull reviewer crash log, symbolicate FIRST)
│ │ ├─ 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 8Pattern Selection Rules (MANDATORY)
Before proceeding to a pattern:
1. Copy the exact rejection text — Word for word, including guideline numbers 2. Match guideline number to pattern — Don't guess, map directly 3. If multiple guidelines cited — Fix ALL of them before resubmitting 4. If no guideline number — Likely Binary Rejected, start with Pattern 6 5. 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
First step for crash rejections — get the reviewer's log, do not guess
When the rejection is a crash, the reviewer's actual crash log is the diagnosis. Pull it before forming any theory:
1. Resolution Center — open the rejection message. Crash-on-launch and many in-review crashes attach a .crash/.ips directly to the message. Download it. 2. Xcode Organizer → Crashes — filter by the submitted version and the OS/device the reviewer used (ASC Activity → Build shows review device info). App Review crashes surface here within hours. 3. Symbolicate before theorizing — run it through xcsym and read the pattern_tag (see Diagnosis below). The tag tells you the crash class — a forced-unwrap on a missing-locale path is a different fix than a watchdog hang.
Skipping this and guessing from the Common Causes list is the #1 way a 2.1 fix fails re-review: you "fix" a plausible cause that wasn't the actual crash. The signed crash report removes the guessing.
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
1. App crashes on reviewer's device (different OS version, different device class) 2. Placeholder text or images visible in any screen 3. Broken links (support URL, privacy policy, in-app links) 4. Missing demo credentials for login-required apps 5. Backend service was down during review window
Diagnosis
# 1. Check crash logs in App Store Connect
# Xcode Organizer > Crashes > Filter by version
# Export the .ips and symbolicate with xcsym:
xcsym crash --format=summary <path-to-ips>
# The `pattern_tag` field tells you the crash class at a glance:
# swift_forced_unwrap → nil-unwrap on reviewer's device (often a missing locale/permission path)
# swift_concurrency_violation → @MainActor violation only reproducing on review hardware
# jetsam_oom → reviewer hit a memory ceiling your internal test devices didn't
# watchdog_termination → launch/main-thread hang exceeding 20s on slower review hardware
# code_signing_killed → certificate/provisioning issue (not a code bug)
# 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
1. Screenshots show old UI or features that no longer exist 2. Description promises features not yet implemented 3. Keywords contain trademarked terms or competitor names 4. App name implies functionality that doesn't exist 5. 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 changesFix
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 versionVerification
- 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
1. Privacy policy missing or not accessible from within the app 2. Privacy policy doesn't match actual data collection 3. Missing purpose strings for permission requests 4. Privacy manifest (PrivacyInfo.xcprivacy) missing required reason API declarations 5. Third-party SDK collects data not disclosed in privacy nutrition labels 6. 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 APIsFix
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 inquiriesApp 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
1. App has Google/Facebook/Twitter login but no SIWA 2. SIWA button exists but doesn't work 3. SIWA not offered at equal prominence (hidden or secondary) 4. 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):
- Company-internal or employee-only apps
- Education or enterprise apps with existing institutional auth
- Government/tax/banking apps requiring government ID
- Apps that are a client for a specific 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
1. Digital content unlocked without IAP (using external payment for in-app features) 2. Subscription doesn't provide ongoing value (one-time content sold as subscription) 3. Loot box or random item purchase odds not disclosed 4. Deceptive subscription flow (dark patterns, misleading free trial) 5. 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 servicesFix
// ❌ 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
1. Built with outdated SDK version (must meet Apple's minimum) 2. Privacy manifest (PrivacyInfo.xcprivacy) missing or invalid 3. Encryption compliance not declared (ITSAppUsesNonExemptEncryption) 4. Invalid signing or provisioning profile 5. Missing required device capabilities in Info.plist 6. App uses private or deprecated APIs 7. 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 submissionFix
<!-- 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: 1. Does your app use ONLY standard OS-provided HTTPS (URLSession, Alamofire)? → Set false, done 2. Does your app call OpenSSL, libsodium, or custom crypto directly? → Set true, upload BIS docs 3. Does your app implement proprietary encryption protocols? → Set true, upload BIS docs 4. 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 → AccountsVerification
- 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
When NOT to use
- You disagree with Apple's rules (they won't change for your app)
- You're hoping a different reviewer will approve without changes
- You want to skip implementing a required feature (like SIWA)
Deadline pressure is NOT an appeal reason — it's an expedited-review reason
When the pressure is "we have a launch date / we can't lose our place in the queue," the appeal is the wrong tool (deadlines are not App Review's concern and saying so weakens the appeal). The legitimate, named answer is expedited review:
- Request at developer.apple.com/contact/app-store/?topic=expedite
- Fix the cited issues properly FIRST, then request expedited review on the corrected submission — a 1-3 day turnaround instead of standard 3-7 days, with no loss of queue position.
- Valid grounds: time-sensitive event tied to the release, critical bug fix for live users, security patch.
- Use it sparingly — Apple tracks expedite usage and may deny future requests if abused. It is not a way to skip the fix; it is a way to ship a real fix faster.
This is the answer to a manager pushing "resubmit and hope" or "claim it's fixed without fixing": you can hit the deadline legitimately by fixing fast and requesting expedite, and the dishonest paths cost MORE time (escalated re-review) while risking developer-account standing.
Step 1: Reply in App Store Connect first
Most issues resolve without a formal appeal. Reply to App Review messages in ASC with:
- Specific evidence of compliance
- Screenshots or video demonstrating the feature
- Clear reference to the guideline you believe you comply with
Step 2: If unresolved, submit formal appeal
URL: developer.apple.com/contact/app-store/?topic=appeal
Appeal writing
✅ GOOD appeal structure:
"Our app complies with Guideline [X.Y] because [specific evidence].
The reviewer noted: '[quote exact rejection text]'
However, our app [specific counter-evidence with details]:
1. [Feature X] works as shown in [attached screenshot/video]
2. [Policy Y] is accessible at [URL] and within the app at [screen]
3. [Requirement Z] is implemented as described in [technical detail]
Attached: [screenshots, screen recording, or documentation]
We respectfully request re-review of this decision."❌ BAD appeal examples:
"This is unfair. Other apps do the same thing. Please approve."
→ Apple reviews each app independently
"We've been rejected 3 times and are losing money."
→ Financial pressure is not relevant to guideline compliance
"The reviewer didn't understand our app."
→ Vague. Show specifically what they missed.
"We need this approved by Friday for our launch."
→ Deadlines are not App Review's concern in an appeal.
Fix the issue, then request expedited review (?topic=expedite) — that's the deadline tool.Step 3: Escalate if needed
If appeal is denied: 1. Request a phone call with App Review (available through appeal process) 2. Contact Apple Developer Relations as last resort 3. Consider whether the app genuinely needs architectural changes
Verification
- Wait for response before making code changes (if appealing)
- Include ONE appeal per rejection (multiple appeals slow the process)
- Respond to any information requests before filing appeal
---
Pattern 8: Guideline 4.2/4.3 — Minimum Functionality / Spam
Patterns 8-9 address subjective rejections where the fix is demonstrating value or compliance, not changing code.
Time to resolve 1-4 weeks (requires app changes, not just metadata)
Rejection messages you'll see
- 4.2: "Your app does not include sufficient content and features to be appropriate for the App Store"
- 4.3: "Your app duplicates the content and functionality of other apps submitted by you or another developer"
What it really means
- 4.2 (#3 most common rejection): "Your app doesn't do enough to justify existing as a native app" — not enough value beyond what a website provides.
- 4.3 (#2 most common rejection): "Your app looks too similar to another app, or is template-generated." Apple actively fights template-mill spam.
Detection — is this really a 4.2/4.3?
Before assuming the rejection is valid, check for misclassification:
# Is the app a WKWebView wrapper?
grep -rn "WKWebView\|SFSafariViewController\|UIWebView" --include="*.swift" .
# Does the app use native features at all?
grep -rn "import CoreLocation\|import AVFoundation\|import UserNotifications\|import HealthKit\|import CoreML" --include="*.swift" .
# Is the codebase template-generated? (common template markers)
grep -rn "powered by\|generated by\|template\|starter kit" --include="*.swift" --include="*.plist" .If WKWebView is the primary UI and native feature imports are absent, the rejection is likely valid.
Response decision tree
Is the rejection valid? (be honest)
│
├─ YES, app is thin / web wrapper
│ ├─ Can you add meaningful native features? → Add them (see Evidence Checklist)
│ └─ Core value IS the web content? → Consider reader app model or PWA instead
│
├─ PARTIALLY, app has value but reviewer missed it
│ ├─ Did you provide demo credentials? → If not, resubmit with access
│ ├─ Is the value hidden behind onboarding? → Add review notes explaining path to value
│ └─ Does the app need content/data to show value? → Pre-populate sample data for review
│
└─ NO, app is clearly feature-rich
└─ Appeal with detailed functionality walkthrough (Pattern 7)
Include: feature list, screenshots of each major screen, video demoEvidence checklist — what satisfies reviewers
For 4.2 (Minimum Functionality) — demonstrate native value:
Features that prove native value:
☐ Offline functionality (data available without network)
☐ Push notifications with meaningful triggers
☐ Device API usage (camera, location, sensors, HealthKit)
☐ Custom UI beyond web content (native controls, animations, gestures)
☐ Local data persistence and sync
☐ Widget, Live Activity, or Watch companion
☐ Accessibility features (VoiceOver, Dynamic Type)
☐ System integration (Shortcuts, Share Extension, Spotlight)
Changes that DON'T help:
✗ Adding a splash screen or settings-only screen to a web wrapper
✗ Cosmetic changes (colors/fonts) without functional native featuresFor 4.3 (Spam / Duplicate) — demonstrate uniqueness:
How to differentiate:
☐ Unique UI that doesn't match other apps in your catalog
☐ Different target audience with distinct feature set
☐ Separate branding (icon, name, color scheme)
☐ Features that justify a separate app vs. being a mode in an existing app
☐ Distinct App Store description and screenshots
☐ Different primary use case (not just themed variants)
If you have multiple similar apps:
☐ Consolidate into one app with multiple modes/themes
☐ Remove duplicates before resubmitting
☐ Explain in review notes why apps need to be separateCommunication template
Resolution Center response (adapt for 4.2 or 4.3):
"Thank you for your feedback. [Choose one]:
For 4.2: We have added native features that provide value beyond our
web presence: [list features with device capabilities used].
For 4.3: Our app is distinct from [similar app] — different target
audience ([X] vs [Y]), unique features ([list]), separate branding.
[Attach: screenshots of each major screen, 30-60s video walkthrough]
Demo credentials: [username] / [password]"Verification
- Test the app yourself: would YOU download this instead of using the website?
- Compare against your other apps: can you clearly articulate why they're separate?
- Pre-populate demo data so the reviewer sees value immediately
- Record a 30-60 second walkthrough video showing native features in action
---
Pattern 9: Guideline 1.x — Safety: Content / UGC / Kids
Time to resolve 1-3 weeks (requires moderation infrastructure or content changes)
Rejection messages and what they mean
- 1.1: "Your app includes content that many users would find objectionable" — Apple reviews content strictly, including content accessible through your app.
- 1.2: "Your app enables the display of user-generated content but does not include sufficient mechanisms to report offensive content" — UGC without adequate moderation. Non-negotiable: if users can post anything, you need a complete moderation system.
- 1.3: "Your Kids category app must comply with COPPA" / "includes third-party analytics not appropriate for Kids" — Kids category has the tightest rules. Any gap is a rejection.
Detection — which sub-guideline?
Does the app have UGC?
├─ YES → Likely 1.2 (moderation required)
│ ├─ Comments, posts, or forums? → Need reporting + moderation
│ ├─ Photo/video uploads visible to others? → Need content review
│ ├─ User profiles visible to others? → Need profile reporting
│ └─ Chat or messaging? → Need blocking + reporting + content filtering
│
├─ Is it in the Kids category?
│ └─ YES → Likely 1.3 (strict requirements)
│ ├─ Any third-party SDKs? → Must be certified for kids
│ ├─ Any external links? → Must be gated or removed
│ └─ Any purchases? → Must have parental gate
│
└─ Does it display third-party or app-provided content?
└─ YES → Likely 1.1 (content standards)
├─ Web content via WKWebView? → Must filter or restrict
├─ AI-generated content? → Must moderate outputs
└─ Content from third-party APIs? → Must filter before displayResponse decision tree
UGC rejection (1.2):
What moderation exists?
│
├─ No moderation at all
│ └─ Implement complete moderation system (see Implementation Checklist)
│
├─ Reporting exists but insufficient
│ ├─ Missing blocking? → Add user blocking (immediate effect)
│ ├─ No response workflow? → Add 24-hour review commitment
│ └─ No pre-publish review? → Add content queue or ML filtering
│
└─ Moderation exists but not visible to reviewer
└─ Add review notes explaining moderation flow + demo how to trigger itKids category rejection (1.3):
What triggered the rejection?
│
├─ Third-party SDKs
│ └─ Remove ALL analytics/ads SDKs not certified for Kids category
│ Common offenders: Firebase Analytics, Facebook SDK, AdMob
│ Allowed: Apple's own frameworks, COPPA-certified SDKs only
│
├─ External links
│ └─ Remove all links OR gate behind parental verification
│ Includes: "Visit our website", social media links, "More apps"
│
├─ In-app purchases
│ └─ Add parental gate before ANY purchase flow
│ Gate must require adult knowledge (e.g., "spell this word", math problem)
│ Simple "Are you 18?" button is NOT sufficient
│
└─ Data collection
└─ Remove ALL data collection not essential to app function
No device IDs, no location, no contact info, no trackingImplementation checklist — minimum viable moderation (1.2)
Required for ANY app with UGC:
☐ Report button on every piece of user content (visible, not buried)
☐ Block user functionality (immediate, no delay)
☐ Visible Terms of Use / Community Guidelines (accessible from within app)
☐ Content review workflow (human review queue or ML pre-screening)
☐ 24-hour response commitment for reported content
☐ Ability to remove content and ban users
☐ In-app link to Terms of Use from content creation screensKids category requirements (1.3)
MANDATORY for Kids category:
☐ COPPA compliance (no data collection from children under 13)
☐ No third-party advertising (none, not even "child-safe" networks)
☐ No external links (or gated behind parental verification)
☐ No social features (no chat, no profiles, no friend lists)
☐ Parental gate before any purchase (not a simple age button)
☐ Remove ALL non-COPPA-certified SDKs (Firebase Analytics, Facebook, AdMob, Crashlytics)
☐ No user tracking of any kind
☐ Privacy policy specifically addresses children's dataCommunication template
Resolution Center response (adapt for 1.2 or 1.3):
"Thank you for your feedback. [Choose one]:
For 1.2 (UGC): We have implemented moderation: report button on all
content [location], user blocking, [review workflow], Terms of Use at
[URL]. To test: create a post → [...] menu → Report.
For 1.3 (Kids): Removed [SDKs]. External links [removed/gated].
Added parental gate for purchases. No user data collected.
Privacy policy updated at [URL].
[Attach: screenshots showing moderation/parental gate flow]"Verification
- Test the report flow end-to-end: report content, verify it reaches a review queue
- Test the block flow: block a user, verify their content is hidden immediately
- For Kids: remove the app from a test device, reinstall, verify no data persists
- For Kids: run
strings YourApp.app/YourApp | grep -i "firebase\|facebook\|google\|admob"to catch embedded SDKs - Have someone unfamiliar with the app try to find the report/block buttons — if they can't find them in 5 seconds, they're not prominent enough
---
Quick Reference Table
| Rejection Type | Likely Cause | First Check | Pattern | Typical Fix Time |
|---|---|---|---|---|
| Guideline 2.1 | Crashes/placeholders | Test on device, search placeholders | 1 | 1-3 days |
| Guideline 2.3 | Metadata mismatch | Compare screenshots to app | 2 | 1 day (no build) |
| Guideline 5.1 | Privacy gaps | Check policy + manifest + purpose strings | 3 | 2-5 days |
| Guideline 4.8 | Missing SIWA | Check for third-party login | 4 | 3-5 days |
| Guideline 3.x | Payment method | Review IAP flows | 5 | 3-14 days |
| Binary Rejected | Technical gate | Check SDK, manifest, encryption | 6 | 1-2 days |
| Guideline 1.x | Safety/content/UGC | Check UGC moderation + Kids compliance | 9 | 1-3 weeks |
| Guideline 4.2/4.3 | Thin app/spam | Audit native features + app uniqueness | 8 | 1-4 weeks |
Under deadline pressure? Fix the cited issues, then request expedited review (developer.apple.com/contact/app-store/?topic=expedite) for a 1-3 day turnaround. Never resubmit unchanged — App Review sees the full rejection history and escalates unchanged resubmissions to a senior reviewer (Pattern 7).
Production Crisis Scenario
Context: App rejected for 3rd time, different reason each time, launch is tomorrow
Situation: Marketing committed to a launch date. App was rejected for crashes (fixed), then metadata (fixed), now privacy policy "doesn't match actual data collection."
Pressure signals:
- Product team already sent press releases with launch date
- App Store rating will drop if launch delayed
- Manager asking "why wasn't this caught earlier?"
- Temptation to quick-fix only the cited privacy issue
Why this happens: Each review pass goes deeper. First pass catches obvious issues (crashes). Second pass checks metadata. Third pass audits privacy compliance. This is normal, not "the reviewer is picking on you."
Rationalization traps (DO NOT fall into these)
1. "Just fix the privacy policy wording and resubmit"
- The reviewer said "doesn't match actual data collection"
- That means your app collects data you didn't disclose
- A wording change without auditing actual data collection = another rejection
2. "The reviewer is being unreasonable, let's appeal"
- Three rejections for three different valid issues is not unreasonable
- Appealing wastes 3-14 days when you could fix and resubmit in 1-3 days
3. "Let's remove the privacy-sensitive features to ship faster"
- Removing features changes the app, requiring re-review of everything
- May introduce new issues (broken UI, missing functionality)
4. "Different reviewer next time might not notice"
- Reviewers see the rejection history — they check previously cited issues
- Repeat rejections get escalated to senior reviewers
MANDATORY approach
1. Don't panic. Don't resubmit without a thorough fix. 2. Run the COMPLETE pre-flight checklist — not just the cited issue. 3. Audit all data collection: every SDK, every analytics call, every API request that sends user data. 4. Generate privacy report (Product > Archive > Generate Privacy Report) and cross-reference with privacy policy. 5. Fix privacy policy to specifically list every data type actually collected. 6. Verify all previous rejection issues still fixed (crashes, metadata). 7. Request expedited review at developer.apple.com/contact/app-store/?topic=expedite if genuinely time-critical. 8. Communicate to stakeholders: "Each review fixes more issues. This submission addresses privacy compliance comprehensively."
Time comparison
| Approach | Time to Approval |
|---|---|
| Quick fix + resubmit | 7-14 more days (likely rejected again) |
| Full audit + thorough fix | 3-5 days (high confidence) |
| Full audit + expedited review | 1-3 days (if granted) |
Professional communication template
To stakeholders:
"Root cause: Our third-party analytics SDK collects device identifiers
that weren't disclosed in our privacy policy or nutrition labels.
Fix: Updated privacy policy, privacy nutrition labels in ASC, and
PrivacyInfo.xcprivacy to accurately reflect all data collection.
Also audited all SDKs for undisclosed collection.
Timeline: Resubmitting today with expedited review request.
Expected approval: 1-3 business days.
Prevention: Adding privacy audit to our pre-submission checklist
so future submissions include accurate disclosure from the start."---
Common Mistakes
1. Skimming the Rejection Message
Problem Developer reads "Guideline 5.1" and assumes they know the issue without reading the full explanation.
Why it fails Guideline 5.1 covers privacy policy, purpose strings, privacy manifest, tracking, AND data collection disclosure. The rejection message tells you exactly which aspect failed. Guessing the wrong one wastes a full review cycle (3-7 days).
Fix: Copy the FULL rejection text. Highlight every specific requirement mentioned. Map each one to the fix before writing any code.
2. Fixing Only the Cited Issue
Problem Rejection cites Guideline 5.1 (privacy). Developer fixes privacy but doesn't check for other issues.
Why it fails Reviewers find new issues on each pass. First pass catches crashes, second catches metadata, third catches privacy. If you only fix privacy, the fourth pass might find a Guideline 4.8 (SIWA) issue.
Fix: Before every resubmission, run through ALL common rejection patterns (1-6). Fix everything proactively. One thorough submission beats three partial ones.
3. Resubmitting Without Changes
Problem "Maybe a different reviewer will approve it."
Why it fails Reviewers see the rejection history. Unchanged resubmissions get the same result or escalated to senior reviewers. Each wasted cycle costs 3-7 days.
Fix: Always make at least the changes the reviewer requested. If you believe the rejection is wrong, reply in ASC with evidence first.
4. Arguing Emotionally in App Review Messages
Problem "This is unfair! Other apps do this! You're blocking our business!"
Why it fails App Review is a technical compliance review, not a negotiation. Emotional arguments are ignored. Specific evidence of compliance works.
Fix: Be factual, specific, and professional. Quote the guideline. Show screenshots. Provide technical evidence.
5. Ignoring Third-Party SDK Issues
Problem "We don't collect that data — it must be the SDK."
Why it fails Your app is responsible for ALL SDK behavior. If Facebook SDK collects device identifiers, YOUR privacy policy and nutrition labels must disclose it.
Fix: Audit every third-party SDK. Generate Privacy Report to see aggregate data collection. Update privacy policy and nutrition labels to cover all SDK behavior.
6. Deploying Backend Changes During Review
Problem Pushing a backend update that changes API responses while the app is under review.
Why it fails Reviewers may test at any time during the review window. A backend change that breaks the reviewed build = crash during review = Guideline 2.1 rejection.
Fix: Freeze backend during review period. If changes are necessary, ensure backward compatibility with the submitted build.
7. Not Using Expedited Review When Available
Problem Developer doesn't know about or doesn't use expedited review for critical situations.
Why it fails Waiting 3-7 days for standard review when a 1-day expedited review is available for legitimate reasons.
Fix: Request expedited review at developer.apple.com/contact/app-store/?topic=expedite for: critical bug fixes, time-sensitive events, or security patches. Don't abuse it — Apple tracks usage and may deny future requests.
---
Pre-Submission Checklist
Run through this BEFORE every App Store submission to prevent rejections:
App Completeness (2.1):
☐ Tested on latest shipping iOS version on physical device
☐ Tested on at least 2 device sizes (iPhone SE, iPhone Pro Max)
☐ No placeholder text (search: Lorem, TODO, FIXME, placeholder, sample)
☐ All URLs resolve (support URL, privacy policy, in-app links)
☐ Demo credentials provided if login required (non-expiring)
☐ Backend stable and not deploying during review window
Metadata (2.3):
☐ Screenshots taken from submitted build (not dev build)
☐ Every feature in description exists and works
☐ No trademarked terms in keywords
☐ Age rating matches content
☐ "What's New" text accurate
Privacy (5.1):
☐ Privacy policy accessible in-app AND via URL in ASC
☐ Privacy policy matches actual data collection
☐ Every permission has specific, honest purpose string
☐ PrivacyInfo.xcprivacy exists and lists all required reason APIs
☐ Privacy Report generated and cross-referenced
☐ ATT implemented if any cross-app tracking
☐ Privacy nutrition labels accurate (including third-party SDKs)
Sign in with Apple (4.8):
☐ If third-party login exists, SIWA offered at same prominence
☐ SIWA flow works: sign in, account creation, revocation handling
☐ Account deletion supported (required since June 2022)
Business (3.x):
☐ All digital goods/features use Apple IAP
☐ IAP products approved in ASC before app submission
☐ Subscription terms clear before purchase
☐ Loot box odds disclosed if applicable
Technical (Binary):
☐ Xcode version meets Apple's current requirements
☐ "Validate App" passes in Xcode Organizer
☐ ITSAppUsesNonExemptEncryption key present
☐ Provisioning profile not expired
☐ Tested with release configuration on device
Safety & Content (1.x):
☐ If UGC: report, block, and moderation workflow all functional
☐ If Kids category: no non-COPPA SDKs, no external links, parental gate on purchases
☐ AI-generated or third-party content has moderation/filtering
Design & Originality (4.2/4.3):
☐ App provides native value beyond a website (offline, push, device APIs)
☐ App is distinct from other apps in your catalog
☐ Demo data pre-populated for reviewer if app needs content to show value---
Cross-References
- app-store-connect-ref — ASC crash analysis, TestFlight feedback, metrics dashboards
- privacy-ux — Privacy manifest implementation details and required reason APIs
- storekit-ref — StoreKit 2 IAP/subscription implementation
- accessibility-diag — Accessibility compliance (VoiceOver, Dynamic Type, WCAG)
- axiom-build — Build and signing issues that cause Binary Rejected
- axiom-tools (skills/xcsym-ref.md) — Symbolicate reviewer crash
.ipsfiles, getpattern_tag+ crashed-thread frames
Resources
WWDC: 2025-328
Docs: /app-store/review/guidelines, /distribute/app-review, /support/offering-account-deletion-in-your-app, /contact/app-store/?topic=appeal
Skills: app-store-connect-ref, privacy-ux, storekit-ref, accessibility-diag, axiom-tools (skills/xcsym-ref.md)
App Store Connect MCP Integration
Core principle: When asc-mcp is configured, you can manage the entire App Store Connect workflow without leaving Claude Code — submit builds, distribute to TestFlight, respond to reviews, and monitor metrics programmatically.
Setup
Install
brew install mint
mint install zelentsov-dev/asc-mcp@1.4.0Create API Key
1. Open App Store Connect → Users and Access → Integrations → API 2. Generate key with Admin or App Manager role 3. Download the .p8 file (one-time download — save it securely) 4. Note the Key ID and Issuer ID
Add to Claude Code
claude mcp add asc-mcp \
-e ASC_KEY_ID=YOUR_KEY_ID \
-e ASC_ISSUER_ID=YOUR_ISSUER_ID \
-e ASC_PRIVATE_KEY_PATH=/path/to/AuthKey.p8 \
-- ~/.mint/bin/asc-mcpVerify
Ask Claude to call company_current. If it returns your team name, you're connected.
---
Worker Filtering
asc-mcp has 25 workers (~208 tools). Loading all of them wastes context. Use --workers to load only what you need.
Presets
| Preset | Workers | Tools | Use Case |
|---|---|---|---|
| TestFlight | apps,builds,beta_groups,beta_testers | ~34 | Beta distribution |
| Release | apps,builds,versions,reviews | ~40 | App Store submission |
| Monetization | apps,iap,subscriptions,offer_codes,pricing | ~55 | IAP and subscriptions |
| Full | (default, all workers) | ~208 | Everything |
To use a preset, add --workers when registering the server:
claude mcp add asc-mcp \
-e ASC_KEY_ID=... \
-e ASC_ISSUER_ID=... \
-e ASC_PRIVATE_KEY_PATH=... \
-- ~/.mint/bin/asc-mcp --workers apps,builds,versions,reviewsNote: company and auth workers always load regardless of --workers. When builds is enabled, build_processing and build_beta are included automatically.
Worker Selection Decision Tree
digraph workers {
"What are you doing?" [shape=diamond];
"TestFlight preset" [shape=box, label="--workers apps,builds,\nbeta_groups,beta_testers"];
"Release preset" [shape=box, label="--workers apps,builds,\nversions,reviews"];
"Monetization preset" [shape=box, label="--workers apps,iap,\nsubscriptions,offer_codes,pricing"];
"Full (no flag)" [shape=box, label="No --workers flag\n(all 208 tools)"];
"What are you doing?" -> "TestFlight preset" [label="distributing beta builds"];
"What are you doing?" -> "Release preset" [label="submitting to App Store"];
"What are you doing?" -> "Monetization preset" [label="managing IAP/subscriptions"];
"What are you doing?" -> "Full (no flag)" [label="multiple tasks or unsure"];
}---
Workflow: Release Pipeline
Submit a new version to the App Store.
1. apps_search(query: "MyApp") → get app ID
2. builds_list(appId, limit: 5) → find latest processed build
3. app_versions_create(appId, platform: "IOS", versionString: "2.1.0")
4. app_versions_attach_build(versionId, buildId)
5. app_versions_set_review_details(versionId, { contactEmail, notes, ... })
6. app_versions_submit_for_review(versionId)
7. (After approval) app_versions_create_phased_release(versionId)Before step 3: Version string must not already exist. Check with app_versions_list.
Before step 4: Build must be in VALID processing state. Check with builds_get_processing_state.
Before step 6: Version must be in PREPARE_FOR_SUBMISSION state. Attaching a build and setting review details are prerequisites.
---
Workflow: TestFlight Distribution
Distribute a build to beta testers.
1. apps_search(query: "MyApp") → get app ID
2. builds_list(appId, limit: 5) → find latest build
3. builds_set_beta_localization(buildId, locale: "en-US", whatsNew: "Bug fixes")
4. beta_groups_list(appId) → find or create group
OR beta_groups_create(appId, name: "Internal Testers", isInternal: true)
5. beta_groups_add_builds(groupId, [buildId])
6. builds_send_beta_notification(buildId) → notify testers (optional)Tip: Internal testers (up to 100) get builds immediately. External testers (up to 10,000) require Beta App Review for the first build of each version.
---
Workflow: Review Management
Monitor and respond to App Store reviews.
1. apps_search(query: "MyApp") → get app ID
2. reviews_list(appId, sort: "-createdDate", limit: 20)
OR reviews_list(appId, filterRating: "1,2") → negative reviews only
3. reviews_stats(appId) → rating distribution summary
4. reviews_create_response(reviewId, responseBody: "Thank you for...")Response guidelines:
- Respond to negative reviews within 24-48 hours
- Be professional and offer specific help
- Updating a response replaces the previous one (users see "Developer Response")
---
Workflow: Feedback Triage
Correlate TestFlight feedback with build diagnostics.
1. builds_list(appId, limit: 10) → recent builds
2. builds_get_beta_testers(buildId) → who tested this build
3. metrics_build_diagnostics(buildId) → crash signatures for this build
4. metrics_get_diagnostic_logs(signatureId) → individual crash logsLimitation: TestFlight text feedback and screenshots are NOT available via the App Store Connect API. Use Xcode Organizer or the ASC web dashboard for feedback content.
---
Workflow: Multi-Company
Switch between App Store Connect teams.
1. company_list → see configured accounts
2. company_switch(companyId: "client-a") → switch active account
3. (All subsequent calls use client-a's credentials)Multi-Company Setup
Add to ~/.config/asc-mcp/companies.json:
{
"companies": [
{
"id": "my-company",
"name": "My Company",
"key_id": "KEY_ID_1",
"issuer_id": "ISSUER_1",
"key_path": "/Users/you/.keys/AuthKey1.p8"
},
{
"id": "client-a",
"name": "Client A",
"key_id": "KEY_ID_2",
"issuer_id": "ISSUER_2",
"key_path": "/Users/you/.keys/AuthKey2.p8"
}
]
}Or use numbered environment variables: ASC_COMPANY_1_NAME, ASC_COMPANY_1_KEY_ID, etc.
---
Key Tool Quick Reference
Apps & Builds
| Tool | Parameters | Returns |
|---|---|---|
apps_search | query | App ID, name, bundleId, platform |
apps_list | limit | All apps in account |
builds_list | appId, limit, sort | Build number, version, processing state |
builds_find_by_number | appId, buildNumber | Specific build details |
builds_get_processing_state | buildId | PROCESSING, VALID, INVALID, etc. |
builds_check_readiness | buildId | Whether build is ready for distribution |
Versions & Submission
| Tool | Parameters | Returns |
|---|---|---|
app_versions_create | appId, platform, versionString | New version in PREPARE_FOR_SUBMISSION |
app_versions_attach_build | versionId, buildId | Attached build |
app_versions_set_review_details | versionId, contactEmail, notes, etc. | Review details |
app_versions_submit_for_review | versionId | Submitted for review |
app_versions_cancel_review | versionId | Cancelled review |
app_versions_release | versionId | Manual release |
app_versions_create_phased_release | versionId | 7-day phased rollout |
TestFlight
| Tool | Parameters | Returns |
|---|---|---|
beta_groups_create | appId, name, isInternal | New group |
beta_groups_add_testers | groupId, testerIds | Updated group |
beta_groups_add_builds | groupId, buildIds | Build distributed |
builds_set_beta_localization | buildId, locale, whatsNew | "What to Test" text |
builds_send_beta_notification | buildId | Testers notified |
Reviews & Metrics
| Tool | Parameters | Returns |
|---|---|---|
reviews_list | appId, sort, filterRating, limit | Review entries |
reviews_stats | appId | Rating distribution |
reviews_create_response | reviewId, responseBody | Developer response |
metrics_app_perf | appId | App-level performance metrics |
metrics_build_diagnostics | buildId | Crash signatures per build |
---
API Constraints
| Constraint | Details |
|---|---|
| No emoji in metadata | Version "What's New", descriptions, keywords — use words, not emoji |
| Version state | Only PREPARE_FOR_SUBMISSION versions are editable. Once submitted, create a new version to make changes. |
| JWT lifetime | 20-minute tokens, auto-refreshed by asc-mcp |
| Rate limits | Apple enforces per-account limits. asc-mcp retries with exponential backoff on 429s. |
| Locale format | Standard codes: en-US, ja, de-DE, zh-Hans, ru |
| Build processing | Newly uploaded builds take 15-30 minutes to process. Poll builds_get_processing_state before attaching. |
| Phased release | Only available after approval. Can pause/resume with app_versions_update_phased_release. |
---
Gotchas
| Gotcha | Details |
|---|---|
| Build not found | Build may still be processing. Check builds_get_processing_state — must be VALID. |
| "Version already exists" | Can't create duplicate version strings. Use app_versions_list to check first. |
| Attach fails | Build must be processed AND the version must be in PREPARE_FOR_SUBMISSION. |
| Review details rejected | Contact info fields have format requirements. Email must be valid, phone must include country code. |
| Wrong app | apps_search is fuzzy. Verify the returned bundleId matches your target app. |
| Multi-company confusion | Always call company_current first to confirm which account is active before making changes. |
| Beta App Review | First external TestFlight build per version requires review. Subsequent builds to the same version are auto-approved. |
| Missing analytics | analytics_* tools require vendor_number in company config. Without it, sales/financial reports fail silently. |
---
Anti-Rationalization
| Thought | Reality |
|---|---|
| "I'll just use the ASC web dashboard" | MCP tools are faster for repetitive tasks — respond to 20 reviews, distribute to 5 groups, create versions across apps. |
| "I don't need worker filtering" | 208 tools consume ~30K tokens of context. Filter to what you need. |
| "I'll submit without review details" | Submission will fail. app_versions_set_review_details is required before app_versions_submit_for_review. |
"I'll skip company_current — I only have one account" | Multi-company configs persist between sessions. Always verify. |
| "Feedback triage is the same via API" | Text feedback and screenshots are NOT in the ASC API. Use Organizer for feedback content, MCP for crash diagnostics. |
---
When asc-mcp is NOT Available
If asc-mcp is not configured, fall back to manual workflows:
- Crash analysis: Use Xcode Organizer (see
axiom-shipping (skills/testflight-triage.md)) or App Store Connect web dashboard (seeaxiom-shipping (skills/app-store-connect-ref.md)) - TestFlight distribution: Use Xcode → Product → Archive → Distribute, or
xcodebuild+altool - Review management: Use App Store Connect web dashboard
- Submission: Use Xcode → Product → Archive → Distribute to App Store
---
Resources
Skills: axiom-shipping (skills/app-store-submission.md), axiom-shipping (skills/app-store-ref.md), axiom-shipping (skills/app-store-connect-ref.md), axiom-shipping (skills/testflight-triage.md)
Agents: crash-analyzer, security-privacy-scanner, iap-auditor
Expert Review Checklist
Comprehensive 9-section submission checklist. For the discipline-focused pre-flight workflow, see app-store-submission.
Build
- [ ] Built with the current required SDK (Apple mandates the latest major SDK within months of release — currently Xcode 26 / iOS 26 SDK)
- [ ] Export compliance answered (
ITSAppUsesNonExemptEncryption) - [ ] Encryption documentation uploaded (if custom encryption)
- [ ] IPv6-only network compatible
- [ ] Signed with distribution certificate and provisioning profile
- [ ] Correct bundle ID for target environment (production, not development)
- [ ] Build string unique for this version
- [ ] Binary under 200 MB OTA cellular limit (or warn users)
- [ ] All required architectures included (arm64)
- [ ] No private API usage
Privacy
- [ ]
PrivacyInfo.xcprivacypresent and complete - [ ] Privacy policy URL set in App Store Connect
- [ ] Privacy policy accessible within the app
- [ ] All purpose strings (
NS*UsageDescription) present for requested permissions - [ ] ATT implemented if app tracks users
- [ ] Required Reason APIs declared with approved reasons
- [ ] Privacy Nutrition Labels match actual data collection
- [ ] Third-party SDK privacy manifests included
- [ ] Privacy report generated and reviewed (
Product > Archive > Generate Privacy Report)
Metadata
- [ ] App name unique, max 30 characters
- [ ] Description complete, max 4000 characters, plain text
- [ ] Keywords set, max 100 bytes, no trademarked terms
- [ ] Screenshots provided for all supported device sizes
- [ ] Screenshots show app in actual use (not title art or splash screens)
- [ ] What's New text updated for this version
- [ ] Copyright field current year
- [ ] Support URL links to real contact information
- [ ] Privacy Policy URL is HTTPS and publicly accessible
- [ ] Promotional Text set (editable without submission)
- [ ] App category accurate
- [ ] All metadata localized for target markets
Account
- [ ] Account deletion implemented and easy to find
- [ ] SIWA token revocation on account deletion
- [ ] Sign in with Apple offered if any third-party login exists
- [ ] SIWA given equal visual prominence to other login options
- [ ] Demo credentials provided in App Review Information (if login required)
- [ ] Demo credentials will not expire during review period
Content
- [ ] No placeholder content ("Lorem ipsum", "Coming Soon", etc.)
- [ ] All links functional and leading to real content
- [ ] Final production assets (not development/staging URLs)
- [ ] No test data visible in screenshots or app
- [ ] No references to other mobile platforms in metadata
Age Rating
- [ ] Age rating questionnaire completed
- [ ] New capability declarations answered (messaging, UGC, advertising, parental, age assurance)
- [ ] UGC moderation implemented if applicable
- [ ] Content filtering in place for web views (or accept 16+ minimum)
- [ ] Loot box odds disclosed if applicable
Monetization
- [ ] All IAPs configured and in "Ready to Submit" status
- [ ] IAP screenshots uploaded
- [ ] Subscription terms clear (price, duration, auto-renewal, cancellation)
- [ ] Loot box odds displayed before purchase
- [ ] Restore Purchases functionality working
- [ ] No removing paid features to force new purchases
- [ ] Subscription grace period supported
- [ ] Offer codes configured if planned
EU Compliance
- [ ] DSA trader status declared for all EU-distributed apps
- [ ] Trader email verified via 2FA
- [ ] Trader phone verified via 2FA
- [ ] Contact information accurate and current
- [ ] Labels and markings complete (if applicable for product category)
App Review
- [ ] Contact information complete (name, email, phone)
- [ ] Demo account credentials provided (if login required)
- [ ] Notes for Review explain any non-obvious features
- [ ] Attachment uploaded for features requiring special hardware or setup
- [ ] Review contact email actively monitored
Related skills
How it compares
Pick axiom-shipping for Apple App Store compliance; pick a TestFlight or CI skill for build upload automation without review guideline guidance.
FAQ
What does axiom-shipping cover for iOS apps?
axiom-shipping guides App Store Connect submission checklists, metadata and screenshot requirements, privacy manifests and nutrition labels, age ratings, export compliance, Sign in with Apple rules, and account deletion requirements for iOS and macOS apps.
When must agents use axiom-shipping?
Agents must load axiom-shipping when preparing any app for App Store submission, handling an App Store rejection, writing an appeal, or working on release workflow items like privacy manifests and EU DSA trader status.
Does axiom-shipping help with App Store rejections?
axiom-shipping provides rejection troubleshooting for any App Store Review guideline, plus appeal drafting and remediation steps for metadata, privacy, encryption declarations, and compliance gaps that caused the rejection.
Is Axiom Shipping safe to install?
skills.sh reports 1 of 3 security scanners passed. Review the Security Audits panel on this page before installing in production.