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:
- Create sandbox testers in App Store Connect → Users and Access → Sandbox Testers
- On your device, go to Settings → App Store → Sandbox Account (iOS 14+) and sign in with the sandbox Apple ID
- Run your app — purchases will use the sandbox environment
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:
- Create a StoreKit Configuration file in Xcode (File → New → File → StoreKit Configuration File)
- Define your products and subscriptions in the configuration
- Edit your scheme (Product → Scheme → Edit Scheme) and set the StoreKit Configuration under the Options tab
- 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 use the sandbox environment automatically. Testers do not need a separate sandbox account — purchases made in TestFlight are not charged. This is the closest test environment to production.
Reference: Apple: TestFlight
Clearing Sandbox Purchase History#
To reset sandbox purchase history on iOS:
- Go to Settings → App Store → Sandbox Account
- Tap your sandbox account
- Select Manage and clear purchase history for specific apps
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:
- Open Google Play Console → Settings → License testing
- Add the Gmail addresses of your testers
- 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
finishTransactionafter 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
initConnectionis 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
endConnectionwhen 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
| Production | Sandbox |
|---|---|
| 1 week | 3 minutes |
| 1 month | 5 minutes |
| 2 months | 10 minutes |
| 3 months | 15 minutes |
| 6 months | 30 minutes |
| 1 year | 1 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(oryarn android) - For Expo: use a development build (
npx expo run:ios) — Expo Go does not support native modules like IAP
Flutter#
- Run
flutter runon 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
- In-App Purchase Overview
- Testing with Sandbox
- StoreKit Testing in Xcode
- StoreKit 2 Documentation
- Setting Up Subscription Groups
- Google Play Billing Overview
- Test Your Billing Integration
- Set Up Internal Testing
- Integrate the Google Play Billing Library
- Google Play Subscriptions