Claude
Skills
Sign in
Back

app-store-preflight-skills

Included with Lifetime
$97 forever

```markdown

Writing & Docs

What this skill does

```markdown
---
name: app-store-preflight-skills
description: AI agent skill for scanning iOS/macOS projects to catch App Store rejection patterns before submission
triggers:
  - check my app for App Store rejection
  - run preflight checks before App Store submission
  - scan my iOS project for review guideline violations
  - preflight my Xcode project for App Store
  - catch App Store rejection issues
  - validate my app metadata for submission
  - check for Apple review guideline violations
  - pre-submission scan for iOS app
---

# App Store Preflight Skills

> Skill by [ara.so](https://ara.so) — Daily 2026 Skills collection.

An AI agent skill that runs pre-submission checks on iOS/macOS projects to catch common App Store rejection patterns before you submit to Apple Review.

## What This Skill Does

App Store Preflight scans your:
- **Xcode project files** — entitlements, capabilities, configuration
- **Source code** — Sign in with Apple usage, privacy manifest, data collection
- **App metadata** — descriptions, keywords, screenshots, preview videos
- **Subscription/IAP setup** — ToS links, pricing display, EULA presence
- **Privacy configuration** — `PrivacyInfo.xcprivacy`, unnecessary data requests

It maps findings to specific Apple Review Guidelines, assigns severity (`REJECTION` or `WARNING`), and provides resolution steps.

## Install

```bash
npx skills add truongduy2611/app-store-preflight-skills
```

This installs the skill so AI coding agents (Claude Code, Cursor, Codex, etc.) can use it automatically when you ask about App Store submission readiness.

## Prerequisites

Install the `asc` CLI for metadata pulling:

```bash
brew install asc
```

Set up App Store Connect API credentials:

```bash
export ASC_KEY_ID="your_key_id"
export ASC_ISSUER_ID="your_issuer_id"
export ASC_PRIVATE_KEY_PATH="/path/to/AuthKey_XXXXXXXX.p8"
```

## Core Workflow

### 1. Identify Your App Type

Choose the matching checklist from `references/guidelines/by-app-type/`:

| App Type | Checklist File |
|----------|---------------|
| All apps (universal) | `all_apps.md` |
| Subscriptions / IAP | `subscription_iap.md` |
| Social / UGC | `social_ugc.md` |
| Kids Category | `kids.md` |
| Health & Fitness | `health_fitness.md` |
| Games | `games.md` |
| macOS / Mac App Store | `macos.md` |
| AI / Generative AI | `ai_apps.md` |
| Crypto / Finance | `crypto_finance.md` |
| VPN / Networking | `vpn.md` |

### 2. Pull App Metadata

```bash
# Pull metadata for a specific app and version
asc metadata pull --app "1234567890" --version "2.1.0" --dir ./metadata

# Or use the asc-metadata-sync skill
npx skills add rudrankriyam/app-store-connect-cli-skills
```

After pulling, your metadata directory structure will look like:

```
./metadata/
  en-US/
    description.txt
    keywords.txt
    release_notes.txt
    promotional_text.txt
  metadata.json
  screenshots/
  app_previews/
```

### 3. Run Preflight Scan

Ask your AI agent to run preflight checks:

```
"Check my iOS project at ./MyApp.xcodeproj for App Store rejection patterns"
"Run preflight scan on my subscription app before I submit version 2.1.0"
"Scan my metadata folder and Xcode project for App Store guideline violations"
```

## Rejection Rules Reference

All rules live in `references/rules/` organized by category.

### Metadata Rules (`references/rules/metadata/`)

**competitor_terms** — Guideline 2.3.1
```
REJECTS: Description or keywords containing "Android", "Google Play", 
         "Samsung", "Windows" or other competitor brand references
CHECK:   metadata/en-US/description.txt
         metadata/en-US/keywords.txt
         metadata/en-US/promotional_text.txt
```

**apple_trademark** — Guideline 5.2.5
```
REJECTS: App icon containing device frames (iPhone bezels, MacBook outline)
         Misuse of "Apple", "iPhone", "iPad" in app name or description
CHECK:   AppIcon.appiconset/
         metadata/en-US/description.txt
```

**china_storefront** — Guideline 5
```
REJECTS: References to OpenAI, ChatGPT, Gemini in China storefront metadata
CHECK:   metadata/zh-Hans/description.txt (China-specific locale)
```

**accurate_metadata** — Guideline 2.3.4
```
REJECTS: App preview videos containing device frames/bezels
         Screenshots that misrepresent actual app UI
CHECK:   metadata/app_previews/
```

**subscription_metadata** — Guideline 3.1.2
```
REJECTS: Subscription app missing ToS/EULA URL in metadata
         Missing Privacy Policy URL
CHECK:   metadata.json → "licenseAgreementUrl"
         metadata.json → "privacyPolicyUrl"
```

### Subscription Rules (`references/rules/subscription/`)

**missing_tos_pp** — Guideline 3.1.2

Check `metadata.json` for required URLs:
```json
{
  "privacyPolicyUrl": "https://yourapp.com/privacy",
  "licenseAgreementUrl": "https://yourapp.com/terms"
}
```

Also verify in-app presentation:
```swift
// ✅ Required: Show links before purchase
Button("Subscribe - $9.99/month") { }
Link("Terms of Service", destination: URL(string: "https://yourapp.com/terms")!)
Link("Privacy Policy", destination: URL(string: "https://yourapp.com/privacy")!)
```

**misleading_pricing** — Guideline 3.1.2
```swift
// ❌ REJECTION: Monthly price more prominent than actual billing
Text("Only $2.99/month")        // Large, prominent
Text("Billed $35.99 annually")  // Small, hidden

// ✅ CORRECT: Annual price equally or more prominent
Text("$35.99/year")
Text("($2.99/month)")
```

### Privacy Rules (`references/rules/privacy/`)

**privacy_manifest** — Guideline 5.1.1

Check for `PrivacyInfo.xcprivacy` in your project:
```bash
find . -name "PrivacyInfo.xcprivacy" -not -path "*/node_modules/*"
```

Required file structure:
```xml
<!-- MyApp/PrivacyInfo.xcprivacy -->
<?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/>
  <key>NSPrivacyAccessedAPITypes</key>
  <array>
    <!-- Required if using UserDefaults -->
    <dict>
      <key>NSPrivacyAccessedAPIType</key>
      <string>NSPrivacyAccessedAPICategoryUserDefaults</string>
      <key>NSPrivacyAccessedAPITypeReasons</key>
      <array>
        <string>CA92.1</string>
      </array>
    </dict>
  </array>
</dict>
</plist>
```

**unnecessary_data** — Guideline 5.1.1
```swift
// ❌ REJECTION: Requiring irrelevant personal data at signup
struct SignUpView: View {
    @State var birthdate: Date      // Not needed for your app type
    @State var phoneNumber: String  // Not needed for your app type
    @State var address: String      // Not needed for your app type
}

// ✅ CORRECT: Only collect what your app genuinely needs
struct SignUpView: View {
    @State var email: String
    @State var password: String
    // Request additional data only when feature requires it
}
```

### Design Rules (`references/rules/design/`)

**sign_in_with_apple** — Guideline 4.0
```swift
// ❌ REJECTION: Asking for name/email AFTER Sign in with Apple completes
func authorizationController(
    controller: ASAuthorizationController,
    didCompleteWithAuthorization authorization: ASAuthorization
) {
    // DON'T show a form asking for name or email here
    // Apple already provided it — use credential.fullName and credential.email
    if let credential = authorization.credential as? ASAuthorizationAppleIDCredential {
        let name = credential.fullName      // ✅ Use this
        let email = credential.email        // ✅ Use this
        // ❌ Don't: showAdditionalInfoForm()
    }
}
```

**minimum_functionality** — Guideline 4.2
```
REJECTS: App is a pure WebView wrapper with no native functionality
         App has fewer than 3 distinct screens/features
         App provides no unique value over mobile browser
         App is a template/demo with placeholder content

SIGNALS TO CHECK:
- WKWebView loading a single URL as the entire

Related in Writing & Docs