All articles
Mobile DevelopmentJune 27, 2026 7 min read

App Store Review Rejections in React Native: The 2026 Pattern We Keep Seeing

Apple and Google have quietly tightened review in 2026. Here are the React Native and Expo rejection patterns we keep hitting on client projects, and how to ship past them without rewriting your app.

Every quarter we put a handful of React Native and Expo apps through App Store and Play Store review, and every quarter the rejection reasons shift. 2026 has been particularly noisy: Apple's review notes are shorter and more automated, Google has gone aggressive on data safety and foreground service declarations, and both stores are quietly punishing the lazy defaults that come with cross-platform tooling.

This is the pattern we keep seeing, ordered by how often it bites our clients.

The metadata mismatch trap

The single most common rejection we've handled in 2026 isn't a code issue at all — it's a mismatch between what your binary declares and what your store listing says.

React Native and Expo apps tend to accumulate native modules over time. Each module quietly adds an entitlement, a permission, or a usage description string. Six months later you remove the feature from your UI but the module — and its declarations — stay in the binary. The reviewer's tooling flags the discrepancy faster than ever.

iOS: usage strings that promise features you removed

Open your Info.plist (or app.json ios.infoPlist block in Expo) and audit every NS*UsageDescription. If you have NSCameraUsageDescription but your app no longer uses the camera anywhere, Apple's reviewer will either reject you under Guideline 5.1.1 or — more commonly in 2026 — send a metadata rejection asking you to justify it.

{
  "expo": {
    "ios": {
      "infoPlist": {
        "NSCameraUsageDescription": "Scan receipts to attach to expense reports.",
        "NSPhotoLibraryUsageDescription": "Pick a profile photo."
      }
    }
  }
}

The rule we apply: every usage string must name a specific, user-visible feature. "To improve your experience" is now a guaranteed rejection.

Android: foreground services and the Play Console questionnaire

On Android, the equivalent landmine is the foreground service type declaration. If any native module — Bluetooth scanners, audio players, location trackers — declares a FOREGROUND_SERVICE_* permission, you must answer the Play Console's foreground service use-case questionnaire and provide a demonstration video. We've had three apps in the last year rejected because a dependency added FOREGROUND_SERVICE_DATA_SYNC and nobody noticed in the merged manifest.

Run this before every submission:

# Check merged manifest for foreground service declarations
./gradlew :app:processReleaseManifest
grep -r "FOREGROUND_SERVICE" android/app/build/intermediates/merged_manifests/

The OTA update grey zone

EAS Update and CodePush are still allowed, but Apple has narrowed what you can ship over the air. The 2026 reading of Guideline 3.3.2 (which governs JavaScriptCore execution) is roughly: you can patch bugs and tune UX, but you cannot materially change functionality, add new features users would consider new, or change the app's purpose.

In practice, reviewers don't see your OTA payloads. The risk is that a user reports your app, the reviewer downloads a fresh copy and finds it doesn't match your listing screenshots. That's a takedown, not a rejection.

Our policy on every client account:

  • OTA channel for hotfixes only, gated by a feature flag
  • New features ship in a binary release, even if the code went out via OTA first behind a flag
  • Screenshots updated in the same release train as the binary that exposes the feature

We've written more about the channel strategy itself in our EAS Update OTA playbook.

Account deletion: still the silent killer

Apple's account deletion requirement (5.1.1(v)) has been in force since 2022, but the enforcement in 2026 is stricter and more automated. The reviewer's bot now traces the path: sign in, find delete, confirm, verify the account is gone.

