Pass App Review
Run the store check, fix what it flags, fill in the metadata, and submit to the App Store and Google Play without burning a review cycle.
Hey - by the end of this page you'll have a build that passed bun run doctor --store, a
report from the store-review skill with every finding tied to a guideline id, and the store
metadata filled in from that report. Then you submit.
Nobody can promise approval - reviewers are people and the guidelines move. What this page does is take the rejections that are predictable off the table before you wait a week to hear about them.
1. Run the check ✅
From your app's root:
bun run doctor --storeIt reads readynative.config.ts, app.config.ts, .readynative.json and your package.json, and
prints one finding per problem - blocking, warning or info - with its id, platform, guideline
citation, the file and line, and the fix:
Store review check
Blocking - fix before you submit (1)
✗ Missing usage string for expo-location [ios-usage-string-missing · ios · App Store Review 5.1.1(i)]
app.config.ts:41
expo-location is installed but ios.infoPlist has no NSLocationWhenInUseUsageDescription
fix: Add the "expo-location" config plugin to plugins (with its *Permission prop) or set ios.infoPlist.NSLocationWhenInUseUsageDescription.It also prints a Data safety draft - one row per SDK you selected, with what it collects and the vendor's disclosure page. Keep that output open; you'll paste from it in step 3.
In a Starter tree the command prints that the check is part of Pro and exits.
2. Fix the blocks
Work top to bottom. The findings that come up most:
- Account deletion (App Store Review 5.1.1(v), Play Account deletion) - if you picked any
auth option, users can create an account, so the app has to let them
delete it from inside the app. The finding points at the settings screen; wire a "Delete
account" row to
deleteAccount()insrc/lib/auth.ts, and if you offer Sign in with Apple, revoke the token server-side. - Sign in with Apple (App Store Review 4.8) - a Google or other social button on the sign-in screen means Apple's button has to be there too, with the same prominence.
- Paywall copy (App Store Review 3.1.2(c), Play Subscriptions) - price, billing period and
renewal terms on the paywall itself, plus a Restore Purchases action. The
payments module ships these; the finding fires if you removed one
or if
urls.terms/urls.privacyinreadynative.config.tsare still empty. - Digital goods through in-app purchase (App Store Review 3.1.1, Play Payments policy) - subscriptions or unlocks used inside the app must be sold through StoreKit / Play Billing (the RevenueCat or Adapty option). Stripe Checkout alone is fine for physical goods and services; for digital Pro it is allowed as a link-out on the US App Store storefront, and elsewhere only with Apple's external purchase entitlement. Offering both rails, as the Snap Recipe example does, is the safe shape.
- Purpose strings (App Store Review 5.1.1(ii)) - every permission-bearing dependency needs its
NS*UsageDescriptioninapp.config.ts, and the string names the feature, not the permission. - Tracking (App Store Review 5.1.2(i)) - analytics or ads SDKs that link your data with other
companies' data need the App Tracking Transparency prompt. The analytics modules ship
expo-tracking-transparencywith a purpose string; setfeatures.tracking: trueinreadynative.config.tsandapp.config.tsadds its plugin andNSPrivacyTracking: true, andAnalyticsProviderasks once the app is active, withanalytics.identifywaiting for consent. Off (the default), Android'sAD_IDpermission is blocked anddoctor --storereminds you to answer "No" to tracking in App Store Connect. - Privacy manifest (ITMS-91053) - setup composes
ios.privacyManifestsfrom the selected modules' declarations; the finding fires if it is missing or declares tracking whilefeatures.trackingis off. The Privacy and consent page has the full picture. - Placeholders -
com.acme.app, an emptyurls.support, the default app name. Reviewers read them as an unfinished app (App Store Review 2.1(a)). Config lists every field.
Re-run the command until it is green.
3. Fill in the metadata 📋
The stores ask for things no file in your tree can prove. Go through these in App Store Connect and the Play Console before you upload:
- Screenshots that show the app in use - not the splash or sign-in screen - for every device
class you support: iPhone, iPad if
supportsTabletis on, phone plus 7" and 10" tablets on Play. - The age rating questionnaire, answered from what the app actually contains.
- Export compliance:
ITSAppUsesNonExemptEncryptioninapp.config.tsmatches your answer. - A demo account in the App Review notes when anything sits behind sign-in, and a backend that stays up while the reviewer is in.
- The Data safety form on Play and the App Privacy answers in App Store Connect, filled from
the draft table
doctor --storeprinted - every SDK in.readynative.jsonaccounted for. - A privacy policy URL and a support URL that are live, public and reachable from Settings.
- On Play, the account-deletion web link in the Data safety form.
The draft table is a starting point, not an answer
doctor --store knows which SDKs you selected and what their vendors say they collect. It does
not know what your own backend stores. Add your own data types before you submit the form - an
inaccurate Data safety form gets updates blocked.
4. Run the skill with your agent 🤖
The mechanical check cannot judge copy, flows, or whether a permission prompt reads as a
reason. That is the store-review skill. In Claude Code, Cursor
or any agent that reads .agents/skills/:
Run the store-review skill on this app and give me the report.It runs doctor --store, reads the paywall, onboarding, sign-in and settings screens against
the distilled App Store and Play checklists, optionally screenshots them on the simulator, and
returns a table of findings - likely rejection, fix before submit, fine - each with the
guideline id and file:line. Fix the first two groups, then ask it to run again.
5. Submit
Build and submit the way Ship to TestFlight set up:
bunx eas-cli build --profile production --platform all
bunx eas-cli submit --platform allPaste the demo account and a specific description of what is new into the review notes (App Store Review 2.3.1 rejects generic ones), then submit for review.
Congrats 🎉
You submitted with every predictable rejection already handled and a report you can hand to whoever asks why a screen looks the way it does. If a reviewer still comes back with something, the reply cites the guideline they name - run the skill again with their message and it will tell you which finding it maps to. Next: keep users current without another review with Your first update.