All articles
Mobile DevelopmentSeptember 29, 2026 6 min read

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

A field guide to the App Store and Play Store rejections that hit React Native and Expo apps hardest in 2026 — and how to ship a build that actually gets through on the first try.

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

Every React Native team hits it eventually: the build is green, the PM has already told sales, and then a two-line message from App Review lands in the inbox. Guideline 4.3. Or 5.1.1. Or a Play Console warning about a permission you didn't know a library was pulling in. Here's what we've seen actually get RN and Expo apps rejected in 2026, and the fixes that stop the loop.

Why React Native apps get flagged more than native ones

App Review doesn't care what framework you used, but the pattern of rejections skews differently for RN and Expo builds. Two structural reasons:

  1. You inherit every native dependency your libraries pull in. A single analytics SDK can add three permissions, a tracking domain, and a background mode you never asked for.
  2. OTA updates change the risk model. Reviewers now assume any JS-driven app can silently change behavior post-review, and both stores have tightened language around what that JS bundle is allowed to do.

The result: RN teams get more "minimum functionality," "hidden features," and "privacy manifest" rejections than native teams building the same product. Not because the framework is worse — because the surface area is wider and less visible.

The iOS rejections that keep coming back

Guideline 4.3(a) — Spam / Minimum Functionality

This is the number one killer for smaller RN apps, especially those built on a template or a low-code wrapper. Reviewers reject apps that feel like "a website in a WebView" or a thin CRUD shell.

What actually triggers it in our experience:

  • More than ~40% of screens rendered via WebView pointing at your marketing site
  • No offline behavior at all — every screen shows a spinner without network
  • Sign-in wall on launch with no preview of what the app does
  • Reusing the same binary across many "white label" clients without meaningful differentiation

Fix: give the app at least one genuinely native interaction (camera, haptics, notifications the user configures, on-device search), and make sure at least the first screen renders something useful offline.

Privacy manifests and required reason APIs

Since 2024 Apple has required a PrivacyInfo.xcprivacy file declaring tracking domains, collected data types, and "required reason" API usage. In 2026 this is enforced hard, and RN apps fail it constantly because a transitive dependency uses UserDefaults, NSFileManager modification dates, or systemUptime without declaring a reason.

Expo handles the app-level manifest well via config plugins, but you still need to audit third-party pods. A quick check we run before every submission:

# From the ios/ directory after pod install
grep -r "NSPrivacyAccessedAPICategory" Pods/ | \
  awk -F: '{print $1}' | sort -u

# Then diff against what's declared in your app's PrivacyInfo
plutil -p ios/YourApp/PrivacyInfo.xcprivacy

If a pod uses a required-reason API and doesn't ship its own privacy manifest, you have to either declare it in yours, patch the pod, or drop the library. Apple no longer silently ignores this.

Guideline 3.1.1 — Payments outside IAP

Still a top-five rejection. The 2024 Epic ruling loosened some external-link rules in the US, but the safe default in 2026 is: any digital good consumed inside the app must use StoreKit. Common RN traps:

  • A Buy Pro button that opens Stripe Checkout in an in-app browser
  • "Restore purchases" that hits your own backend instead of StoreKit
  • Subscription paywalls that mention pricing in a currency the store doesn't show

If you're using RevenueCat or plain react-native-iap, make sure the paywall copy matches the price the store returns at runtime, not a hardcoded string. Reviewers do check.

The Android rejections that catch RN teams off guard

Google's rejections come more from automated scans than human reviewers, which means they're both more predictable and harder to argue with.

Data safety form mismatches

Play Console cross-references your Data Safety declaration against what the app actually does at runtime. If a library sends analytics to a domain you didn't declare, you get a policy warning and eventually a removal.

Run this before every submission and reconcile the output against your Data Safety form:

# Extract every network permission and declared domain
./gradlew :app:dependencies --configuration releaseRuntimeClasspath \
  > deps.txt

# Inspect the merged manifest for permissions you didn't add
cat android/app/build/intermediates/merged_manifests/release/AndroidManifest.xml \
  | grep uses-permission

The usual culprits: an SDK that requests AD_ID, ACCESS_COARSE_LOCATION, or POST_NOTIFICATIONS without you noticing.

Foreground service types (Android 14+)

Every foreground service now needs a declared type, and the type must match the actual work. A React Native background audio library declaring dataSync when it's really mediaPlayback will fail Play review. Check your merged manifest, not just your own AndroidManifest.xml.

Target SDK deadlines

Google pushes the required targetSdkVersion every August. RN teams on older Expo SDKs or ejected apps with pinned versions get delisted from search for new users well before they're formally rejected. If you're not on a current Expo SDK, put the upgrade on the roadmap now, not in Q3.

The OTA update trap on both stores

Apple's guideline 3.3.1 (and Google's equivalent) explicitly allow JavaScript OTA updates, but with a condition that keeps getting tighter: the update cannot change the app's core purpose, add features not disclosed at review, or bypass native review of sensitive functionality.

In practice, what gets teams in trouble:

  • Shipping a feature flag OFF at review, then flipping it ON via EAS Update the same day
  • Using OTA to swap out an entire product surface (turning a fitness app into a marketplace)
  • OTA-ing a paywall change that adds a purchase flow the reviewer never saw

Our rule: if a reviewer would have asked a question about it, ship it in a binary update. Use OTA for bug fixes, copy changes, and small UX tweaks. Not for anything that changes what the app is.

More on how we scope OTA in our release engineering work.

A pre-submission checklist that actually works

We run this checklist for every client build before it goes to TestFlight or Internal Testing. It's not glamorous but it cuts our first-review rejection rate to near zero.

Binary hygiene

  • Version and build numbers incremented and matching between iOS and Android
  • No console.log of tokens, emails, or user IDs in release JS bundle
  • Source maps uploaded to Sentry (or equivalent) but not shipped in the binary
  • Hermes enabled and bundle size checked against previous release

Privacy and permissions

  • PrivacyInfo.xcprivacy regenerated and reviewed against pod manifest scan
  • Play Data Safety form matches actual network calls (proxy the app for an hour and diff)
  • Every NS*UsageDescription string is specific — not "we need your camera"
  • AD_ID permission removed if you don't actually use advertising ID

Review account and demo

  • Demo account credentials in App Store Connect, tested from a fresh device
  • Demo account has realistic data, not an empty state
  • Any region-locked features have a note in the Review Notes field
  • Video preview or notes for anything that requires hardware the reviewer won't have (BLE peripherals, NFC tags, printers)

Post-review discipline

  • OTA channel for the reviewed build is frozen until approval
  • Feature flags shipped OFF stay OFF until the binary is live for real users
  • Rollout percentage starts at 10–20%, not 100%

Where we'd start

If you're mid-project and dreading your first submission: skip trying to fix everything at once. Do two things this week. First, run the pod and gradle scans above and reconcile them against your privacy declarations — that alone eliminates the most common automated rejections. Second, sit with your PM and mark every feature as either "shown at review" or "gated behind a flag," then write down which flags are safe to flip via OTA and which need a new binary. That single document has saved us more review cycles than any tooling ever has.

For teams already stuck in a rejection loop, the fastest path out is usually to reply to the reviewer with a short screen recording showing exactly what they missed, plus a fresh demo account. Long written appeals rarely work. A 30-second Loom often does.

#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