Migrating from StoreKit 1 to StoreKit 2

While still supporting StoreKit 1

Nacho Soto

Nacho Soto

PublishedLast updated

StoreKit 1 vs. StoreKit 2

StoreKit has been with us since iPhone OS 3.0 launched in 2009. It was not without its flaws, and developers had to battle implementation and upkeep for over 12 years.

At WWDC 2021, we saw the introduction of the new StoreKit 2: a new Swift-only framework with modern async APIs. Since then, the RevenueCat team has been hard at work to support the new APIs. 

Why we support both

Using StoreKit 2 is not possible with Objective-C or if you need to support versions before iOS 15.0. So, migrating to StoreKit 2 might not be as straightforward for all apps with existing StoreKit 1 implementations.

This is another reason why using RevenueCat can vastly simplify in-app purchases. Our SDK provides abstractions that are backed by StoreKit 1 or StoreKit 2. Take, for example, the StoreProduct type:

1/// TypeAlias to StoreKit 1's Product type, called `StoreKit/SKProduct`
2public typealias SK1Product = SKProduct
4/// TypeAlias to StoreKit 2's Product type, called `StoreKit.Product`
5@available(iOS 15.0, tvOS 15.0, watchOS 8.0, macOS 12.0, *)
6public typealias SK2Product = StoreKit.Product
8/// Type that provides access to all of `StoreKit`'s product type's properties.
9@objc(RCStoreProduct) public final class StoreProduct: NSObject, StoreProductType {
11    let product: StoreProductType

This allows users to write code once (in either Objective-C or Swift) that can run on iOS versions as far back as 11.0.

Choosing an implementation

When version 4.0.0 of our iOS SDK launched, StoreKit 2 support was still in beta and therefore was opt-in only.

Internally, the SDK uses 3 different settings:

1/// Defines when StoreKit 2 APIs may be used
2enum StoreKit2Setting {
4    /// Never use SK2
5    case disabled
7    /// Use SK2 (if available in the current device) only for certain APIs that provide a better implementation
8    /// For example: intro eligibility, determining if a receipt has purchases, managing subscriptions.
9    case enabledOnlyForOptimizations
11    /// Enable SK2 in all APIs if available in the current device
12    case enabledForCompatibleDevices

Using this abstraction, we’re able to make our tests run in both StoreKit 1 and StoreKit 2, ensuring that all APIs produce consistent results.

StoreKit 2 has been disabled by default, but we provided a way to enable it:

2            with: .init(withAPIKey: "api_key")
3                .with(usesStoreKit2IfAvailable: true)
4                .build()

After many months of testing, and thanks to several of our users using this in production, we stopped considering this experimental.

Even though StoreKit 2 does not provide a replacement for every single API that StoreKit 1 has, we were also recently able to disable the majority of the StoreKit 1 wrappers. This means that when StoreKit 2 support is enabled, we no longer unnecessarily have StoreKit 1 and StoreKit 2 listeners.

StoreKit 1 vs 2: The future

It’s clear that Apple’s focus is now on StoreKit 2 moving forward: iOS 16 only brought improvements to StoreKit 2. We also see more reports of unreliable behavior from StoreKit 1 than StoreKit 2. For example, a common issue with StoreKit 1 is transactions not having an ID.

Additionally, some of the SDK implementations become much more accurate with StoreKit 2, like the implementation for checkTrialOrIntroDiscountEligibility.

There are also several workarounds for StoreKit 1, like properties that are marked as not-optional but that can actually return nil. These aren’t issues when using StoreKit 2.

For all these reasons, version 4.13.0 of our Purchases SDK has StoreKit 2 enabled by default. And, the best part is that RevenueCat customers don’t need to change any code.

In-App Subscriptions Made Easy

See why thousands of the world's tops apps use RevenueCat to power in-app purchases, analyze subscription data, and grow revenue on iOS, Android, and the web.

Related posts


Vision Pro apps powered by RevenueCat: What’s available on launch day

Over 160 of the first visionOS apps are powered by RevenueCat

Charlie Chapman

Charlie Chapman

February 2, 2024


How I successfully migrated my indie app to RevenueCat Paywalls

And how a simple experiment increased my LTV by 33%.

Charlie Chapman

Charlie Chapman

January 3, 2024

StoreKit 2 tutorial: implementing in-app purchases in a SwiftUI app

StoreKit 2によるiOSのアプリ内課金のチュートリアル


Josh Holtz

Josh Holtz

January 1, 2024

Want to see how RevenueCat can help?

RevenueCat enables us to have one single source of truth for subscriptions and revenue data.

Olivier Lemarie, PhotoRoomOlivier Lemarie, PhotoRoom
Read case study