Testing & Troubleshooting
This guide describes how to test in-app purchases in your app and provides useful tips.
Android
Testing purchases in Android is the same as real purchases. However, you will need to add your Google account to application license testing in order to make purchases for free. For more information about the testing purchases, please read the official documentation.
Test a Fresh Install
To test a fresh install you will need to:
- Delete user in Apphud
- Delete the app
Android SDK doesn't save the User ID / Device ID to the device keychain. This means that deleting the app and user in Apphud will generate a new User ID / Device ID pair. When launching the app after re-install, you will get a fresh user without purchases.
However, if restore purchases are called, Apphud will merge an existing user with a new user. As a result, the User ID will change to the original one and the user will have two devices, with the old and new Device IDs. The original purchase history will be restored.
Clear Purchases History
Google Play doesn't fully clear purchase history. The best way is to change your Google account on the device, but if this is not an option, you can refund/cancel transactions in Google Play console > Order management.
Troubleshooting
Common steps
In case you experience any issues with in-app purchases in your Android app, please check the following:
- Make sure you have correctly set up Google Play Service Credentials .
- View debug logs in Android Studio. To enable debug logs call:
Apphud.enableDebugLogs()
before SDK initialization. If you have any issues with in-app purchases, the error will populate in console. - Make sure you have entered the correct Android Package Name in Apphud app settings.
- If you don't use Apphud billing client, make sure
Apphud.syncPurchases()
is called after a successful purchase or restoration.
iOS
Testing Environments
There are two ways to test purchases in iOS: using Local StoreKit Testing (Xcode builds only) or Sandbox Testing (Xcode or TestFlight builds).
You can read more about differences and limitations between Sandbox and StoreKit Testing in this documentation.
Local StoreKit Testing
Apphud supports receipts made using StoreKit Configuration File. No need to update SDK and no additional code is required. With StoreKit Configuration File enabled in your scheme, you can make purchases in iOS Simulator (or real device) as usual by calling Apphud.purchase(product){...}
method. You can read more about StoreKit Configuration File set up in our blog post.
Note, that receipt generated by Local StoreKit is limited, and doesn't contain many fields that are available when verifying receipts through Apple. For example, trial period
field is missing, as well as pending_renewal_info
, which is a special sub-json containing important fields about the state of subscription, like auto-renew, in billing retry, etc.
Limitations
- Unable to detect
trial
status of the subscription. That means after purchasing subscription with trial period, you will getApphudSubscripton
model withregular
status in the response. But don't worry, that is only local receipt issue, everything will work fine in production! ApphudSubscripton
models generated from local receipts will always haveisInRetryBilling
=false
andisAutorenewEnabled
=true
, unless expired.- Simplified renewals logic. Local receipt is just a snapshot and we are unable to detect renewals of such receipts, until a fresh local receipt is sent to our backend. Which means that subscription will move to
expired
state after the first transaction is expired. When launching the app again in simulator, a new receipt will be automatically sent to Apphud, and subscriptions data will be updated. No actions required on developer side. Again, everything will work just fine in production. - Apphud doesn't create transactions and events of local receipts. In Apphud User page, subscription will only have status and expiration date.
- Testing promotional offers using Xcode generated Subscription Offers key will be supported soon.
- Testing eligibilities is not supported.
- Testing Apphud Rules is not supported.
Note
We don't validate local receipts with the StoreKit certificate at the moment (you can test without them, everything would work fine). The certificates required for testing automation scenarios. Will be added later.
Sandbox Testing
Sandbox testing requires creating Sandbox User if testing in Xcode build. TestFlight builds use real Apple ID. You can read more about differences and limitations between Sandbox and StoreKit Testing in this documentation.
Create Sandbox User
Creating a sandbox test user is required for making purchases in Xcode build. You can create as many sandbox users as you want in App Store Connect. In most cases one sandbox user is enough, but you may want to create a new sandbox user in order to clear purchases history.
Note
You can read more about testing and setting up auto-renewable subscriptions in our blog.
To test in app purchases you need to create sandbox user. Go to App Store Connect and open "Users and Access", then – "Sandbox Testers":

You can sign in to Sandbox account separately from your App Store account since iOS 12. Sign in to sandbox here:

