| name | swift-appstore |
| description | Use this skill when working on any Swift/iOS/iPadOS/macOS app that needs to be submitted to the Apple App Store. Covers App Store Review Guidelines (Safety, Performance, Business, Design, Legal), App Store Connect required fields and metadata, privacy manifests, entitlements, code signing, in-app purchases, TestFlight, and pre-submission checklists. Trigger when the user mentions App Store submission, rejection handling, App Store Connect fields, privacy policy requirements, in-app purchases, app review notes, age ratings, or any Apple platform app release workflow. |
| version | 1.0.0 |
| author | Khalid Abdi |
| license | MIT |
SwiftShip: Ship iOS Apps to the App Store Correctly the First Time
This skill gives an agent everything needed to prepare, submit, and pass Apple App Store review without external lookups. It covers the Review Guidelines, every App Store Connect field with exact character limits, privacy manifests, entitlements, code signing, in-app purchases, subscriptions, age ratings, and the end-to-end submission workflow.
Use the companion files for deep dives:
checklists/pre-submission.md full technical and content checklist
checklists/privacy-manifest.md PrivacyInfo.xcprivacy guide
checklists/aso-checklist.md App Store Optimization checklist
templates/app-store-connect-fields.md every ASC field with limits and tips
templates/review-notes-template.md App Review Information notes
templates/privacy-policy-template.md minimal privacy policy
templates/subscription-setup.md StoreKit subscription configuration
How to use this skill
When a user is preparing an App Store release, work through these phases in order:
- Confirm the build is technically sound (SDK, privacy manifest, no private APIs, accessibility).
- Fill every required App Store Connect field within its character limit.
- Verify privacy declarations match actual data use.
- Configure in-app purchases and subscriptions if present.
- Complete the age rating questionnaire.
- Write App Review notes and provide a demo account.
- Archive, validate, upload, and submit.
Do not tell a user "you may get rejected." Instead, identify the specific guideline at risk and give the concrete fix.
1. App Store Review Guidelines: the 5 pillars
Apple organizes the Review Guidelines into five sections. Below are the sections and the sub-guidelines that cause the most rejections, each with the fix.
Safety (Guideline 1)
- 1.1 Objectionable content. No defamatory, discriminatory, or mean-spirited content. Fix: add a content filter and a reporting mechanism.
- 1.2 User-generated content. Any app with UGC MUST include: a method to filter objectionable material, a mechanism to report offensive content with timely response, the ability to block abusive users, and published contact info. Missing any of these four is an automatic rejection. Fix: implement all four before submitting.
- 1.4 Physical harm. Medical, drug-dosage, or safety apps get extra scrutiny. Fix: cite sources and add disclaimers.
- 1.5 Developer information. Support URL must resolve and provide real contact. Fix: host a working support page.
Performance (Guideline 2)
- 2.1 App completeness. The single most common rejection. Builds must be final, not demos or trials, must not crash, and must not contain placeholder content, broken links, or bugs. Reviewers need full access to all features. Fix: test on device, remove placeholders, provide a demo account for gated features, and answer the App Review "additional information" prompts.
- 2.3 Accurate metadata. Screenshots, description, and preview must reflect the actual app. No pricing in screenshots, no references to other platforms (Android), no "beta"/"test" language. Fix: use real in-app screenshots at current device sizes.
- 2.5 Software requirements. Use only public APIs, the current SDK, and declare background modes honestly. No downloading executable code. Fix: remove private API usage (see detection below).
Business (Guideline 3)
- 3.1.1 In-app purchase. Unlocking features or content used inside the app MUST use Apple in-app purchase. You cannot link to external payment or tell users to pay elsewhere for digital goods. Physical goods and services consumed outside the app use other payment methods and must NOT use IAP. Fix: route all digital unlocks through StoreKit.
- 3.1.2 Subscriptions. Must work across the user's devices, and the app must disclose price, duration, and auto-renewal before purchase.
- 3.1.3 "Reader" apps. Specific categories (magazines, video, music, cloud storage) may let users access previously purchased content without offering IAP, and may qualify for the External Link Account Entitlement.
Design (Guideline 4)
- 4.2 Minimum functionality. The app must do something useful, unique, and app-like. A thin wrapper around a website, a repackaged template, or a marketing brochure is rejected. Fix: add native features (offline mode, notifications, device integration) that a mobile website cannot provide.
- 4.3 Spam. No duplicate apps or apps that differ only by minor branding. Consolidate variants into one app, or use a single app with configuration.
- 4.8 Sign in with Apple. If the app uses a third-party or social login (Google, Facebook), it must also offer Sign in with Apple, unless the exclusive login is the developer's own account system or an education/enterprise/government system. Fix: add Sign in with Apple.
- 4.0 / 4.1 Design and copycats. Follow the Human Interface Guidelines; do not copy another app's UI or name.
Legal (Guideline 5)
- 5.1.1 Data collection and storage. Every permission prompt (NSCameraUsageDescription and friends) MUST have a specific, purpose-driven string. Generic strings like "This app needs access" are rejected. Request permission only when a feature needs it, and only if the app functions without unnecessary data. Fix: rewrite each usage string to name the exact feature.
- 5.1.1(v) Account deletion. Any app that supports account creation MUST offer in-app account deletion (not just deactivation). Fix: add a "Delete Account" flow inside the app.
- 5.1.2 Data use and sharing. Match your privacy nutrition labels and privacy manifest to actual behavior.
- 5.2 Intellectual property. Do not use third-party trademarks or content without rights.
- 5.3 Gaming, gambling, lotteries. Extra licensing requirements apply.
2. Pre-Submission Checklist (summary)
Full version in checklists/pre-submission.md. Minimum bar:
Technical
- Built with the current iOS SDK (iOS 18 SDK, Xcode 16 or later) as required by Apple's submission cutoff.
PrivacyInfo.xcprivacy present and accurate (see section 4).
- No private API usage. No use of deprecated UIWebView.
- Runs without crashing on a real device and on the lowest supported OS.
- VoiceOver labels on interactive controls, Dynamic Type support, Dark Mode support, and layout that respects safe areas.
- App Transport Security: HTTPS only, no blanket
NSAllowsArbitraryLoads.
Content and safety
- No placeholder text, lorem ipsum, or broken links.
- UGC apps: filtering, reporting, blocking, and contact info implemented.
Privacy and data
- Every
NS*UsageDescription string is specific and purpose-driven.
- Privacy nutrition labels in App Store Connect match the privacy manifest and real data flows.
- In-app account deletion present if accounts exist.
Business and IAP
- All digital unlocks use StoreKit in-app purchase.
- Subscriptions disclose price, duration, and auto-renewal pre-purchase, with links to Terms of Use and Privacy Policy.
Design and minimum functionality
- More than a webview wrapper. Native, useful, app-like.
- Sign in with Apple offered when a third-party social login is present.
3. App Store Connect fields (exact character limits)
Full table with tips in templates/app-store-connect-fields.md. Quick reference:
| Field | Limit | Notes |
|---|
| App Name | 30 chars | Shown on the product page and Home Screen basis. Must be unique. |
| Subtitle | 30 chars | One-line summary under the name. Indexed for search. |
| Keywords | 100 chars total | Comma-separated, no spaces after commas to save characters. Not shown to users. |
| Description | 4000 chars | First 1-2 lines matter most (truncated before "more"). |
| Promotional Text | 170 chars | Editable without a new build. Appears above the description. |
| What's New (release notes) | 4000 chars | Required for updates. |
| Support URL | required | Must resolve to a real support page. |
| Privacy Policy URL | required | Must be a working, app-specific policy. |
| Marketing URL | optional | Product landing page. |
| SKU | internal | Your unique product identifier, not shown to users. |
| Bundle ID | fixed | Must match the Xcode project, cannot change after first submission. |
Screenshots (current required sizes):
- iPhone 6.9" display: 1290 x 2796 or 1320 x 2868 px (portrait). Required.
- iPhone 6.5" display: 1242 x 2688 or 1284 x 2778 px. Accepted if 6.9" not supplied.
- iPad 13" display: 2048 x 2732 or 2064 x 2752 px. Required for iPad apps.
- Up to 10 screenshots per device size per localization.
- App previews: up to 3 videos, 15 to 30 seconds each.
App Review Information:
- Demo account username and password (required if any content is behind a login).
- Contact first name, last name, phone, email.
- Notes field: up to 4000 chars. Use it to explain non-obvious features, how to reach gated content, and any special hardware or regulatory context.
4. Privacy Manifest (PrivacyInfo.xcprivacy)
Since 2024, Apple requires a privacy manifest declaring data collection, tracking domains, and any use of "required reason" APIs. Add a file named exactly PrivacyInfo.xcprivacy to the app target (and each SDK that requires one). Full guide in checklists/privacy-manifest.md.
Complete template:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>NSPrivacyTracking</key>
<false/>
<key>NSPrivacyTrackingDomains</key>
<array/>
<key>NSPrivacyCollectedDataTypes</key>
<array>
<dict>
<key>NSPrivacyCollectedDataType</key>
<string>NSPrivacyCollectedDataTypeEmailAddress</string>
<key>NSPrivacyCollectedDataTypeLinked</key>
<true/>
<key>NSPrivacyCollectedDataTypeTracking</key>
<false/>
<key>NSPrivacyCollectedDataTypePurposes</>
NSPrivacyCollectedDataTypePurposeAppFunctionality
NSPrivacyAccessedAPITypes
NSPrivacyAccessedAPIType
NSPrivacyAccessedAPICategoryUserDefaults
NSPrivacyAccessedAPITypeReasons
CA92.1
NSPrivacyAccessedAPIType
NSPrivacyAccessedAPICategoryFileTimestamp
NSPrivacyAccessedAPITypeReasons
C617.1
NSPrivacyAccessedAPIType
NSPrivacyAccessedAPICategorySystemBootTime
NSPrivacyAccessedAPITypeReasons
35F9.1
NSPrivacyAccessedAPIType
NSPrivacyAccessedAPICategoryDiskSpace
NSPrivacyAccessedAPITypeReasons
E174.1
NSPrivacyAccessedAPIType
NSPrivacyAccessedAPICategoryActiveKeyboards
NSPrivacyAccessedAPITypeReasons
3EC4.1
Required reason API categories and their valid reason codes:
NSPrivacyAccessedAPICategoryFileTimestamp: DDA9.1 (display to user), C617.1 (access timestamps of files available to the app), 3B52.1 (access timestamps inside the app or group container).
NSPrivacyAccessedAPICategorySystemBootTime: 35F9.1 (measure elapsed time between in-app events), 8FFB.1 (calculate absolute timestamps for events from the kernel).
NSPrivacyAccessedAPICategoryDiskSpace: 85F4.1 (display to user), E174.1 (check for sufficient space before writing), 7D9E.1 (check space to avoid errors).
NSPrivacyAccessedAPICategoryUserDefaults: CA92.1 (read/write data accessible only to the app), 1C8F.1 (read/write data shared across an app group with the same team ID), AC6B.1 (read MDM-managed configuration).
NSPrivacyAccessedAPICategoryActiveKeyboards: 3EC4.1 (custom keyboard app determining active keyboards), 54BD.1 (feature requires it).
Only declare the reasons that are actually true. If you set NSPrivacyTracking to true, you MUST list every tracking domain in NSPrivacyTrackingDomains and gate them behind App Tracking Transparency.
5. Common rejection patterns and concrete fixes
Guideline 2.1 (crashes and completeness). Symptom: reviewer sees a crash, a stuck spinner, or cannot reach a feature.
Fix: test on a physical device and the lowest supported OS, remove all placeholder content and dead links, provide a working demo account, and describe how to reach gated features in the Review notes.
Guideline 5.1.1 (vague permission strings). Symptom: rejection quotes your NSCameraUsageDescription.
Fix: rewrite to name the feature. Bad: "This app needs camera access." Good: "SwiftShip uses the camera so you can scan a shipping label barcode to auto-fill tracking numbers."
Guideline 3.1.1 (IAP bypass). Symptom: the app links out to a website to buy a digital subscription, or unlocks content after an external payment.
Fix: sell all digital content and unlocks through StoreKit in-app purchase. Remove external purchase links and any "buy on our website" language for digital goods.
Guideline 4.2 (minimum functionality / webview wrapper). Symptom: the app is a WKWebView pointed at a URL.
Fix: add native capabilities the web cannot provide (push notifications, offline caching, camera, Core Location, home screen widgets), and give a genuinely app-like experience.
Guideline 4.3 (spam / duplicate). Symptom: multiple near-identical apps, or an app that looks like a template.
Fix: consolidate into a single app with configuration, and add original design and content.
Guideline 2.3 (inaccurate metadata). Symptom: screenshots show features not in the build, or mention other platforms or prices.
Fix: use current-device screenshots captured from the actual app, remove platform references and pricing overlays, and keep the description truthful.
6. Code signing and entitlements
Entitlements live in a .entitlements file linked to the target. Only include capabilities you actually use, and enable the matching capability in App Store Connect / the Developer portal so the provisioning profile includes it.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>aps-environment</key>
<string>production</string>
<key>com.apple.developer.icloud-container-identifiers</key>
<array>
<string>iCloud.com.yourcompany.swiftship</string>
</array>
<key>com.apple.developer.icloud-services</key>
<array>
<string>CloudKit</string>
</array>
<key>com.apple.developer.ubiquity-kvstore-identifier</key>
<string>$(TeamIdentifierPrefix)$(CFBundleIdentifier)</string>
<key>com.apple.developer.healthkit</key>
com.apple.developer.healthkit.access
com.apple.developer.applesignin
Default
Archive, validate, distribute (Xcode):
- Set the scheme to a Generic iOS Device or a connected device (not a simulator).
- Bump
CFBundleShortVersionString (marketing version) and CFBundleVersion (build number). Build number must increase for every upload.
- Product menu, then Archive.
- In the Organizer, select the archive, then Validate App to catch signing and asset issues early.
- Distribute App, then App Store Connect, then Upload.
- Let the build finish processing in App Store Connect (a few minutes to an hour), then attach it to the version.
Prefer automatically managed signing for most apps. Use a distribution certificate and an App Store provisioning profile that includes every entitlement you declared.
7. Subscription setup (StoreKit)
Full guide in templates/subscription-setup.md. Essentials:
- Product ID naming. Use reverse-DNS, stable, and descriptive IDs, for example
com.yourcompany.swiftship.pro.monthly and com.yourcompany.swiftship.pro.yearly. IDs cannot be reused once created.
- Subscription group. Put related tiers (monthly, yearly) in one subscription group so users can upgrade, downgrade, and cross-grade. Only one active subscription per group.
- Required pre-purchase disclosure. On the paywall you MUST show, before purchase: the subscription title, the exact price and billing period, that it auto-renews until cancelled, how to cancel, and tappable links to your Terms of Use (EULA) and Privacy Policy. Missing any of these is a 3.1.2 rejection.
Minimal StoreKit 2 purchase flow:
import StoreKit
func purchase(_ product: Product) async throws {
let result = try await product.purchase()
switch result {
case .success(let verification):
let transaction = try checkVerified(verification)
await unlockFeatures(for: transaction.productID)
await transaction.finish()
case .userCancelled, .pending:
break
@unknown default:
break
}
}
func checkVerified<T>(_ result: VerificationResult<T>) throws -> T {
switch result {
case .unverified:
throw StoreError.failedVerification
case .verified(let safe):
return safe
}
}
Always provide a working "Restore Purchases" action (call AppStore.sync() or rely on Transaction.currentEntitlements).
8. ASO best practices
Full checklist in checklists/aso-checklist.md. Budgets and strategy:
- App Name (30). Brand plus one or two high-value keywords, for example "SwiftShip: App Store Deploy".
- Subtitle (30). A distinct value proposition with different keywords than the name. Both name and subtitle are indexed and weighted heavily.
- Keywords (100). Comma-separated, no spaces. Do not repeat words already in the name or subtitle. Do not use competitor trademarks. Use singulars (Apple handles plurals). Do not waste characters on "app" or your category name.
- Description (4000). The description is not indexed for keywords, so write for humans. Front-load the value in the first two lines because the rest is hidden behind "more".
- Promotional Text (170). Editable without a new build. Use it for timely messages (a sale, a new feature).
Never keyword-stuff, never use irrelevant keywords, and never reference competitor names. These trigger 2.3 or 4.3 rejections.
9. Age rating
App Store Connect uses a questionnaire that produces an age rating. As of July 2025, Apple expanded the tiers from 4+, 9+, 12+, 17+ to a more granular set: 4+, 9+, 13+, 16+, and 18+. Existing apps were remapped and should be reviewed.
The questionnaire asks you to declare the frequency (None, Infrequent/Mild, Frequent/Intense) of categories including:
- Cartoon or fantasy violence
- Realistic violence
- Sexual content or nudity
- Profanity or crude humor
- Alcohol, tobacco, or drug use or references
- Simulated gambling
- Horror or fear themes
- Mature or suggestive themes
- Medical or treatment information
- Contests
Newer questions also ask whether the app includes user-generated content, messaging, or in-app controls (such as parental controls or content moderation), which can raise or clarify the rating. Answer honestly. Under-declaring to reach a lower rating is a rejection and can lead to removal. If the app is gambling, contains unrestricted web access, or has mature UGC, expect 17+/18+.
10. Submission workflow (step by step)
- Finalize the build: bump marketing version and build number, confirm the privacy manifest and entitlements.
- Archive in Xcode (Product, then Archive) against a device destination.
- Validate the archive in the Organizer, fix any errors.
- Distribute App, then upload to App Store Connect.
- In App Store Connect, create the app record if new (set Bundle ID, SKU, primary language).
- Fill all metadata fields within their limits (section 3).
- Upload screenshots for each required device size, and app previews if any.
- Complete the Age Rating questionnaire (section 9).
- Set pricing and availability. Configure in-app purchases or subscriptions and submit them with the build if it is the first time.
- Complete App Privacy (nutrition labels) so they match the privacy manifest.
- Fill App Review Information: demo account, contact details, and Notes (use
templates/review-notes-template.md).
- Attach the processed build to the version.
- Set the release option (automatic, manual, or scheduled) and choose phased release if desired.
- Optionally test with TestFlight (internal testers need no review; external testers need a lightweight Beta App Review) before submitting.
- Click Add for Review, then Submit for Review.
- Monitor status. If rejected, read the Resolution Center message, map it to the exact guideline (section 5), apply the concrete fix, and reply or resubmit.
Guardrails for the agent
- Give the specific guideline number and the concrete fix, never vague warnings.
- Enforce exact character limits when drafting metadata.
- Keep the privacy manifest, nutrition labels, and usage strings mutually consistent with real behavior.
- Confirm digital purchases use StoreKit before approving any external payment link.
- Verify accessibility (VoiceOver, Dynamic Type, Dark Mode) is addressed, not assumed.