Flutter App Store Rejection Checklist (2026): 15 Checks Before You Submit
Roughly 23% of App Store submissions get rejected on the first pass. Most of those rejections are not about your app's idea, its design, or its code quality — they are mechanical, checklist-style issues that are easy to miss when you are racing to ship. A missing usage description. A debug flag left on. A crash reporting SDK that is installed but never initialized.
This is a Flutter-specific checklist of 15 checks that commonly cause App Store or Play Store rejections (or silent breakage after launch). You can run through it manually in an hour, or run an automated Launch Score scan that checks all 15 in a few minutes by uploading your project zip.
Why Flutter apps get rejected more than you'd expect
Flutter compiles to a native binary on each platform, which means your iOS and Android configuration still has to satisfy each store separately — even though your Dart code is shared. The rejections cluster in three places: secrets and config hygiene, iOS-specific declarations, and SDK wiring (auth, analytics, monetization, crash reporting).
None of these require deep debugging. Most are a few minutes of work once you know they are there. The hard part is knowing to look before Apple or Google tells you.
The 15 checks
1. pubspec.yaml present and valid
Seems obvious, but a malformed pubspec.yaml — broken YAML, a dependency with no version constraint, a missing environment SDK constraint — will fail a release build or produce inconsistent builds across CI and local machines. Validate the file parses and that the SDK constraint matches the Flutter version you ship with.
2. .gitignore present
A missing or thin .gitignore is the root cause behind several other checks on this list (committed secrets, Firebase config, keystores). A baseline Flutter .gitignore should cover build outputs, .env, signing files, and platform config that should never be committed.
3. Secret paths gitignored
Your .gitignore must cover .env, signing keystores (*.jks, *.keystore), and service-account JSON. If any of these are not gitignored before your first commit, they end up in git history — and deleting the file later does not remove it from history. The only real fix once leaked is key rotation.
4. Firebase client config gitignored
google-services.json (Android) and GoogleService-Info.plist (iOS) are not secret by design, but an ungitignored one combined with other exposed config can add up to more access than you intended. They belong in .gitignore, injected at build time or via CI, not committed.
5. No hard-coded secrets in source
This is the check that catches more apps than expected. API keys pasted directly into lib/main.dart or a constants file as plain strings are readable by anyone who decompiles your APK or IPA. Move runtime secrets to environment config and never commit real keys. If the repo is ever public, the key is already gone.
6. No unpinned git dependencies
A git dependency pointed at a branch (not a tag or commit) can change your build without warning. A maintainer pushes to main and your next clean build behaves differently. Pin git dependencies to a tagged version or a specific commit, especially before submission when you want reproducibility.
7. android:debuggable not left enabled in release
android:debuggable="true" in your release manifest ships debug hooks into your production APK. It is often copied in by accident from a debug configuration or a pasted manifest entry. Play Store does not always catch it — and that is not safe to rely on. Confirm your release build variant sets it to false.
8. Android INTERNET permission present (if you make network calls)
If your app calls an API and the INTERNET permission is not declared, the calls fail silently in release (they work in debug on some setups). The inverse is also a problem: declaring permissions you do not use invites review questions. Match declared permissions to actual usage.
9. iOS usage descriptions non-empty for every permission
If you request camera, location, photo, microphone, or any other protected access, Info.plist needs a real, specific usage description string for each — not blank, not generic ("App needs this to function"). Write one sentence per permission explaining why you need it. This is one of the most common App Store rejection causes.
10. iOS App Transport Security enabled (no blanket bypass)
NSAllowsArbitraryLoads set to true disables App Transport Security app-wide, allowing insecure connections. App Review will ask why you are allowing arbitrary cleartext traffic. If you need an exception for a specific legacy domain, scope it to that domain rather than blanket-disabling ATS.
11. iOS export compliance declared
Missing ITSAppUsesNonExemptEncryption stalls your submission with an encryption questionnaire you did not expect at upload time. Most apps qualify for an exemption (standard HTTPS/TLS) but still need to declare it explicitly in Info.plist. One key, one line, prevents a manual review detour.
12. Auth backend configured correctly (if the app has accounts)
If your app has login, accounts, or any authenticated flow, the auth backend must be configured for production — real provider credentials, correct redirect URIs, working email confirmation. A common failure: auth works in dev against a local or test provider, then breaks in production because the live configuration was never wired. Verify sign-in and account deletion end-to-end in a release build.
13. Analytics SDK configured (if you track events)
If the app tracks events, the analytics SDK must be initialized and reporting — not just installed. The same "installed but not initialized" trap that hits crash reporting (check 15) hits analytics. Confirm events actually arrive at your dashboard from a release build before you ship.
14. Monetization SDK configured correctly (if you sell anything)
If the app sells anything, the monetization SDK (RevenueCat or in_app_purchase) must be wired with correct product identifiers, a working restore-purchases flow, and entitlement handling. Test a real purchase and a restore in sandbox before submission — store reviewers check that purchase and restore work.
15. Crash reporting installed and initialized before runApp
The most common "looks done, isn't" finding: the crash reporting SDK (Sentry or Firebase Crashlytics) is in pubspec.yaml but runApp() was never wrapped in the init call. The SDK sits there capturing nothing, and you find out only when a real crash goes unreported in production. Initialize before runApp, not after.
Automatic vs. manual
You can run this checklist manually in about an hour — open each file, check each value, test each flow. Or you can upload your Flutter project as a zip to ShipForge's free Launch Score tool and get all 15 checks run automatically, with a Launch Score (0–100) and a downloadable report explaining each finding and the specific fix. The free tier requires no card.
The automated scan catches the mechanical, pattern-matchable issues fast — secrets in source, gitignore gaps, config flags, SDK init. What it does not replace is human judgment on App Review guideline edge cases specific to your app's category. Use both: run the scan to clear the mechanical rejections, then review the guideline edge cases yourself.
Run your scan
If you are about to submit a Flutter app, run a free Launch Score scan first — it takes a few minutes and catches the 15 checks above before a reviewer does.
Frequently asked questions
What are the most common reasons Flutter apps get rejected from the App Store?
The most common App Store rejections for Flutter apps are missing iOS usage descriptions (NSCameraUsageDescription, NSPhotoLibraryUsageDescription), hardcoded API keys in client code, missing Sign in with Apple, no account deletion flow, and crash reporting SDKs that are installed but never initialized before runApp().
How long does App Store review take in 2026?
App Store review typically takes 24-48 hours for most apps, but can take up to 7-10 days during busy periods or if your app triggers manual review. Apps with in-app purchases, subscriptions, or sensitive content may take longer.
Can I check my Flutter app for rejection risks before submitting?
Yes. You can run a free Launch Score check at shipforgeai.dev/free-tools/launch-score that scans your project for 15 common rejection causes including secrets in code, missing usage descriptions, and uninitialized SDKs.