---
title: Getting started with In-App Purchase using StoreKit views
framework: storekit
role: article
role_heading: Article
path: storekit/getting-started-with-in-app-purchases-using-storekit-views
---

# Getting started with In-App Purchase using StoreKit views

Set up an in-app store using SwiftUI and StoreKit views.

## Overview

Overview StoreKit provides a streamlined system for building basic In-App Purchase (IAP) capabilities that allow you to provide purchases in your app and process transactions using simple SwiftUI views. You can use this capability to build a basic store with default styling, or you can customize your store’s experience using the full, expressive capabilities of SwiftUI. Choose your product types StoreKit supports the following product types, and StoreKit views can display all of them without any custom programming: Prototype your in-app store offline With StoreKit, you can create a file that allows you to prototype and test your In-App Purchase code in Xcode without needing to set up products in App Store Connect. Xcode calls this a StoreKit local configuration; to create a local configuration file, follow these steps: Open your app’s Xcode project. Create the local StoreKit configuration by selecting File > New > File From Template. In the sheet that appears, enter storekit in the Filter search field. Click the StoreKit Configuration File, then click Next. In the dialog, enter a name for the file, for example LocalConfiguration.storekit. Leave the configuration sync checkbox unchecked and click Next. Select a location for your file in your app’s project, then click Create to save the file. For more information about setting up a local configuration file, see Setting up StoreKit Testing in Xcode. This local configuration file allows you to experiment with product IDs and various purchase types offline. To use the product IDs in a published app, create the same product IDs in App Store Connect after you finish prototyping. Choose IDs for your products In your app, define products that someone can buy, in order to prototype your store. Choose descriptive product IDs that are easy for you to read and understand. In this example, the product IDs describe the product type they represent. Although you could write product IDs in your code as an array of strings, defining an enumeration whose raw value is a string can help make your code easier to read. For example, when you add a new product, any switch that handles product IDs but omits the new product produces a compile-time error. enum ProductID: String {     case consumable = "consumable"     case consumablePack = "consumable_pack"

case nonconsumable = "nonconsumable"

case subscriptionMonthly = "subscription_monthly"     case subscriptionYearly = "subscription_yearly"     case subscriptionPremiumYearly = "premium_subscription_yearly" } note: In a production app, consider fetching the list of product IDs programmatically — either from App Store Connect, or from your own server. This approach lets you enable and disable products without recompiling your app. For more information, see Configure In-App Purchase settings. Monitor transactions in your app StoreKit provides several asynchronous sequences that provide your app with information and updates. For example, the class below checks unfinished and currentEntitlements at startup, and continues to check updates in the background while the app is running. import Foundation import Observation import StoreKit

@MainActor @Observable final class Store {     private let defaultsKey = "com.example.consumable count"     private let nonConsumableDefaultsKey = "com.example.nonconsumable"

public var consumableCount: Int {         willSet {             UserDefaults.standard.set(newValue, forKey: defaultsKey)         }     }     public var boughtNonConsumable: Bool = false     public var activeSubscription: String? = nil

init() {         self.consumableCount = UserDefaults.standard.integer(forKey: defaultsKey)  // Returns 0 on first app launch.

// Because the tasks below capture 'self' in their closures, this object must be fully initialized before this point.         Task(priority: .background) {             // Finish any unfinished transactions -- for example, if the app was terminated before finishing a transaction.             for await verificationResult in Transaction.unfinished {                 await handle(updatedTransaction: verificationResult)             }

// Fetch current entitlements for all product types except consumables.             for await verificationResult in Transaction.currentEntitlements {                 await handle(updatedTransaction: verificationResult)             }         }         Task(priority: .background) {             for await verificationResult in Transaction.updates {                 await handle(updatedTransaction: verificationResult)             }         }     } } The handle(updatedTransaction:) method handles new verification results from all three sources of updates, to provide access to newly purchased content. For example, this work could include allocating consumable in-game coins, or delivering an in-game object. private func handle(updatedTransaction verificationResult: VerificationResult<Transaction>) async {     // The code below handles only verified transactions; handle unverified transactions based on your business model.     guard case .verified(let transaction) = verificationResult else { return }

if let _ = transaction.revocationDate {         // Remove access to the product identified by `transaction.productID`.         // `Transaction.revocationReason` provides details about the revoked transaction.         guard let productID = ProductID(rawValue: transaction.productID) else {             print("Unexpected product: \(transaction.productID).")             return         }

switch productID {         case .consumable:             consumableCount -= 1         case .consumablePack:             consumableCount -= 10         case .nonconsumable:             boughtNonConsumable = false         case .subscriptionMonthly, .subscriptionYearly, .subscriptionPremiumYearly:             // In an app that supports Family Sharing, there might be another entitlement that still provides access to the subscription.             activeSubscription = nil         }         await transaction.finish()         return     } else if let expirationDate = transaction.expirationDate, expirationDate < Date() {         // In an app that supports Family Sharing, there might be another entitlement that still provides access to the subscription.         activeSubscription = nil         return     } else {         // Provide access to the product identified by transaction.productID.         guard let productID = ProductID(rawValue: transaction.productID) else {             print("Unexpected product: \(transaction.productID).")             return         }         print("transaction ID \(transaction.id), product ID \(transaction.productID)")         switch productID {         case .consumable:             consumableCount += 1         case .consumablePack:             consumableCount += 10         case .nonconsumable:             boughtNonConsumable = true         case .subscriptionMonthly, .subscriptionYearly, .subscriptionPremiumYearly:             // In an app that supports Family Sharing, there might be another entitlement that already provides access to the subscription.             activeSubscription = transaction.productID         }         await transaction.finish()         return     } } Define products in the local StoreKit configuration file Before moving on to the views that display these products, define these products in the local configuration file you created earlier. To create the local products, follow these steps: In Xcode, open the local StoreKit configuration file you created earlier. In the lower left corner click the plus (+) button; select the kind of product to add. Edit the new product name, product ID string, price, and other properties. Repeat steps 2 and 3 with additional product ID strings, and product types as needed.

Create SwiftUI views that display your products After completing the local configuration, you can show all of your products on one page with a simple, compact SwiftUI view. import StoreKit import SwiftUI

struct AllProductsView: View {     // Your app's data store.     @Environment(Store.self) private var store: Store

var body: some View {         @Bindable var store = store         VStack {             // ProductID.all is an array of your product ID strings.             StoreView(ids: ProductID.all)                 .storeButton(.hidden, for: .cancellation)                 .storeButton(.visible, for: .restorePurchases)         }         .padding()     } } Here, the StoreView view from StoreKit constructs a page and lays out a grid that contains each product, as shown in the following screenshot:

To show a specific subset of your available products, use the same view structure, but change the list of product IDs you provide to the StoreView(). So, change store.allProductIDs to another array of product IDs. For example, the subscriptionProductIDs array contains only subscription purchase types, so replace store.allProductIDs with the subscriptionProductIDs array to show subscriptions as shown here.

For more information on StoreKit Testing in Xcode, see Setting up StoreKit Testing in Xcode. For more information on the presentation of In-App purchase products, see Human Interface Guidelines > In-App Purchase. For more information on creating products in App Store Connect, see Configure In-App Purchase settings.

## See Also

### In-App Purchase

- [In-App Purchase](storekit/in-app-purchase.md)
- [Understanding StoreKit workflows](storekit/understanding-storekit-workflows.md)
