Use this page with AI

Copy this into your coding assistant and add your request.

Read https://openiap.dev/docs/guides/testing and https://openiap.dev/llms.txt. Follow the reading instructions, detailed reference, and linked guides relevant to my task before making changes.
Inspect my existing project and reuse its framework and conventions. Ask me for missing product decisions. Implement the requested behavior and run the applicable checks.
Show the working result, the commands and actual test results, and any remaining limitations. Keep your explanation brief.

My request: [describe what customers should be able to do]
See an example request →

Testing & Sandbox

In-app purchases require specific setup for testing on each platform. This guide covers sandbox environments, common pitfalls, and framework-specific notes to help you test effectively.

iOS Testing#

Sandbox Apple Account#

Apple provides sandbox accounts for testing purchases without real charges. To configure a sandbox account on your device:

  1. Create sandbox testers in App Store Connect → Users and Access → Sandbox Testers
  2. In a development-signed build, start a purchase and sign in with the sandbox account when the App Store asks
  3. Manage the account afterwards in Settings → Developer, which appears once Developer Mode is on

Reference: Apple: Testing in-app purchases with sandbox

StoreKit Testing in Xcode#

Xcode provides local StoreKit testing that works without a network connection or sandbox account. This is the fastest way to iterate on your purchase logic:

  1. Create a StoreKit Configuration file in Xcode (File → New → File → StoreKit Configuration File)
  2. Define your products and subscriptions in the configuration
  3. Edit your scheme (Product → Scheme → Edit Scheme) and set the StoreKit Configuration under the Options tab
  4. Run the app in the simulator or on device — purchases use the local configuration

Local StoreKit testing also lets you simulate scenarios like subscription renewal, refunds, ask-to-buy, and interrupted purchases via the StoreKit Transaction Manager in Xcode.

Reference: Apple: Setting up StoreKit testing in Xcode

TestFlight Testing#

TestFlight builds always run in the sandbox environment, and purchases are not charged. They use the Apple Account signed in under Media & Purchases, so testers need no sandbox account. This is the closest test environment to production.

To test with a Sandbox Apple Account and its sandbox controls instead, sign out of Media & Purchases, then sign in to the sandbox account under Settings → Developer. This works only for apps in your own developer account. Signing back in to Media & Purchases moves TestFlight purchases back to that account.

Reference: Apple: Testing subscriptions and In-App Purchases in TestFlight

Prices and Currency in Testing#

OpenIAP passes StoreKit's values through unchanged: a product's displayPrice and currency come from StoreKit's displayPrice and priceFormatStyle.currencyCode, and getStorefront() returns the country code of Storefront.current.

In sandbox and TestFlight, prices follow the App Store storefront of the Apple Account making the purchase, not the device region. In TestFlight that is the account in Media & Purchases, unless you switched to a Sandbox Apple Account as described above. To test a specific country:

  • Set the Sandbox Apple Account's Country or Region in App Store Connect, then sign out of the account on the device and sign back in. Product metadata changes in App Store Connect can take up to an hour to reach sandbox.
  • For layout and currency formatting, set the default storefront in a StoreKit configuration file: Configuration Settings in Xcode 15 and later, the Editor menu before that.

If a product's currency still disagrees with the storefront, fetch the same products with Product.products(for:) in Swift. OpenIAP calls that API directly, so the same mismatch there comes from StoreKit or the sandbox; report it through Feedback Assistant. A check that blocks purchases when currency and storefront disagree can trip in these environments, so limit it to production, for example with the environment from getAppTransactionIOS().

Reference: Apple Developer Forums: sandbox prices follow the tester's storefront

Clearing Sandbox Purchase History#

To reset sandbox purchase history on iOS:

  1. Go to Settings → Developer and select your Sandbox Apple Account
  2. Select Manage, then Clear Purchase History
  3. Sign out of the account and sign back in to clear the cached history on the device

Alternatively, create a new sandbox tester account in App Store Connect for a completely fresh state.

Android Testing#

License Testers#

License testers can make test purchases without being charged. To set them up:

  1. Open Google Play Console → Settings → License testing
  2. Add the Gmail addresses of your testers
  3. Set the license response to RESPOND_NORMALLY

