Implementing subscriptions In-App Purchases with StoreKit 2

Implementing subscriptions In-App Purchases with StoreKit 2

Learn how to start selling subscriptions In-App Purchases in your SwiftUI app.

The App Store supports multiple ways of monetizing your apps. You have a wide variety of choices, ranging from making your app paid upfront to offering subscriptions for recurring access.

Subscriptions are commonly used when users pay on a recurring basis, for example to access premium features, ongoing content, or services that are continuously maintained.

In this tutorial, we explore how to get started with subscription In-App Purchases using StoreKit 2. You will create a subscription group with multiple subscription options and present Apple’s native subscription store inside your app.

The version of Xcode used is 26.2, and iOS 26.

The goal of the tutorial is to guide you through creating, configuring, and testing subscription In-App Purchases from Xcode to App Store Connect. By the end, you will have implemented a complete subscription purchase setup using StoreKit 2.

Before We Start

To follow this tutorial successfully, basic familiarity with Xcode and SwiftUI is helpful, although no prior StoreKit knowledge is required.

First, create a new project, let’s call it “PhotoEditor”. Now add a new folder called “Store”. This is where all your purchase-related management files will live. In iOS, Apple provides you with a framework, called StoreKit. This is the framework that gives everything you need to sell content in your apps with In-App Purchases. For StoreKit to know about the available In-App Purchases in your app, you need a StoreKit configuration file.

There are no additional assets or starter projects required for this tutorial.

Step 1 – Create the StoreKit Configuration File

Choose “New File from Template”, then search for “StoreKit” in the top-right search bar. In our example, we choose the name “PhotoEditor.storekit”. Make sure not to select “Sync this file with an app in App Store Connect.” You don’t need this for local testing, and enabling it only adds unnecessary complexity.

After creating the file, click the “+” button in the bottom-left corner and then “Add Subscription Group” from the popover menu. Now you have to give your new subscription group a “Reference Name”, which is simply a human-readable name so you can easily identify the group later. You can choose “PhotoEditor Plus”, since this subscription group will contain all subscription options for PhotoEditor+.

Next, select the subscription group, click the “+” button again, and then “Add Auto-Renewable Subscription” from the popover menu. Now you have to give your first subscription a “Reference Name”. You can choose “PhotoEditor Plus Monthly”, since this will be the monthly option. You also have to add a “Product ID,” which must be unique across the entire App Store — similar to how your app’s bundle identifier works. A good rule of thumb is to take your app’s bundle identifier and append another component, e.g. .Plus.Monthly.

Now repeat the same step and add a second auto-renewable subscription to the same subscription group. Choose “PhotoEditor Plus Yearly” as the reference name. For the “Product ID”, you again take your app’s bundle identifier and append another component, e.g. .Plus.Yearly.

Now you successfully created your subscription group with two subscriptions. The last thing you need to do to be able to show this as an option to a user in your app, is setting a “Display Name” and “Description”. For the subscription group, I choose “PhotoEditor+” as the Display Name and “Export as many pictures as you want” as the Description. For the monthly subscription, I choose “PhotoEditor+ Monthly” as the Display Name and “Export as many pictures as you want” as the Description. For the yearly subscription, I choose “PhotoEditor+ Annual” as the Display Name and “Export as many pictures as you want” as the Description.

Step 2 – Present the Subscriptions in ContentView

Now you can go to your ContentView.swift and remove everything and add this block of code

// 1
import StoreKit
import SwiftUI

struct ContentView: View {
    // 2
    @State private var showSubscriptionStore: Bool = false
    
    var body: some View {
        // 3
        Button {
            showSubscriptionStore.toggle()
        } label: {
            Text("Subscribe to PhotoEditor+")
        }
        // 4
        .buttonStyle(.borderedProminent)
        // 5
        .sheet(isPresented: $showSubscriptionStore) {
            SubscriptionStoreView(groupID: "4C765C93")
        }
    }
}
  1. import StoreKit is required to access StoreKit views such as SubscriptionStoreView.
  2. The state property controls whether the subscription store sheet is presented.
  3. The button triggers the presentation of the subscription store.
  4. A prominent button style makes the call to action clearly visible.
  5. SubscriptionStoreView(groupID: ...) displays all subscriptions belonging to the specified subscription group.

Step 3 – Connect the StoreKit Configuration File

When the preview canvas on the right finishes re-rendering, you will see that your subscriptions are not shown, even though you correctly passed the subscription group identifier to SubscriptionStoreView. This happens because your app doesn’t yet know that you have a local StoreKit configuration file where the subscription group and its subscriptions are defined. Instead, it tries to load the subscriptions from App Store Connect, where they don’t exist yet, so a placeholder view is shown.