Note
You can read more about creating sandbox testers here.
Sandbox Purchasing
Purchasing process is the same as real in-app purchases. The only difference is accelerated time and impossibility to cancel subscription manually. Subscriptions in sandbox renew 6 times per day maximum.
Real duration | Duration in 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 |
Which Events Can Be Tested?
You can test following all events in sandbox except REFUNDED events.
However, REFUNDED events can still be tested using Local StoreKit Testing.
Note
You can read more about events here.
Eligibilities
Important Note
Testing Eligibilities are not supported in Local StoreKit Testing mode. Use Sandbox testing instead.
Apphud checks whether the given user is eligible for purchasing introductory or promotional offers by searching for transactions in ANY of the current user's subscriptions. This means that if your Apphud user has several app store receipts from previous sandbox Apple IDs, you may get unexpected results.
Apphud User may have several subscriptions with the same product from a different Apple ID account if you were changing sandbox Apple ID without deleting Apphud User. In this case, Apphud will merge multiple subscriptions under the same user. That is why it is recommended to delete your Apphud User from Apphud Dashboard when testing the app from another Apple ID.
Testing Eligibility for Trial / Introductory Offer
To correctly use the checkEligibilityForIntroductoryOffer
method please do the following:
- Please make sure that your Apphud User doesn't contain multiple App Store receipts from previous test Apple IDs. If so, delete your user.
- Note that the "Reset Eligibility" option (Settings > App Store > Sandbox Account > Manage > Your App) is not supported. Apple doesn't delete old trial transactions from the receipt, so there is no technical way to correctly determine introductory eligibility after you pressed the "Reset Eligibility" button.
- Test on a clean Apple ID account. Create a fresh sandbox Apple ID account.
- When running the app for the first time after deleting (i.e. fresh install), keep in mind that you would need to submit App Store Receipt to Apphud either by calling
Apphud.migratePurchasesIfNeeded{}
or by tapping the restore purchases button in your App's UI. This is required only in Sandbox because apps running from Xcode/TestFlight initially don't have App Store Receipts and Apphud doesn't automatically refresh missing App Store receipts to avoid Apple ID password prompt. At production, however, everything will work okay, because App Store receipts always exist in apps downloaded from the App Store. - Now you can test your eligibility method: the method will return
true
because you didn't yet use the introductory offer. After you have used the introductory offer, the method will returnfalse
.
Testing Eligibility for Promotional Offer
To correctly use checkEligibilityForPromotionalOffer
method please do the following:
- Please make sure that your Apphud User doesn't contain multiple App Store receipts from previous test Apple IDs. If so, delete your user.
- When running the app for the first time after deleting (i.e. fresh install), keep in mind that you would need to submit App Store Receipt to Apphud either by calling
Apphud.migratePurchasesIfNeeded{}
or by tapping the restore purchases button in your App's UI. This is required only in Sandbox because apps running from Xcode/TestFlight initially don't have App Store Receipts and Apphud doesn't automatically refresh missing App Store receipts to avoid Apple ID password prompt. At production, however, everything will work okay, because App Store receipts always exist in apps downloaded from the App Store. - Now you can test your promo eligibility method: the method will return
true
if Apphud User has any subscription andfalse
if the user doesn't have any subscriptions.
Test a Fresh Install
In order to test a fresh install in Apphud you need to:
- Delete your user in Apphud.
- Delete the app.
- Optionally clear purchase history.
Clear Purchases History
If you make purchases in Local StoreKit Testing, deleting the app and Apphud User will be enough since it will reset the receipt.
However, when making purchases using Sandbox / TestFlight mode, you will also need to change sandbox Apple ID.
Troubleshooting
Payment cancelled but Apphud.hasActiveSubscription
method still returns true
Apphud.hasActiveSubscription
method still returns true
Please check your Apphud user's purchase history. Probably, you made purchases earlier for this user. Try testing with a fresh install.
Payment completed but it does not appear in Apphud / Apphud.hasActiveSubscription
returns false
Apphud.hasActiveSubscription
returns false
In case you experience any issues with in-app purchases in Apphud, please check the following steps:
- Make sure you have entered correctly Shared Secret .
- View debug logs in Xcode. To enable debug logs call:
Apphud.enableDebugLogs()
before SDK initialization. If you have any issues with in-app purchases, the error will populate in the console. - Make sure you have entered the correct iOS Bundle ID.
Errors during the purchase
When you make purchases using Apphud, in response you get ApphudPurchaseResult
object. If the purchase failed, you get an error that may be of three classes:
SKError
from StoreKit withSKErrorDomain
codes. This is a system error when purchasing transactions. Apphud is not responsible forSKError
domain codes, because they are returned directly from App Store.NSError
from HTTP Client withNSURLErrorDomain
codes. This is a network/server issue when uploading receipts to Apphud.- Custom
ApphudError
without codes. For example, if couldn't sign a promo offer or couldn't get an App Store receipt. This is an SDK level error.
"Cannot connect to iTunes Store" / SKError.code
= unknown
SKError.code
= unknown
If you experience issues like "Cannot connect to iTunes Store" or your SKPaymentTransaction
fails with SKError.code
= unknown
, it is a generic error message that App Store generates. This may be one of the:
- Transaction is interrupted by the Ask to Buy feature
- Transaction is interrupted due to Strong Customer Authentication
- There was another problem with the user's Apple ID account.
Apphud SDK is unable to fix the issue and the developer is responsible to handle these types of errors. The best practice is to check the error code, and if it is SKError.code
= paymentCancelled
, then the payment was cancelled by the user, do nothing in this case. In other cases, you may want to display the error message to the user.
Another case of a high percentage of failed
transactions is Strong Customer Authentication (SCA) for European Economic Area, which requires all payments to be verified. In this case, the current transaction goes to the failed
state, and once payment is approved, a new transaction with the purchased
state is created. Apphud SDK automatically handles interrupted purchases for this case as well, you have nothing to do about it.
Failed to get App Store Receipt
This error means that the App Store receipt is missing on the device even after a successful purchase. Apphud SDK automatically tries to recover the receipt with SKReceiptRefreshRequest
, but if the receipt is still missing "Failed to get App Store Receipt" error will be thrown. Apphud SDK is unable to recover this issue due to an iOS / Sandbox bug. Unfortunately, this often happens to Apple Reviewers.
App was rejected due to purchase problems
If your app got rejected and worked fine in Xcode / TestFlight builds during the test, don't worry – your app probably works fine, but reviewers are having issues with their devices. They may experience the following issues:
- Transaction failed with
SKError.code = unknown
- Transaction complete, but Failed to get App Store Receipt error is thrown in case App Store receipt is missing on the device even after purchase.
- Transaction complete, but Sandbox server is down. In this case, Apphud SDK will throw an error.
The first thing you need to do is to determine, whether SKProducts
were actually loaded in the reviewer's paywall screen. In most cases, the reviewer attaches a screenshot of their error/paywall screen.
If products did load correctly and prices were displayed, then it is probably a payment issue. The next thing is to try to find the reviewer's error in your product analytics, if available.
Workaround:
- Just re-submit the same build and send the reviewer a message about the Sandbox issue.
- Add a code workaround for Sandbox only by letting users go through the paywall screen if the transaction's state is purchased. Here is an example:
extension ApphudPurchaseResult {
var success: Bool {
subscription?.isActive() ?? false ||
nonRenewingPurchase?.isActive() ?? false ||
(Apphud.isSandbox() && transaction?.transactionState == .purchased)
}
}
Apple reviewer provided tips regarding validating receipt in a sandbox environment
Sometimes, the reviewer provides a tip with the following message:
When validating receipts on your server, your server needs to be able to handle a production-signed app getting its receipts from Apple’s test environment. The recommended approach is for your production server to always validate receipts against the production App Store first. If validation fails with the error code "Sandbox receipt used in production," you should validate against the test environment instead.
This tip is useless since Apphud automatically handles sandbox and production environments.
App was rejected due to the use of ASIdentifierManager (IDFA)
Since Apphud SDK 2.1.0
ASIdentifierManager
is no longer used as well as AdSupport
framework:
pod update 'ApphudSDK'
"Failed to load SKProducts from the App Store" error
Failed to load SKProducts from the App Store, because product identifiers are invalid
error means that Product IDs provided in Apphud Product Hub are invalid. Please check the following:
- Check that the Product ID is correct and doesn't contain hidden spaces, tabs, etc.
- You agreed to the latest Apple Developer Program License Agreement.
- You completed all the financial agreements as described in the Agreements, Tax, and Banking.
- You use the correct bundle ID and signing credentials.
For more information please read the following.
"Attempted to decode store response
" error while fetching products
Attempted to decode store response
" error while fetching productsIf you encounter the decoding error Failed to load SKProducts from the App Store, error
with reason Attempted to decode store response
**** , that probably means that you are running the app in iOS Simulator which doesn't support App Store features. Try running on a physical device instead.
On iOS Simulator you can test App Store features using Local StoreKit configuration file.
Products are not appearing in Paywall screen
Keep in mind, that StoreKit products are not appearing immediately after the first app launch. The network request is made to App Store to fetch the products. And if your app displays a paywall screen immediately after launch, be ready to handle case, when products are fetched after the screen is shown.
You can do any of the following:
- Add observer for
Apphud.didFetchProductsNotification()
- Implement
func productsDidFetchCallback(_ callback: @escaping ([SKProduct]) -> Void)
- Implement
func apphudDidFetchStoreKitProducts(_ products: [SKProduct])
delegate method.
Once products are fetched, update your UI.
Products Loading Tip (Advanced)
Note
As you may know, at the launch of the app Apphud SDK fetches product identifiers from the server and then fetches SKProducts from App Store. If you wish to improve the product's loading speed, you can skip request to Apphud by hardcoding product identifiers, using
func apphudProductIdentifiers() -> [String]
delegate method. SeeApphudDelegate
for details.
Purchases are ready for sale, but not available in the app
When your app update is approved with new in-app purchases, they may not be available for purchase for the first few hours after approval. This is an App Store cache issue and not related to Apphud SDK (or any other SDKs). In most cases your in-app purchases are ready immediately after approval, however, it may take up to 24 hours.
Updated 11 months ago