Reference: Android: Test your Google Play Billing integration

Internal Testing Track#

Upload your APK or AAB to an internal testing track in Google Play Console. This gives you a test link that testers can use to install the app. The app must be installed from the Play Store (not sideloaded) for billing to work properly.

Reference: Google: Set up internal testing

Test Card Numbers#

When testing with license tester accounts, Google Play provides special test instruments:

  • Test card, always approves — Purchase completes successfully
  • Test card, always declines — Purchase is rejected
  • Test card, slow — Simulates a slow network response

These appear automatically in the payment sheet when a license tester initiates a purchase.

Clearing Test Purchases#

To clear test purchases on Android:

  • Consumable products are automatically consumed when purchased by license testers (after 3 minutes if not consumed by the app)
  • For subscriptions, cancel them in the Google Play app or wait for the short test renewal period to expire
  • You can also refund or revoke purchases in the Google Play Console → Order management

Common Issues#

Products Not Found#

If fetchProducts returns an empty list, check the following:

  • Agreements: Ensure all paid app agreements are signed in App Store Connect / Google Play Console
  • Banking & Tax: Complete your banking and tax information in the respective console
  • Bundle ID: The app's bundle identifier must exactly match what is configured in the store
  • Product IDs: Verify product identifiers match exactly (case-sensitive)
  • Product Status: Products must be in "Ready to Submit" or "Approved" state (iOS) or "Active" state (Android)
  • Wait time: New products can take several hours to propagate — up to 24 hours in some cases

Purchase Not Completing#

If a purchase starts but never completes or stays in a pending state:

  • Ensure you are calling finishTransaction after processing the purchase. Unfinished transactions block future purchases.
  • Check that your purchase listener is properly set up before initiating the purchase
  • On Android, verify the app is signed correctly and installed from the Play Store test track

Connection Failed#

If you receive connection errors when trying to fetch products or make purchases:

  • Ensure initConnection is called before any other IAP operations
  • On Android, the Google Play Billing client may fail to connect if the Play Store app is outdated or the device does not have Google Play Services
  • On iOS, verify the device has network access and is signed in with a valid (sandbox or production) Apple ID
  • Always call endConnection when the app is closing or the IAP context is being torn down

Sandbox vs Production Differences#

  • iOS: Sandbox subscriptions renew at an accelerated rate (e.g., monthly subscription renews every 5 minutes). Production subscriptions renew at their normal interval.
  • Android: Test subscriptions have a shortened renewal period (default 5 minutes). The billing flow UI shows "Test card" options for license testers.
  • Receipt/purchase token formats may differ between sandbox and production — do not hard-code assumptions about their structure

iOS Sandbox Subscription Renewal Rates

ProductionSandbox
1 week3 minutes
1 month5 minutes
2 months10 minutes
3 months15 minutes
6 months30 minutes
1 year1 hour

References: Apple: Sandbox testing | Android: Test subscriptions

Framework-Specific Testing Notes#

React Native / Expo#

  • IAP must be tested on a real device. The iOS simulator has limited StoreKit functionality and Android emulators require a Google Play Store image.
  • For React Native CLI: cd libraries/react-native-iap/example && yarn ios (or yarn android)
  • For Expo: use a development build (npx expo run:ios) — Expo Go does not support native modules like IAP

Flutter#

  • Run flutter run on a connected real device for the best testing experience
  • The iOS simulator supports basic StoreKit testing with a local configuration file, but real-device testing is recommended
  • On Android, ensure the device or emulator has the Play Store installed

Godot#

  • In-app purchases cannot be tested in the Godot editor. You must export the project to a real device.
  • For Android: export an APK, sign it, and upload to an internal testing track
  • For iOS: export via Xcode and run on a physical device with a sandbox account

Kotlin Multiplatform#

  • Android: Use an emulator with a Google Play Store image (e.g., "Google APIs" system image) or a real device. Build with Gradle: ./gradlew :composeApp:assembleDebug
  • iOS: Open the iosApp/ directory in Xcode and run on a physical device. The simulator supports local StoreKit testing only.

References#

Apple

Google

OpenIAP