Why doesn’t Transaction.updates emit reliably?

I'm on macOS Sequoia Version 15.7.3 (24G419) and using Xcode Version 26.2 (17C52).

In my Xcode project, Transaction.updates and Product.SubscriptionInfo.Status.updates don’t seem to emit updates reliably.

The code below works consistently in a fresh Xcode project using a minimal setup with a local StoreKit Configuration file containing a single auto-renewable subscription.

class InAppPurchaseManager {
    static let shared = InAppPurchaseManager()

    var transactionTask: Task<Void, Never>?
    var subscriptionTask: Task<Void, Never>?

    init() {
        print("Launched InAppPurchaseManager...")

        transactionTask = Task(priority: .background) {
            for await result in Transaction.updates {
                print("\nReceived transaction update...")
                try? await result.payloadValue.finish()
            }
        }

        subscriptionTask = Task(priority: .background) {
            for await result in Product.SubscriptionInfo.Status.updates {
                print("\nReceived subscription update...")
                print("state:", result.state.localizedDescription)
            }
        }
    }

}

I initialise it in:

func applicationDidFinishLaunching(_ aNotification: Notification) {
    _ = InAppPurchaseManager.shared
}

I do not build any UI for this test. I open StoreKit Transaction Manager then click Create Transaction → select the product → choose Purchase (Default)NextDone. The console shows that it detects the initial purchase, renewals and finishes each transaction.

It also works even if I do not add the In-App Purchase capability.

In my actual project, the initial purchase is detected and finished, but renewals are not detected. Subsequent transactions then appear as unverified, presumably because the updates are not being observed so the transactions are not being finished.

What can I do to make this work reliably in my actual project?

For context, in the actual project:

  • I have a StoreKit Configuration file that is synced with App Store Connect
  • The In-App Purchase capability is enabled
  • The configuration file is selected in the scheme
  • The products in App Store Connect show “Ready to Submit”
  • Loading products works:
try await Product.products(for: ...)

Also, I use ProductView for the purchase UI. The first purchase works and is detected and finished, but subsequent renewals are not finished because the updates do not seem to be emitted.

Update the customer product status using

for await result in Transaction.currentEntitlements {
    // Verify transaction and append to the product items/subscription items.
}

Also its better to use @Observable class on your InAppPurchaseManager instead of a shared singleton, especially if your project is iOS 17+.

You would have:

var purchasedProducts: [Product] = []
var purchasedSubscriptions: [Product] = []

Check out tutorials online on how to create Observable StoreKit 2 manager.

Sorry, how would using the @Observable macro help in this case?

As I mentioned in my post, the InAppPurchaseManager works perfectly in a fresh Xcode project with a minimal setup.

Your listenerTask will update the purchasedProducts/purchasedSubscriptions. If there is any change in the Transaction.updates, you can update the array.

With Observable, your views will update accordingly to this change.

Take a look at the WWDC25 sample on Understanding StoreKit workflows.

https://developer.apple.com/documentation/StoreKit/understanding-storekit-workflows

Why doesn’t Transaction.updates emit reliably?
 
 
Q