Gitrex Technologies
React NativeApp StoreExpo

Getting a React Native app through App Store review the first time

The rejections we see most on React Native and Expo submissions, the guideline numbers behind them, and the checklist we run before pressing Submit so review takes days, not weeks.

· Founder, Gitrex Technologies

4 min read

App review is not a code review. Nobody at Apple is reading your React Native components. They install the build on a device, tap around for a few minutes, and check it against a list. Almost every first-time rejection I've seen came from that list, not from the code, and almost all of them were avoidable with an hour of preparation.

These are the rejections that show up again and again, with the guideline numbers so you can recognise them in the review notes.

Guideline 2.1: "We were unable to sign in"

The single most common one. The app needs an account to do anything, the reviewer doesn't have one, and they're not going to create one with their own details.

Give them a demo account in App Review Information, under Sign-in required, and make sure that account has data in it. An empty dashboard reads as a broken app. If sign-in uses a one-time code sent by SMS, the reviewer can't receive it; either give them a fixed code in the notes or add a review bypass for that specific account.

Also under 2.1: the app crashes on launch on the reviewer's device. Nine times out of ten this is an environment variable that exists in your EAS build profile for development but not production. Install the exact build you're submitting on a physical device with a fresh install before you submit it. Not the simulator. Not a build from yesterday.

Guideline 4.2: "Your app provides a limited user experience"

The web-wrapper rejection. If the app is a WebView around your website, Apple will notice and say no. React Native apps don't usually trip this, but "React Native app" sometimes means a native shell with a single WebView pointing at a Lovable-built site, and that gets caught.

The fix is real native screens for the core flow. It doesn't have to be everything. It has to be enough that the app does something the website in Safari can't.

Guideline 5.1.1(v): account deletion

Since 2022, if users can create an account in the app, they must be able to delete it in the app. Not by emailing support. Not by visiting the website. A button, in the app, that deletes the account and the data behind it.

This one catches teams that built auth with Supabase or Firebase and never wrote the deletion path. On Supabase it means a server-side function that removes the user's rows and then calls auth.admin.deleteUser, because the client can't delete its own auth record. Budget half a day.

Guideline 5.1.1 and the privacy labels

The App Privacy section in App Store Connect asks what data you collect. Teams guess. Then the reviewer sees the app request location and the label says "no data collected", and back it comes.

Fill the labels in from the code, not from memory. Every SDK you added has a documented answer: analytics, crash reporting, push notifications, ads. And the permission prompt strings in Info.plist (or app.json infoPlist on Expo) have to say why you want the permission, in a sentence a human would accept. "This app needs camera access" gets rejected. "Take a photo of your receipt to add it to your expenses" doesn't.

Guideline 4.8: Sign in with Apple

If you offer Google or Facebook login, you must also offer Sign in with Apple. Expo's expo-apple-authentication makes the client side a morning's work; the part people skip is handling the fact that Apple only sends the user's name and email on the first sign-in. Store them then or you'll never see them again.

Guideline 3.1.1: in-app purchase

If users pay for digital features, they pay through Apple's in-app purchase, not through a Stripe checkout in a WebView. Physical goods and services consumed outside the app can use Stripe. A "Pro" subscription that unlocks features in the app cannot. RevenueCat is the shortest path to doing this properly on React Native and it's what we reach for.

The checklist we run before submitting

  • The exact production build installed fresh on a physical iPhone and a physical Android phone, launched, signed in, core flow completed.
  • A demo account with realistic data, credentials in the review notes, any OTP bypass explained.
  • Account deletion works end to end and the button is findable from settings.
  • Every permission string explains the reason in plain language.
  • Privacy labels match the SDK list in package.json.
  • Sign in with Apple present if any third-party login is.
  • Privacy policy URL and support URL both load and both mention the app by name.
  • Screenshots are from the current build. Reviewers do compare.
  • On the Play side: the Data safety form filled from the same SDK list, and, for a new personal developer account, the closed test with real testers that Google requires before production access. Start that early; it takes weeks of calendar time, not effort.

Run TestFlight with a few real people for a week before the first submission. Not for the feedback, although that helps. For the crash reports on devices and iOS versions you don't own.

When it still gets rejected

Reply in Resolution Center, politely, with what you changed, and resubmit. Reviews of resubmissions are usually faster. If you think the rejection is wrong, say why and cite the guideline; I've had 4.2 rejections reversed by walking the reviewer through the native-only features they missed. If it's a judgement call, don't argue, change the thing.

Store submission is included in every React Native build we do, and it's the part clients are most relieved to hand over. Not because it's hard. Because it's a list, and lists are only easy once you've been through them.

Wajahat Shaw, founder of Gitrex Technologies

Wajahat Shaw

Founder of Gitrex Technologies. Senior engineer; builds and rescues software for founders, most of it React Native, Next.js and Supabase. Writes here about what actually breaks and how to check for it. More about Gitrex

Keep reading
ReplitMigrationVercel

Moving a Replit app onto your own stack without breaking it

Replit Agent apps are more portable than people fear. The order of operations we use to move one to your own repo, Postgres and hosting: what to swap, what to keep, and how to cut over with a rollback.

4 min read