In-App Purchases in iOS. Part 3: Testing purchases in TestFlight, Sandbox, and locally in Xcode

Sergey Zhuravel
14 min readNov 22, 2022

--

Hi, I am continuing a series of articles about IAP. In the previous articles, I showed how to create an IAP and how to add it to the project, I also told how to make a simple paywall and the purchase logic for it. After that, comes the testing phase — we need to make sure that everything works correctly. In this article, I will talk about several testing ways — local testing in Xcode, TestFlight, and Sandbox.

Links to all my articles about IAP:

  1. In-App Purchases in iOS. Part 1: Creating purchases and adding to the project.
  2. In-App Purchases in iOS. Part 2: Initialization and processing of purchases.
  3. In-App Purchases in iOS. Part 3: Testing purchases in TestFlight, Sandbox and locally in Xcode.
  4. In-App Purchases in iOS. Part 4: Receipt validation.

Overview

Use the Apple testing environments in Xcode and Sandbox to test your IAP implementation using the StoreKit framework. Comprehensive testing can help you to:

  • ensure a seamless purchase flow to provide a positive customer experience in your app
  • implement sound logic that covers all scenarios, such as purchases, restores, and subscription offers
  • validate that purchases behave correctly in production after your app is available in the App Store

The tools you need to test IAP, non-renewing subscriptions, and auto-renewable subscriptions from early development through beta testing are:

StoreKit testing in Xcode

  • For early development, continuous integration, and debugging.

Sandbox

  • For testing scenarios using data, you set up in App Store Connect.

TestFlight

  • For managing beta testing with internal and external testers.

Choose the tools that support the test scenarios you need. Make sure you’re able to perform the setup required for the tools you select.

During the early stages of development, you may not be ready to configure IAP in App Store Connect. StoreKit testing in Xcode lets you configure the information locally. You can test StoreKit transactions before you create Sandbox Apple IDs without a network connection. You can test your app in a Simulator or on real devices.

After you set up IAP in App Store Connect, start using the sandbox to test the product information your app will use in production. Testing in the Sandbox lets you test transactions from end-to-end and from the client to your server. You can also test any server-to-server functionalities your app depends on, such as receipt validation and App Store Server Notifications.

TestFlight lets you get feedback from members of your team or external testers. TestFlight uses the Sandbox environment for IAP. Transactions and purchases that occur in the Sandbox don’t incur charges. The following table compares the testing environments and features:

None of the testing environments charge users when they test buying a product. The App Store doesn’t send emails for purchases or refunds made in the testing environments.

Control the test environment

To set up and run test scenarios, you often need to control the test environment. For example, you may want to reset a test account to re-run the same test multiple times, or mimic actions users take outside your app that affect the test conditions. The following table shows the capabilities each tool has to control the test environment:

Test subscriptions and Ask to Buy

Depending on the IAP your app offers, you may need to test scenarios that involve auto-renewing subscriptions, introductory offers, promotional offers, and Ask to Buy. The following table lists test scenarios and whether they’re testable in the Sandbox or Xcode:

Testing in-app purchases in Xcode

Testing your StoreKit implementation in Xcode ensures that your app behaves correctly when your users perform various tasks associated with subscriptions and IAP transactions. Be sure to test a variety of IAP scenarios, such as receipt validation, promotional offers, interrupted purchases, introductory offers, subscription renewals, and purchase restoration.

StoreKit testing in Xcode is a local test environment for testing IAPs without requiring a connection to App Store servers. Set up IAPs in a local StoreKit configuration file in your Xcode project, or create a synced StoreKit configuration file in Xcode from your IAP settings in App Store Connect. After you enable the configuration file, the test environment uses this local data when your app calls StoreKit APIs.

Note: Enable Developer Mode to test your app on devices running iOS 16 and later, or watchOS 9 and later. For more information about how to enable Developer Mode, see Enabling Developer Mode on a device.

As you test transactions, the test environment displays a payment sheet with localized values and produces receipts for you to verify.

