All articles
Mobile DevelopmentJune 6, 2026 7 min read

In-App Purchases in React Native: What Apple and Google Actually Reject in 2026

A practical breakdown of the IAP rejection patterns we keep seeing in React Native and Expo apps in 2026 — from receipt validation to subscription restore flows — with code you can lift straight into your project.

In-App Purchases in React Native: What Apple and Google Actually Reject in 2026

Every quarter we get the same call: an app that has been live for a year suddenly hits a wall on an IAP update, or a fresh submission gets bounced three times in a row over subscription wording. The rules haven't really changed in 2026, but reviewers are stricter, and React Native apps in particular keep tripping on the same handful of issues. Here is what we keep seeing, and how we fix it.

The rejection patterns that dominate 2026

Apple's App Review and Google's Play policy team flag IAP issues for fairly predictable reasons. After shipping or auditing maybe two dozen subscription apps in the last eighteen months, the rejections cluster into five buckets:

  • Missing or broken restore purchases flow (iOS, Guideline 3.1.1)
  • Subscription terms not visible before purchase (both stores)
  • Receipt validation done only client-side — usually surfaces as a fraud or refund complaint later, not a review rejection, but it bites
  • Mismatched product metadata between the store and what the app displays
  • Using a non-IAP payment method for digital goods, often accidentally via a webview

The React Native angle is that the JavaScript layer makes some of these easier to get wrong. A webview that links to a Stripe checkout for a digital subscription is a one-line mistake that costs you a week. Let's go through the ones we see most.

Restore purchases: the rejection that keeps coming back

If your app has any account-bound entitlement, Apple expects a visible Restore Purchases control. Not buried in settings, not gated behind a login wall that the reviewer can't get past. We have seen apps rejected even when the restore flow exists, because the reviewer couldn't find it in under thirty seconds.

With react-native-iap (still the most common choice in 2026, alongside Expo's expo-in-app-purchases successor and RevenueCat's SDK), the restore call itself is simple. The mistake is usually what you do with the result.

import {
  getAvailablePurchases,
  finishTransaction,
} from 'react-native-iap';

export async function restorePurchases() {
  try {
    const purchases = await getAvailablePurchases();
    const active = purchases.filter(isStillEntitled);

    for (const p of active) {
      await syncEntitlementWithBackend(p);
      // iOS: only finish after your server confirms
      if (p.transactionId) {
        await finishTransaction({ purchase: p, isConsumable: false });
      }
    }

    return active.length > 0;
  } catch (err) {
    reportError(err);
    throw err;
  }
}

Three things matter here:

  1. Always hit your backend to revalidate the receipt before you grant access. Restore is a common fraud vector.
  2. Don't finish the transaction until the server confirms. Otherwise a failed sync leaves the user paid-up on Apple's side but with no access in your app.
  3. Show a result toast or screen. Reviewers tap restore on a fresh install with no purchases — if nothing happens visually, they assume it's broken.

Where to put the button

For iOS submissions in 2026 we put a Restore Purchases button in two places: on the paywall itself, and in account settings. Both. Yes, it feels redundant. No, you will not get rejected for redundancy. You will get rejected for the reviewer not finding it.

Subscription disclosure: the wall of text Apple wants

