I've shipped enough iOS apps at this point to notice a pattern in App Store rejections. The app almost never gets rejected because something is broken. It gets rejected because of something in the metadata.
Three examples I keep running into.
Missing or vague privacy details. Since iOS 17, Apple checks your PrivacyInfo.xcprivacy manifest against the actual APIs your app, and any third party SDKs, actually touch. If you use UserDefaults, a disk space check, or a system boot time call and haven't declared the matching required reason API category, review flags it. This has nothing to do with whether your app crashes. It's a paperwork mismatch.
A screenshot that doesn't match the app's actual UI. Reviewers compare your submitted screenshots against what the build actually shows on first launch. Redesign a screen and forget to update one screenshot, and you get a Guideline 2.3.3 rejection with zero code changes needed, just new screenshots.
An unclear permission usage string. "This app needs your location" gets rejected under Guideline 5.1.1 for being too vague. Apple wants the specific reason, something like "used to show nearby stores." Again, zero code involved, just a string in Info.plist.
The pattern holds across all three. Read the specific line in the rejection message before assuming something's fundamentally broken. Apple's rejection emails usually name the exact guideline number and the exact issue. It's tempting to panic and start debugging your build. Most of the time the fix is a sentence of text or a missing manifest entry, not an afternoon in Xcode.
I built a pipeline called Macless, macless.dev, that ships iOS apps to TestFlight and the App Store without owning a Mac, using GitHub Actions macOS runners for the build, sign, and upload. None of that touches the metadata side of review though. That part's still on you regardless of what builds your app. Worth knowing the difference before you start debugging the wrong thing.
Top comments (0)