The failure modes we keep fixing:

  • Delete buried more than two taps deep from the main account screen
  • "Delete" that actually means "deactivate" with a 30-day grace period and no clear messaging
  • Delete that requires emailing support — explicitly banned
  • Social-login-only apps where the developer assumes revoking the social token is enough (it isn't, you must delete the server-side record)

Google now requires the same, plus a public web URL where users can request deletion without installing the app. Put it in your Data Safety form and link it from your Play listing. If you forget, the listing gets rejected at the next update, not the first one — which is worse, because you've built a release pipeline around an assumption that breaks.

Privacy manifests and the SDK supply chain

Apple's privacy manifest requirement (PrivacyInfo.xcprivacy) hit a critical mass of SDKs in 2025 and is now table stakes. Every native module you depend on should ship its own manifest. The problem: React Native's ecosystem is uneven. Popular libraries like react-native-mmkv, react-native-reanimated, and the Expo modules have manifests. Long-tail community modules often don't.

How to audit before submitting

# From your iOS build output
find ios/Pods -name "PrivacyInfo.xcprivacy" | sort

# Cross-reference with your Podfile.lock
grep -E "^  - " ios/Podfile.lock | awk '{print $2}' | sort -u

If a pod has no manifest and uses one of Apple's "required reason" APIs (file timestamps, UserDefaults, system boot time, disk space), you'll get a binary rejection. The fix is usually to fork the module, add a manifest, and PR upstream. We keep a small internal repo of patched manifests for libraries we use on multiple projects.

In-app purchase edge cases that still bite

We wrote about IAP rejections recently, but two specific 2026 patterns deserve a callout because they hit React Native apps disproportionately:

The "web paywall first" rejection. If your app shows a paywall before the user can use any functionality, Apple wants the IAP option visible and not visibly worse than your web pricing. A common React Native pattern — showing a Stripe-powered web view with a small "or subscribe in-app" link — is now an instant rejection.

The restore purchases requirement. Every paid app must have a visible "Restore Purchases" button, not buried in settings. react-native-iap and Expo's in-app purchases module both expose getAvailablePurchases() — wire it to a button on your paywall screen, not just your account screen.

Android's data safety form is the new minefield

Google's review is less binary than Apple's, but the Data Safety form has become the place where Android releases die. Every SDK you bundle that collects data — analytics, crash reporting, ads, attribution — needs to be declared. The form asks about data types, collection, sharing, and whether it's optional.

The React Native and Expo problem: you often don't know what your SDKs do. Sentry collects device info. Firebase Analytics collects approximate location by default. RevenueCat shares purchase data with its servers. Each of these has a documented data collection profile — find them, fill the form accurately, and update it when you change SDKs.

A mismatch between your declared data practices and what the SDK actually sends triggers a policy strike. Three strikes and the account is suspended, not just the app. We've seen this happen to a small studio that ignored two warning emails.

A pre-submission checklist that actually works

This is the checklist we run before every submission. It takes about an hour and has caught roughly four out of every five issues that would have caused a rejection.

BINARY
[ ] Strip unused native modules from package.json and re-prebuild
[ ] Audit Info.plist usage strings against actual features
[ ] Check merged AndroidManifest for unexpected permissions
[ ] Verify foreground service types match Play Console answers
[ ] Run privacy manifest audit on all pods

UX
[ ] Account deletion reachable in <=2 taps from profile
[ ] Restore purchases button on paywall screen
[ ] No dark patterns in subscription cancellation
[ ] Sign in with Apple offered if any third-party social login is

METADATA
[ ] Screenshots match the current binary's UI
[ ] Data Safety form reflects current SDKs
[ ] Privacy policy URL live and matches declared practices
[ ] Age rating matches actual content

OTA
[ ] Latest EAS Update channel matches submitted binary
[ ] Feature flags for unreleased features default to off

Where we'd start

If you're shipping a React Native or Expo app this quarter and haven't done a review-readiness audit in six months, start with the binary audit — usage strings, manifest permissions, privacy manifests. That's where the highest-impact issues hide, and they're invisible until the reviewer's tooling catches them.

Do the metadata pass second, because it's faster to fix and cheaper to get wrong. Save the UX changes for last; they require product decisions and usually a design review.

If you'd rather hand this off, our mobile team runs this audit as a fixed-scope engagement before any major release. Either way, do it before you hit submit. The cost of a one-week review delay on a launch campaign is almost always higher than the cost of two engineers spending a day on the checklist.

#React Native#Expo#App Store#Play Store#Release Ops

Want a team like ours?

72Technologies builds production software for the kind of teams who actually read this blog.

Start a project