Testing IAP scenarios with StoreKit in Xcode is useful for:

  • developing features that use IAPs before configuring them in App Store Connect
  • testing locally when a network connection isn’t available
  • debugging in-app purchase use cases that are harder to set up in Sandbox, such as eligibility for promotional offers
  • viewing localized product information in the payment sheet
  • testing transactions end-to-end, including failed transactions.

Create a StoreKit configuration file

A StoreKit configuration file contains descriptions of IAPs, subscription groups, auto-renewable subscriptions, and non-renewing subscriptions. When the configuration file is active, StoreKit uses this data when your app calls StoreKit APIs in the test environment. There are two types of StoreKit configuration files: local and, in Xcode 14 and later, synced.

  • Set up a local configuration file if you haven’t set up your app in App Store Connect yet, or you want to try out new types of IAPs or subscriptions before you set them up in App Store Connect. The local data is convenient to edit in Xcode and stands in for the data that otherwise comes from App Store Connect.
  • Set up a synced configuration file if you have IAPs or subscriptions already set up in App Store Connect that you want to test in Xcode.

To create a StoreKit configuration file:

  1. Launch Xcode, then choose File > New > File.
  2. In the sheet that appears, enter storekit in the Filter search field.
  3. Select StoreKit Configuration File, then click Next.
  4. In the dialog, enter a name for the file. For a synced configuration file, select the checkbox, specify your Team and App in the drop-down menus that appear, then click Next. For a local configuration, leave the checkbox unselected, then click Next.
  5. Select a location, and click Create.
  6. Save the file to your project.

Once the file is created, all IAPs are synced to App Store Connect and appear in the file. Read my first article to find out how to create an IAP in App Store ConnectIf you rename the configuration file, be sure to keep its file extension .storekit.

Note: You can convert a synced configuration file to a local configuration file. If you want to sync again, create a new synced configuration file.

Set up a StoreKit configuration

To edit the settings in a local StoreKit configuration file, select the file in the Project navigator to open the custom editor. Click the Add button (+) in the editor to add product details to the configuration file.

Note: You can’t edit a synced configuration file unless you convert it to a local configuration file. To convert a synced configuration file, select the file, then choose Editor > Convert to Local StoreKit Configuration from the Xcode menu. Click Convert File in the confirmation dialog. When you are viewing a synced configuration file, click the Sync button in the bottom left corner to pull the latest updates from App Store Connect.

Enter the information in your local StoreKit configuration file manually. The product names, IDs, prices, localizations, and any other data you provide in the StoreKit configuration file don’t upload to App Store Connect and don’t appear in App Store-signed apps. App Store Connect data transfers only to a synced StoreKit configuration file, which you can’t edit in Xcode.

Tip: If you have a synced configuration file with items you want to test in a local configuration file, you may copy an item from your synced configuration file to your local configuration file. To do this, Control-click an item in your synced configuration file, and choose Copy. In your local configuration file, select where you want to place the item, and choose Edit > Paste from the Xcode menu.

Each IAP and non-renewing subscription have a reference name, product ID, and price. IAP and non-renewing subscriptions optionally can have localizations. This metadata shows up in the payment sheet after you click to buy a product in your app. Note that the price is a placeholder value that’s not connected to price tiers or real pricing information. However, it appears using the correct currency symbols for the storefront you’re testing.

For non-consumable IAPs and auto-renewable subscriptions, select Family Sharing to mark the product for sharing as the following image shows:

When you set up the first auto-renewable subscription, Xcode prompts you to create the first subscription group. After adding subscriptions to a group, the level you assign to each subscription determines their upgrade and downgrade options.

For auto-renewable subscriptions, set up introductory offers and promotional offers with the options available in App Store Connect. To begin testing, configure at least one IAP product.

Enable StoreKit testing in Xcode

