Most app rejections don't come from anything complicated.
They come from things that were easy to fix but nobody checked before hitting Submit.
The App Store review team and Google Play's automated systems are looking for a small, predictable set of problems. Teams that catch these before submission move through review cleanly. Teams that don't end up in a back-and-forth that adds days or weeks to their launch.
Here are the five things that matter most — in the order you should do them.
1. Test the App on a Real Physical Device
Not a simulator. Not a browser preview. A real phone.
Simulators lie. They have reliable network connections, consistent performance, and none of the quirks of actual hardware. A build that runs perfectly in a simulator can behave completely differently on a physical device with a spotty connection, limited RAM, or a different OS version.
App Store reviewers use real devices. Google Play's automated checks run on real hardware configurations. If your app crashes on launch, freezes during onboarding, or produces a blank screen when a network request fails, the review ends there.
Test the main user flow from a clean install — not from a state where you've already logged in and set everything up, but from the very first screen a new user sees. That's what the reviewer sees.
Also test with airplane mode on. If your app has no graceful handling for lost connectivity, you'll find out now rather than from a rejection email.
2. Audit Every Permission Your App Requests
Open your app's permission manifest and read every entry.
For each permission, ask two questions: does the app actually use this? And can I explain clearly why a user would agree to grant it?
AI-generated and no-code apps often inherit permissions from templates or third-party components that aren't being used in the final product. A camera permission from an image picker library that was never integrated. A location permission from a map SDK that got removed. These stay in the manifest unless someone explicitly removes them.
Both Apple and Google will flag permissions that have no justification. And if your Data Safety form or Privacy Nutrition Label doesn't mention a permission your code requests, you have a contradiction that will trigger rejection.
Remove every permission you don't use. For the ones you keep, write one sentence explaining why the app needs it and when it asks for it. That sentence becomes your Data Safety form answer.
3. Make Sure Your Privacy Policy Is Live and Accurate
Both platforms require a valid privacy policy URL before you can submit. This is not optional.
The policy needs to be publicly accessible — not behind a login, not on a page that redirects, not a placeholder that says "coming soon." It needs to load in an incognito browser window with no issues.
And it needs to be accurate. A policy that says "we don't collect any personal data" while your app requires email login and uses analytics is a contradiction. A policy written for a website but that doesn't mention mobile apps is incomplete.
Cover the basics clearly: what you collect, why you collect it, how long you keep it, whether you share it with third parties, and how users can request deletion. Apps that collect data from children have additional requirements under COPPA (US) and similar regulations elsewhere.
4. Update Your Screenshots and Store Listing to Match the Current Build
This is the most common and most avoidable cause of rejection.
Screenshots taken during development show an earlier version of the app. Descriptions written during planning describe features that changed. If your listing shows a UI that doesn't match what the reviewer sees when they open the build, that's misleading metadata — and it's a rejection.
The rule is simple: write the description and take the screenshots after the build is locked. Not before. Not during. After.
Read each sentence of your description and ask: can a reviewer test this right now in this build? If the answer is no, remove it or rewrite it. Only describe what exists.
| Common Listing Mistake | What to Do Instead |
|---|---|
| Screenshots from an earlier UI version | Retake screenshots on the final build, same day you submit |
| Description mentions unreleased features | Remove any feature not in the current build — add it when it ships |
| Title uses generic superlatives | Describe specifically what the app does — avoid 'best', 'ultimate', '#1' |
| Support URL goes to a 404 page | Test every link in the listing from an incognito window |
| Keywords stuffed into the description | Write for humans — stores penalize obvious keyword stuffing |
5. Check Your In-App Purchase and Subscription Flow
If your app has any form of paid feature, subscription, or premium tier, the payment flow gets scrutinized carefully by both platforms.
For Apple: all digital goods and subscriptions must use Apple's in-app purchase system. No exceptions. Linking to a web page to complete a purchase for digital content is a violation. The price, billing period, and what the user gets must be clearly displayed before they confirm.
For Google Play: same principle. Digital content purchases must go through Google Play Billing. Subscriptions need a clear restore mechanism, visible from within the app.
The most common mistakes here are offering a web payment option for digital content, not displaying subscription terms clearly before the purchase confirmation, and not providing a working restore purchases button for iOS.
Test the full payment flow yourself before submission. Complete a test purchase. Cancel a test subscription. Confirm that the restore function works. If anything in that flow is broken, it will come back as a rejection.
The Underlying Pattern
All five of these checks share something in common: they're about making sure what you claim about your app matches what a reviewer will actually find.
A stable build. Honest permissions. A real privacy policy. A listing that reflects the current product. A payment flow that follows the rules.
When those five things are true, most apps clear review on the first submission. When any of them isn't, you're in the rejection loop.