Apple's subscription disclosure requirements are old, and yet at least a third of the apps we audit get this wrong. Before the purchase action, the user must see:

  • Subscription title and length
  • Price per period
  • That it auto-renews
  • How to cancel (or a link to Apple's cancellation docs)
  • Links to your Terms of Use (EULA) and Privacy Policy

This text has to be visible on the same screen as the buy button. Not behind a tooltip, not on a previous screen. We have had submissions rejected because the disclosure was a one-tap accordion that started collapsed.

The React Native pitfall: paywalls built with a remote config or A/B testing tool sometimes ship variants that drop the disclosure block. If you A/B test paywalls, the disclosure text should be a non-removable component, not a configurable field.

Server-side receipt validation is not optional anymore

Client-side validateReceiptIos or validateReceiptAndroid calls are fine for a hackathon. In production they are a liability. Both stores have moved most of their subscription state to server-to-server notifications:

  • Apple's App Store Server Notifications V2
  • Google Play's Real-time Developer Notifications via Pub/Sub

If you are not consuming these, you will not know when a user's subscription is refunded, paused, or moved to a different family-sharing setup. The user calls support angry that they cancelled a month ago and you are still serving them paywalled content — or worse, you cut off someone who is still paying because you trusted a stale client receipt.

Our usual server architecture:

Client purchase
  -> POST /iap/verify { platform, receipt }
  -> Server validates with Apple/Google
  -> Server writes entitlement row { userId, productId, expiresAt, source }
  -> Server returns entitlement to client

Apple/Google webhook
  -> POST /iap/webhook
  -> Server updates entitlement row
  -> Server pushes silent notification to client to refresh

The entitlement row is the source of truth, not the receipt. The client asks your server, not the store. This also makes cross-platform restore (paid on iOS, opened on Android) trivial — assuming you have user accounts, which is its own debate.

When RevenueCat earns its keep

We do not recommend tools by default, but RevenueCat genuinely removes a class of work here. The webhook handling, the entitlement model, the cross-platform reconciliation — it is all done. For a team without backend bandwidth to babysit Apple's notification format changes, the cost is usually justified. For a team that already runs a billing-adjacent backend, rolling your own with react-native-iap and a clean entitlement service is fine.

The webview trap

If your app is even partially a webview wrapper, audit every link. Apple's Guideline 3.1.1 prohibits using non-IAP payment methods for digital goods inside the app. A login screen that opens a webview to your site, where the user can then navigate to an upgrade page with a Stripe button, is a rejection.

The Reader app exception exists, but it is narrower than people think and requires an entitlement. Do not assume you qualify.

For React Native apps with embedded WebView components, the safe pattern is:

  • Strip or intercept any URL that leads to a payment page
  • For physical goods or services consumed outside the app (e-commerce, ride hailing, food delivery), external payment is fine — and in the EU and a growing list of jurisdictions, external payment links for digital goods are now also permitted under specific conditions
  • For digital subscriptions consumed in the app, use IAP unless you have explicitly applied for and received the external link entitlement

The 2026 reality is that external payment rules vary wildly by region. We have stopped trying to be clever about it on global apps — IAP everywhere is boring, but it ships.

Google Play's quieter but stricter side

Google's billing library (Play Billing 7+ in 2026) is technically less fussy than Apple's review process, but the policy team is catching up. Common Play rejections we have hit:

  • Subscription details not matching the Play Console product. If your Play Console says "Monthly Pro" at $9.99 and your app shows "Pro Plan" at "$9.99/mo", that string mismatch has been flagged.
  • Acknowledging purchases late or never. Google gives you three days to acknowledge a purchase. Miss it and the purchase is auto-refunded. With react-native-iap this means calling finishTransaction (which acknowledges under the hood) reliably, including after app restarts where a purchase completed but your handler crashed.
  • Free trials without a clear price-after-trial label. This one is now enforced almost as strictly as on iOS.

A simple pattern: on every app launch, fetch outstanding purchases and acknowledge any that your server has already granted entitlement for. It is idempotent and saves the occasional dropped acknowledgement.

A submission checklist that has passed first time

We keep this taped to the wall, metaphorically:

  • Restore Purchases button on paywall and in settings
  • Disclosure block on paywall: title, length, price, auto-renew, cancel info, Terms, Privacy
  • Terms of Use (EULA) URL set in App Store Connect — Apple's default EULA is fine if you do not have a custom one, but the link must work
  • Server-side receipt validation live, with webhooks consumed
  • No webview routes to external digital-goods payment
  • Test account credentials provided in App Review notes, including how to reach the paywall
  • Sandbox tested for: new purchase, restore, cancellation, refund, upgrade between tiers
  • Android: acknowledgement happens within app session, with a safety net at launch

The single biggest accelerator is the App Review notes field. Tell the reviewer exactly where the paywall is, what test card or sandbox account to use, and what to expect. Reviewers process hundreds of apps a day — make their job easy and you stop being a rejection statistic.

Where we'd start

If you are about to ship IAP in a React Native app for the first time, do these three things before you write any UI code: stand up the entitlement table and webhook endpoint on your backend, decide whether RevenueCat is worth it for your team's bandwidth, and write the App Review notes draft. The paywall screen is the easy part. The infrastructure around it is what gets you approved — and what keeps your refund rate from quietly eating your margin six months later. If you want a second pair of eyes on an IAP build before you submit, our mobile team does pre-submission audits.

#React Native#Expo#In-App Purchase#App Store Review#Mobile Development

Want a team like ours?

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

Start a project
React Native IAP Rejections: What Apple & Google Reject in 2026 · 72Technologies