To enable StoreKit testing in Xcode, your project must have an active StoreKit configuration file. By default, StoreKit testing in Xcode is disabled. To select a configuration file and make it active:

  1. Click the scheme to open the Scheme menu and choose Edit Scheme.
  2. In the scheme editor, select the Run action.
  3. Click the Options tab.
  4. For the StoreKit Configuration option, select a configuration file and click Close.

You can also add an existing StoreKit configuration file to the project from this menu. Choose a configuration file with a .storekit file extension.

An Xcode project can contain multiple StoreKit configuration files, but only one can be active at a time. When it’s active, build and run your app as usual. Instead of accessing App Store Connect or the Sandbox server, your app gets StoreKit data from the test environment.

Prepare to validate receipts in the test environment

StoreKit testing in Xcode generates locally signed receipts that your app validates locally. Obtain the certificate you need for local validation and add it to your project as follows:

  1. In the Xcode Project navigator, click the StoreKit configuration file.
  2. From the Xcode menu, choose Editor > Save Public Certificate.
  3. Select a location in your project to save the file.

Note: The test environment’s certificate is a root certificate. There’s no certificate chain to validate when you validate the receipt signature.

Be sure your code uses the correct certificate in all environments. Add the following conditional compilation block to your receipt validation code to select the test certificate for testing, and the Apple root certificate, otherwise:

#if DEBUG    
let certificate = "StoreKitTestCertificate"
#else
let certificate = "AppleIncRootCertificate"
#endif

Your code is ready to validate receipts by selecting the appropriate certificate in the test environment and production.

Manage transactions

Use the options in the transaction manager to perform steps in an in-app purchase flow that normally occur outside your app, such as approving, declining, or refunding a transaction. To open the transaction manager, choose Debug > StoreKit > Manage Transactions or press the button as shown in the screenshot below.

StoreKit Manage Transactions

The transaction manager lists all the transactions for the running app. If you have multiple apps running on multiple devices, select the app on the sheet to view its transactions. Use the transaction manager to perform these actions:

  • Filter transactions Type a search term in the filter box at the bottom of the dialog to narrow the number of transactions that display.
  • Inspect a transaction — Click a transaction, then view that transaction’s details in the inspector. Click the jump button next to a product or group to navigate to it in the configuration file in Xcode.
  • Delete a transaction — Select a transaction and click Delete to retest a scenario that the user can perform only once. For example, users can purchase a non-consumable product only once, so delete that transaction to retest the purchase. Delete subscription transactions to retest introductory offers. Refresh the receipts to see that the transactions no longer appear in your app.
  • Approve or Decline a transaction — Click Approve or Decline to resolve a pending transaction that’s testing an Ask to Buy scenario.
  • Refund a transaction — Click Refund to simulate a customer receiving a refund.
  • Resolve a transaction — Click Resolve to simulate a customer resolving an interrupted purchase. To simulate the interruption, choose Editor > Enable Interrupted Purchases.
  • Test a price increase — Select a subscription transaction, then click the Request Price Increase Consent button in the toolbar. Test using the price increase sheet that the system presents in your app, or use the buttons to simulate the user’s response from outside the app, such as from a push notification. Click the approve button to indicate that the user accepts the price increase. Click the decline button to simulate the user canceling the subscription.
StoreKit Manage Transactions

The test environment automatically syncs the transaction changes you make. You don’t need to rebuild and run your app.

Sandbox

Use the Apple sandbox environment to test your implementation of IAPs that use the StoreKit framework on devices with real product information from App Store Connect. Your development-signed app uses the sandbox environment when you sign in to the App Store using a Sandbox Apple ID.

To create a Sandbox Apple ID or a test account, go to App Store Connect:

  1. From Users and Access, click Sandbox Testers.
Create a Sandbox Apple ID

2. Click the add button (+).

3. Enter the tester information, then click Create.

The tester’s name, email, and password can’t be edited once the Sandbox Apple ID is created.

Sign in to the App Store with your Sandbox Apple ID

To run your app using your Sandbox Apple ID, build and run your app from Xcode.

