This guide provides multiple methods to test in-app purchases for Toss or Taste on iOS.
-
Add StoreKit Configuration to Xcode Project:
- Open
ios/App/App.xcworkspacein Xcode - Drag the
TossOrTaste.storekitfile into your Xcode project navigator - Make sure it's added to the App target
- Open
-
Configure Scheme to Use StoreKit Configuration:
- In Xcode, go to Product > Scheme > Edit Scheme
- Select Run on the left sidebar
- Go to the Options tab
- Under StoreKit Configuration, select
TossOrTaste.storekit - Click Close
-
Run the App:
- Build and run the app on simulator or device
- IAP purchases will use the local StoreKit configuration
- No internet connection needed
- No sandbox account needed
- Instant purchase processing
- ✅ Test without App Store Connect setup
- ✅ Works offline
- ✅ Fast iteration (no backend verification delays)
- ✅ Easy to test edge cases and error scenarios
- ✅ Can simulate different storefronts/locales
- ✅ Can test transaction failures
While running the app with StoreKit configuration enabled:
-
View Transactions:
- In Xcode, go to Debug > StoreKit > Manage Transactions
- See all test purchases
- Manually approve/decline purchases
- Refund transactions
- Clear purchase history
-
Test Different Scenarios:
- Slow Network: Debug > StoreKit > Enable Slow Network
- Purchase Failures: Edit the
.storekitfile and enable errors - Interrupted Purchases: Stop/restart the app during purchase flow
- Different Storefronts: Change locale in StoreKit settings
-
Clear Purchase History:
- Debug > StoreKit > Clear All Transactions
- Tests consumables and subscriptions from scratch
-
Create Sandbox Test User:
- Go to App Store Connect
- Navigate to Users and Access > Sandbox Testers
- Click the + button to add a new sandbox tester
- Use a unique email that's never been used with Apple ID
- Remember the password
-
Sign Out of Production App Store:
- On your iOS device: Settings > App Store > Sign Out
- DO NOT sign in with the sandbox account yet
-
Build & Install App:
- Archive and export the app for development distribution, OR
- Run directly from Xcode to your device
-
Make a Purchase:
- When you attempt a purchase, iOS will prompt you to sign in
- Sign in with your sandbox test account
- Complete the purchase (you won't be charged)
- Confirmation will say [Environment: Sandbox]
- ✅ Tests real App Store Connect product configuration
- ✅ Tests receipt validation
- ✅ Tests subscription renewals
- ✅ Closer to production environment
- ❌ Requires App Store Connect products to be configured
- ❌ Requires sandbox test account
- ❌ Can be slower
- ❌ Receipt validation may fail if backend isn't configured
-
Upload Build to TestFlight:
# Archive the app in Xcode # Product > Archive # Distribute App > App Store Connect # Upload
-
Add Internal/External Testers:
- In App Store Connect, go to TestFlight
- Add testers via email
- They'll receive an invitation
-
Install via TestFlight:
- Testers install the TestFlight app
- Install your app from TestFlight
- Make purchases using sandbox accounts
- ✅ Tests complete production flow
- ✅ Tests with real users
- ✅ Tests push notifications and other entitlements
You can add these to your appleIAP.ts to get better visibility:
// Add this to your initialize() method after store.ready():
window.store.verbosity = window.store.DEBUG;
// Add transaction monitoring
window.store.when().registered((product) => {
console.log('🍎 Product registered:', product);
});
window.store.when().updated((product) => {
console.log('🍎 Product updated:', product);
});Check:
- Product IDs match exactly in App Store Connect
- At least one product is in "Ready to Submit" state
- Agreements are signed (Paid Apps agreement)
- Banking info is complete
StoreKit Test:
- Verify product IDs in
.storekitfile match code - Check Xcode console for product registration logs
Check:
window.storeis initialized- Product is
loaded,valid, andcanPurchase - Not testing on iOS Simulator (some IAP features don't work)
- StoreKit configuration is enabled in scheme
Debug:
const product = window.store.get('com.linksmarttech.tossortaste.single_credit');
console.log('Product status:', {
exists: !!product,
loaded: product?.loaded,
valid: product?.valid,
canPurchase: product?.canPurchase,
state: product?.state
});Check:
- Backend endpoint is accessible
- Supabase credentials are correct
- Receipt validation logic is working
- Transaction is being finished properly
Debug:
- Add extensive logging in
handleVerifiedPurchase() - Check Supabase logs
- Verify network requests in Safari Web Inspector
- Clear StoreKit transactions (Debug > StoreKit > Clear All)
- Fresh app install (delete and reinstall)
- Check Xcode console for initialization logs
- Verify products are loaded
- Purchase single credit
- Purchase credit pack
- Subscribe to monthly plan
- Subscribe to annual plan
- Cancel during purchase
- Interrupted purchase (kill app mid-purchase)
- Restore purchases
- Purchase with poor network
- Multiple rapid purchases
- Credits reflect in UI immediately
- Database updated correctly
- Subscription status reflects properly
- Receipt saved correctly
- No duplicate charges
- Open Xcode:
open ios/App/App.xcworkspace - Edit Scheme: Product > Scheme > Edit Scheme
- Set StoreKit Config: Options tab > Select
TossOrTaste.storekit - Run app on simulator/device
- Make test purchases - they'll use local config
- Monitor: Debug > StoreKit > Manage Transactions
# Enable verbose StoreKit logging
defaults write com.apple.appstored DebugLogging -bool true
# View StoreKit daemon logs
log stream --predicate 'subsystem contains "com.apple.storekit"' --level debug- StoreKit Testing in Xcode
- Testing In-App Purchases
- Sandbox Testing
- cordova-plugin-purchase Documentation
Your code currently has a mock purchase fallback at appleIAP.ts:330-348 when products aren't loaded. This is helpful for UI testing but should be removed before production.
// TEMPORARY: Mock successful purchase for testing
if (!product || !product.loaded || !product.valid) {
console.log('🍎 Product not loaded from App Store - using MOCK PURCHASE for testing');
// ... mock implementation
}Recommendation: Once StoreKit testing is working, remove the mock fallback to ensure you're testing the real purchase flow.