To fix that, you tap on PhotoEditor in the top bar and then choose “Edit Scheme”. Under Options, you will find a dropdown menu next to “StoreKit Configuration”, where you can select the configuration file you just created earlier. If you close the view and switch back to the Preview Canvas, your subscriptions should now automatically be displayed with their display names, descriptions, and prices.

Step 4 – Test the Subscription on Device

Now you can run the app on your device to test the subscription. When you tap the button titled “Subscribe to PhotoEditor+”, the subscription store sheet will come up, showing the available subscription options.

If you select one of the subscriptions and tap the subscribe button, a native payment sheet will come up, informing you that you won’t be charged and that this is for testing purposes only.

After confirming the purchase, another dialog confirms that the subscription purchase was successful.

<IMAGE: 3_subscription_confirmation_alert>

When you re-run the app on your device, you’ll notice that the subscription is now marked as active. If you want to test different scenarios, you probably want to be able to reset the subscription state. One solution would be to delete and re-install the app. But this is not nice to do every time you want to test something you changed. Luckily, Xcode includes a handy tool to inspect and manage all StoreKit transactions made within your app. It’s tucked away in the “Debug” menu. You need to select “StoreKit” and then tap on “Manage Transactions”.

This opens a new window where you can see your device and the “PhotoEditor” app on the right hand side. When you tap on it, all subscription transactions will be shown in the center section. If you select one of the subscriptions, you can see more details on the left hand side.

Select the subscription and use the available actions to expire, revoke, or refund it. This resets your app’s subscription state so you can test the flow again. Especially when testing App Store Connect–synced subscriptions later, this tool becomes essential for quickly cycling through different subscription states.

Step 5 – Create the Subscription in App Store Connect

Once you’re done testing locally, it’s time to create the real subscriptions in App Store Connect.

Open App Store Connect, navigate to your app, and go to the “Subscriptions” section.

Here you first need to create a subscription group. Tap the “Create” button under “Subscription Groups” and give the group the same reference name you used in the local StoreKit configuration file, for example “PhotoEditor Plus”.

After creating the subscription group, you’ll land on the subscription group detail page. This is where all subscriptions belonging to this group are managed.

Now create your first subscription inside the group. Tap “Create” and choose a reference name such as “PhotoEditor Plus Monthly”. For the Product ID, use the same identifier you used locally by taking your app’s bundle identifier and appending another component, for example .Plus.Monthly.

After creating the subscription, you’ll be taken to its detail page. Here you first need to choose the subscription duration. Select “1 month” for the monthly subscription.

In the “Availability” section, choose the countries or regions where your subscription should be available. You can keep the default selection to make it available in all countries and regions.

Next, configure the subscription price. In the first step of the pricing flow, choose a base price in USD, for example $2.99.

In the second step, you can review or adjust the automatically generated regional prices. If you don’t need custom pricing per country, you can keep the suggested values.

The final step of the pricing flow shows an overview of all selected prices. Tap “Confirm” to create the subscription price.

The last step is creating the App Store localization that is shown to users when they view or purchase the subscription. Here you can copy and paste the display name and description from your local StoreKit configuration file, for example “PhotoEditor+ Monthly” as the display name and “Export as many pictures as you want” as the description.

Repeat the same process to create the yearly subscription inside the same subscription group, using a product ID that appends .Plus.Yearly to your app’s bundle identifier, selecting a one year subscription duration, and choosing $29.99 as the price.

Step 6 – Switch Back to App Store Connect Products

Now your subscriptions are ready to be used inside your app. To do so, tap on PhotoEditor in the top bar and then choose “Edit Scheme”. Under “Options”, you will find the dropdown menu next to “StoreKit Configuration”, where you now select “None” again. From this point on, your app will load subscription products directly from App Store Connect instead of the local StoreKit configuration file.

Now you can run the app again and test the subscriptions loaded from App Store Connect. Just like when testing subscriptions locally, no real charge will be made while testing.

Final Result

And that’s it, you now know how to set up and test subscription In-App Purchases using StoreKit 2. We started with a local StoreKit configuration in Xcode, created a subscription group with multiple subscription options, and tested the subscription flow safely on device without charging anything. Then we moved on to App Store Connect, recreated the same subscriptions there, assigned pricing, added localizations, and switched the app to load products directly from App Store Connect.

The workflow of using a local StoreKit configuration first and then mirroring the setup in App Store Connect is the foundation for every subscription-based monetization setup you’ll build in the future. Once you understand how these pieces fit together, working with subscriptions becomes much more predictable.

With this in place, you can start expanding your subscription offerings and iterating on pricing and presentation. And the best part is that none of this requires complicated backend work. StoreKit gives you everything you need to get started.

Where to Go Next?

Here are helpful resources to continue learning about StoreKit and monetization:

These resources can help you expand your monetization setup or explore other types of In-App Purchases.