In iOS and iPadOS, the Sandbox account appears in Settings > App Store after the first time you use the device to attempt a purchase in a development-signed app. There’s no need to sign out of the non-Sandbox Apple ID. Sign in using a Sandbox Apple ID.

Sign in to the App Store with your Sandbox Apple ID on iOS

After logging into the Sandbox account, you are all set to test your subscriptions.

Make an in-app purchase

The first time you make a purchase in a development-signed app, sign in to the App Store using your Sandbox Apple ID to begin testing. When you sign in, the text [Environment: Sandbox] appears, indicating that you’ve connected to the test environment. If [Environment: Sandbox] doesn’t appear, you’re using the production environment.

Important: When testing in-app purchases in the Sandbox environment, make sure you’re running a development-signed build of your app; production-signed builds use the production environment.

Subscription Duration within the Sandbox testing

You can choose a subscription renewal rate for each tester to speed up or slow down how often subscriptions renew. Subscriptions renew up to 12 times before auto-renewal turns off on the thirteenth renewal attempt.

By default, a one-month renewal lasts 5 minutes. If you want to speed up the renewal period, you can choose 3 minutes. If you want to slow down the renewal period, you can choose 15 minutes, 30 minutes, or an hour.

The columns in the chart below represent each of the accelerated renewal rates you can select. The corresponding test durations are listed underneath.

Subscription Duration within the Sandbox testing

Test IAPs for all regions

IAP products that you create through App Store Connect are available for sale in every App Store region. You may also maintain a list of product identifiers that you make available in specific regions. To test IAP in multiple regions using the same Sandbox Apple ID, open App Store Connect, click the Sandbox Apple ID, and change the App Store Country or Region setting.

To activate a Storefront after you change the region in App Store Connect, sign out of the Sandbox Apple ID account on the device and sign back in. The tester should see the IAPs appropriate to the region assigned to their Sandbox Apple ID. Changing the App Store Country or Region setting affects the storefront value in your app.

Clear the purchase history for a Sandbox Apple ID

You can clear the purchase history for a tester to continue testing with the same Sandbox Apple ID. Clearing purchase history will delete all past auto-renewable subscriptions and nonconsumables purchased by the selected testers in the sandbox environment. Customer accounts aren’t affected.

To clear tester purchase history:

  1. From Users and Access, under Sandbox, click Sandbox Testers.
  2. Click Edit.
Clear the purchase history for a Sandbox Apple ID

3. Check the boxes for each tester you want to modify and click Clear Purchase History.

Clear the purchase history for a Sandbox Apple ID

4. Click Clear Purchase History in the dialog that appears.

Clear Purchase History

Clearing the purchase history for Sandbox Apple IDs with a high number of purchases may take longer. When the process is complete, the transaction history and receipt are empty and the Sandbox Apple ID is eligible for introductory offers. The tester logged in with the Sandbox Apple ID can purchase subscriptions they were previously subscribed to without causing a duplicate purchase.

Note: Clearing the purchase history doesn’t affect IAPs that customers make on the App Store.

TestFlight

An application distributed by TestFlight will automatically use the production Sandbox environment. All testing steps will stay the same as the development sandbox environment. Users cannot be charged in a TestFlight build, but they can view the paywall and step through the purchase process without actually spending money.

TestFlight users don’t require a Sandbox account, but they will test against an automatically created Sandbox account. This means it’s no longer necessary to create test accounts in App Store Connect. Your TestFlight user is a legitimate App Store user, but doing IAPs made with beta builds is free it the beta version.

The duration of subscriptions is the same as in Sandbox testing. Check the table above in the Subscription Duration within the Sandbox testing section.

TestFlight behaves like a Sandbox but uses App Store work accounts. There are no other differences with Sandbox testing. For managing beta testing with internal and external testers, read Beta Testing Made Simple with TestFlight for more information.

In the next article, I will explain how to validate a purchase.

Contact me: My Twitter
Full source code: GitHub

--

--

Sergey Zhuravel

iOS Engineer @ Futurra Group | Reverse-Engineering iOS Apps