Hey y'all,
I'm reaching out because of an observed issue that I am experience both in sandbox and in production environments. This issue does not occur when using the Local StoreKit configurations.
For context, my app only implements auto-renewing subscriptions. I'm trying to track with my own analytics every time a successful purchase is made, whether in the app or externally through Subscription Settings. I'm seeming too many events for just one purchase.
My app is observing Transaction.updates. When I make a purchase with Product.purchase(_:), I successfully handle the purchase result. After a few seconds, I receive 2-3 new transactions in my Transaction.updates, even though I already handled and finished the Purchase result.
The transactions seem to have the same transactionId, and values such as revocationDate, expirationDate, and isUpgraded don't seem to change between any of them.
For purchases made outside the app, I get the same issue. Transaction gets handled in updates several times.
Note that this is not an issue if a subscription renews. I use `Transaction.reason
StoreKit
RSS for tagSupport in-app purchases and interactions with the App Store using StoreKit.
Selecting any option will automatically load the page
Post
Replies
Boosts
Views
Activity
Hey y'all,
I'm reaching out because of an observed issue that I am experience both in sandbox and in production environments. This issue does not occur when using the Local StoreKit configurations.
For context, my app only implements auto-renewing subscriptions. I'm trying to track with my own analytics every time a successful purchase is made, whether in the app or externally through Subscription Settings. I'm seeming too many events for just one purchase.
My app is observing Transaction.updates. When I make a purchase with Product.purchase(_:), I successfully handle the purchase result. After about 10-20 seconds, I receive 2-3 new transactions in my Transaction.updates, even though I already handled and finished the Purchase result. This happens on production, where renewals are one week. This also happens in Sandbox, where at minimum renewals are every 3 minutes.
The transactions do not differ in transactionId, revocationDate, expirationDate, nor isUpgraded... so not sure why they're coming in through Transaction.updates if there are no "updates" to be processing.
For purchases made outside the app, I get the same issue. Transaction gets handled in updates several times.
Note that this is not an issue if a subscription renews. I use `Transaction.reason
I want to assume that StoreKit is a perfect API and can do no wrong (I know, a poor assumption but hear me out)... so where am I going wrong?
My current thought is a Swift concurrency issue. This is a contrived example:
// Assume Task is on MainActor
Task(priority: .background) { @MainActor in
for await result in Transaction.updates in {
// We suspend current process,
// so will we go to next item in the `for-await-in` loop?
// Because we didn't finish the first transaction, will we see it again in the updates queue?
await self.handle(result)
}
}
@MainActor
func handle(result) async {
...
await Analytics.sendEvent("purchase_success")
transaction.finish()
}
Description
SKTestSession.setSimulatedError() does not throw the configured error when testing StoreKit with the .loadProducts API in iOS 26.2. The simulated error is ignored, and products load successfully instead.
Environment
iOS: 26.2 (Simulator)
Xcode: 26.2 beta 2 (Build 17C5038g)
macOS: 15.6.1
Framework: StoreKitTest
Testing Framework: Swift Testing
base project: https://developer.apple.com/documentation/StoreKit/implementing-a-store-in-your-app-using-the-storekit-api
Expected Behavior
After calling session.setSimulatedError(.generic(.notAvailableInStorefront), forAPI: .loadProducts), the subsequent call to Product.products(for:) should throw StoreKitError.notAvailableInStorefront.
Actual Behavior
The error is not thrown. Products load successfully as if setSimulatedError() was never called.
Steps to Reproduce
Create an SKTestSession with a StoreKit configuration file
Call session.setSimulatedError(.generic(.notAvailableInStorefront), forAPI: .loadProducts)
Call Product.products(for:) with a valid product ID
Observe that no error is thrown and the product loads successfully
Sample Code
import StoreKitTest
import Testing
struct SKDemoTests {
let productID: String = "plus.standard"
@Test
func testSimulatedErrorForLoadProducts() async throws {
let storeKitConfigURL = try Self.getStoreKitConfigurationURL()
let session = try SKTestSession(contentsOf: storeKitConfigURL)
try await session.setSimulatedError(
.generic(.notAvailableInStorefront),
forAPI: .loadProducts
)
try await confirmation("StoreKitError throw") { throwStoreKitError in
do {
_ = try await Self.execute(productID: productID)
} catch let error as StoreKitError {
guard case StoreKitError.notAvailableInStorefront = error else {
throw error
}
throwStoreKitError()
} catch {
Issue.record(
"Expect StoreKitError. Error: \(error.localizedDescription)"
)
}
}
#expect(session.allTransactions().isEmpty)
}
static func execute(productID: String) async throws {
guard
let product = try await Product.products(for: [productID]).first(
where: { $0.id == productID })
else {
throw NSError(
domain: "SKDemoTests",
code: 404,
userInfo: [NSLocalizedDescriptionKey: "Product not found for ID: \(productID)"]
)
}
_ = product
}
static func getStoreKitConfigurationURL() throws -> URL {
guard
let bundle = Bundle(identifier: "your.bundle.identifier"),
let url = bundle.url(forResource: "Products", withExtension: "storekit")
else {
fatalError("StoreKit configuration not found")
}
return url
}
}
Test Result
The test fails because the expected StoreKitError.notAvailableInStorefront is never thrown.
Question
Is this a known issue in iOS 26.2 / Xcode 26.2 beta 2, or is there a different approach required for simulating errors with SKTestSession in this version? Any guidance would be appreciated.
Feedback Assistant report: FB21110809
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) → Next → Done. 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.
Hi everyone,
I’m implementing subscriptions using StoreKit v2, and I’ve noticed a behavior change starting with iOS 26.1.
I’d like to ask if anyone else has experienced the same issue.
■ Issue
Immediately after purchasing a new subscription,
the value of auto_renew_status (or autoRenewStatus) returned in the receipt is 0 (auto-renew OFF).
This issue occurs on iOS 26.1.
On iOS 26.0 and earlier, the same parameter returned 1 (auto-renew ON) right after purchase.
Sometimes, after executing a “restore” operation, the value changes to 1 later.
Since we’ve been using this parameter to determine whether a user’s subscription is active or not,
the current behavior is causing some difficulties on our end.
■ Questions
Has anyone else observed this issue (where autoRenewStatus is 0 immediately after purchase on iOS 26.1 or later)?
How are you handling or working around this behavior in your implementation?
If autoRenewStatus is unreliable, we’re considering determining the subscription state based on receipt fields instead.
Would this approach be reasonable?
"status" is 1 (indicates active subscription)
"expire_time" is in the future
"deleted_at" is null
If anyone has encountered the same behavior or knows of any Apple-recommended implementation approach,
I’d really appreciate your insights.
Thank you! 🙏
Environment
OS: iOS 26.2 ~ 26.3
SDK: Xcode 16.4 (Target: iOS 17.6)
Framework: StoreKit 2
Environment: Production (Cannot reproduce in Sandbox or Xcode Configuration)
Issue Description
We are encountering a critical purchase failure that occurs exclusively in the Production environment.
When a user who has a "Pending Downgrade" (scheduled for the next renewal date) attempts to re-purchase their current higher-tier product to cancel the downgrade, StoreKit 2 returns an error.
Steps to Reproduce
User is currently on "Product A" (Higher Tier).
User schedules a downgrade to "Product B" (Lower Tier). The status changes to "Pending Downgrade".
User attempts to purchase "Product A" again via Product.purchase().
The system purchase sheet appears, and the user confirms the purchase.
Immediately after authentication, a system alert from StoreKit appears saying: "Cannot process request at this time. Please try again later." (現在リクエストを一時的に処理できません。しばらくしてからもう一度お試しください。)
After dismissing the alert, the app receives StoreKitError code 2 (unknown) with the localized message: "Request could not be completed" (リクエストを完了できません).
Technical Observations
Transaction.currentEntitlements: Does not change.
App Store Server Notifications (V2): No notifications are sent to our server.
Sandbox Behavior: Works perfectly. Re-purchasing Product A successfully cancels the downgrade and the subscription remains at the Higher Tier.
AppStore.sync(): Running a manual sync does not resolve the pending state after the error.
Question
Since we cannot debug production-level logs, we are stuck. Is this a known regression in the StoreKit 2 commerce engine regarding state synchronization for downgrades? Has anyone found a workaround for this specific scenario?
Any insights would be greatly appreciated.
Hello,
In my iOS app, I have a customer center where the user can see some details about its current subscription. I display things like the billing period, the price, the introductory offer state, the renewal date if it's not cancelled or the expiration date if it's cancelled, etc. From this screen, the user can open the subscription management sheet.
I want to detect if the user cancels the subscription from this sheet or from the App Store (when the app is running) so I can refresh the information displayed on my customer center.
I checked the asynchronous sequences provided by StoreKit 2 like Transaction.updates or Product.SubscriptionInfo.Status.updates and tested with a Sandbox account on my physical device with the app debugged using Xcode. But I noticed these sequences don't emit when I cancel the subscription in Sandbox.
Is this the expected behavior?
Is there a way to observe in real time if a user cancels the subscription?
I can still manually check when the sheet is dismissed but it's not ideal because I want to know even if the user cancel from outside of the app with the app running.
Thank you,
Axel
Topic:
App & System Services
SubTopic:
StoreKit
Tags:
Subscriptions
StoreKit Test
StoreKit
In-App Purchase
I am developing a mobile application using Flutter and plan to implement in-app subscriptions for both iOS platforms. I would like to request guidance on the following:
Technical Implementation:
Recommended best practices for implementing auto-renewable subscriptions in Flutter apps
StoreKit 2 integration requirements and compatibility considerations
Server-to-server notification setup and endpoint requirements
Testing Procedures:
Sandbox environment configuration and testing workflow
TestFlight testing requirements for subscription features
Recommended testing scenarios before production release
Required Documentation and Accounts:
Complete list of required agreements (Paid Applications Agreement, etc.)
Banking and tax information requirements
Privacy policy and terms of service specifications for subscription apps
App Review guidelines specific to subscription-based apps
Subscription Management:
Grace period implementation requirements
Handling subscription cancellations and refunds
Promotional offers and introductory pricing setup
Could you please provide documentation or direct me to the appropriate resources? Additionally, if there are any specific requirements for Flutter-based applications, I would appreciate that information.
Application Details:
Platform: iOS (Flutter framework)
Subscription Type: Auto-renewable subscriptions
There is a warning message displays in my itune connect's In App Purchase page but there is nothing highlighted in the table. This is very stange. Is there anyone having the same problem? Or can anyone help?
Hello,
My app was rejected on iPad (iPad Air 11-inch M3, iPadOS 26.2.1) with two related issues:
Guideline 2.1 – Performance – App Completeness
“The app exhibited one or more bugs that would negatively impact users.
Bug description: the premium subscription cannot be loaded properly.”
Guideline 3.1.2 – Business – Payments – Subscriptions
“The submission did not include all the required information for apps offering auto-renewable subscriptions.”
I am using StoreKit 2 with SubscriptionStoreView to present the auto-renewable subscription.
During development:
Subscriptions load correctly in the simulator (sandbox).
On real devices, I test without a local StoreKit configuration file to fetch products from App Store Connect.
The subscription UI (title, duration, price) displays correctly when products are returned.
At the time of review, the Paid Apps Agreement was not active.
I suspect this may have caused the subscription products to fail loading on the review device.
Since then:
Paid Apps Agreement is now Active. SubscriptionStoreView should automatically show required metadata.
Because the subscription failed to load on iPad during review, the required information (title, price, duration) was not visible, which likely triggered the 3.1.2 rejection.
Additionally, in TestFlight I sometimes see inconsistent behavior where the app appears but cannot be installed (“App Not Available”).
Also, my app was rejected, but the subscription is still waiting for review.
I would really appreciate guidance on the following:
Am I potentially missing any required configuration that could prevent products from loading in production?
Is there any propagation delay after activating the Paid Apps Agreement that could affect product availability?
If I am overlooking something in configuration or testing, please let me know what I should specifically verify before resubmitting.
Thank you very much for your help.
Topic:
App & System Services
SubTopic:
StoreKit
Tags:
Subscriptions
StoreKit
In-App Purchase
TestFlight
Can anyone advise on this? We distributed promotional trial codes for our app Ask Dolly. These 1-month free trials are set to renew and charge users in March 2026.
A segment of users redeemed the promo codes but never created accounts or opened the app. We don't have their contact information to notify them. Our CEO has directed us to prevent these inactive subscriptions from renewing to avoid charging users who never engaged with the service.
We've downloaded the Subscription and Offer Code Redemption reports from App Store Connect, but cannot map Apple's Subscriber IDs to our user database (we only store Transaction IDs). This prevents us from identifying which specific subscriptions to cancel.
What We Need: Assistance preventing renewals for promotional subscriptions where users have had zero app sessions/opens as of the end of February.
These trials will start to renew on March 3, 2026. We need to resolve this before then to avoid charging inactive users.
Can you help us either:
Cancel subscriptions associated with promo codes that show zero app engagement, or
Provide guidance on how to programmatically identify and cancel these subscriptions?
Topic:
App & System Services
SubTopic:
StoreKit
SKProductsRequest always returns as USD not local currency for debug environment and even some time it fails. This is only happening for debug or TestFlight build.
Hi Everyone, Need help 🙌
Could someone help how to test pending purchases in Sandbox accounts ? Can test ask to buy flow ? if yes how, could not find any information about that.
Background:
My app uses a third-party SDK for payments, and it uses Original StoreKit internally for IAP payments. Now I'm getting ready to migrate to StoreKit2, and during the transition, users may use either method to initiate payments, and there's no way to avoid the coexistence of StoreKit2 and Original StoreKit.
Problem:
When a user has an unfinished transaction, if the app is restarted, both StoreKit2 and Original StoreKit will receive a notification of the transaction:
Original StoreKit's '-paymentQueue:updatedTransactions:' method
StoreKit2's 'Transaction.updated' method
resulting in duplicate calls to the shipping API.
My current treatment is to only add '-paymentQueue:updatedTransactions:' to listen for unfinished transactions. Even if the user is using StoreKit2 to initiate the payment, if the transaction is not Finished, it will be fetched via this method after restarting the app to process this transaction.
Is this approach feasible and are there any best practices for this scenario?
To summarize:
Is it feasible to fetch unfinished StoreKit2 transactions via Original StoreKit methods when StoreKit2 coexists with Original StoreKit? Is there a recommended way
This is a copy of a reply to this post.
https://developer.apple.com/forums/thread/722222?page=1
I'm posting as new in the hope someone might have more up-to-date information, as I'm pulling out what little hair I have left.
I'm using Storekit 2, testing in Xcode with a local Storekit config file. I have created a very minimal system to investigate this issue. I have a SwiftUI-based window using SubscriptionStoreView, and my app set up with the usual listener. I have four types of auto renewing subscription, configured in the local Storekit config file.
With my app running, I subscribe to the lowest-level subscription I offer, via the SubscriptionStoreView. Notification of the inital purchase arrives, but subsequent auto-renewals do not trigger any action in my listener for Transaction.updates. They arrive as expected in the Transaction Manager. Radio silence in my listener.
If I upgrade one subscription (via my SubscriptionStoreView) I see this reflected in the UI immediately, and also in the Transaction Manager, but the update that arrives in Transaction.updates refers to the old subscription, and has the isUpgraded flag set to false.
Also, can anyone remind me what the grey warning triangle next to entries in the Transaction Manager means. I'm assuming it means unfinished, as that's what the sidebar indicates.
Can the testing system really be this broken, or am I wildly off the mark? Unless I'm doing something fundamentally wrong this all seems extremely flakey, but happy to be proved wrong.
I find this all rather unsettling if I can't test reliably, and am concerned that I my app may end up in this situation if I use storekit 2:
https://stackoverflow.com/questions/73530849/storekit-renewal-transactions-missing-in-transaction-all-or-transaction-updates
Hello,
I’m experiencing repeated rejections related to Guideline 2.1 – App Completeness for an iOS app using auto-renewable subscriptions, and I’m struggling to understand what is missing, as the purchase flow works correctly in sandbox and TestFlight.
App setup:
iOS app built with React Native (Expo + react-native-iap)
Auto-renewable subscriptions:
• Monthly: €4.99
• Yearly: €39.99
Paid Apps Agreement accepted
Subscriptions configured and active in App Store Connect
Privacy Policy and Apple Standard EULA included:
• Visible inside the app on the subscription screen
• Added in App Store metadata
What App Review reports:
App Review states they are unable to buy the in-app purchase, resulting in a rejection under Guideline 2.1 (App Completeness).
What works correctly:
getSubscriptions() returns valid products in sandbox
Subscription titles, prices, and durations are displayed in the app UI
requestSubscription() is triggered when tapping the subscribe button
Apple purchase sheet appears and completes successfully in:
• Sandbox testing
• TestFlight (external testers)
What I’ve verified:
No conditional logic blocks purchases in review builds
Purchase button always calls requestSubscription
purchaseUpdatedListener and purchaseErrorListener are correctly registered
No hardcoded prices; prices come from StoreKit
Same behavior on iPhone and iPad
Question:
Is there any known limitation or requirement in the App Review environment for auto-renewable subscriptions that differs from sandbox/TestFlight when using a custom subscription UI (not SubscriptionStoreView)?
If App Review requires a specific implementation detail (StoreKit 2, SubscriptionStoreView, or something else), I would really appreciate clarification, as this is not explicitly stated in the rejection.
Thank you for your help.
I’d like to confirm the expected behavior of StoreKit 2 in the Sandbox environment regarding unfinished consumable transactions across devices.
Scenario:
Device A and Device B are signed in with the same Sandbox Apple ID
A consumable in-app purchase is completed on Device A
The transaction may be verified or unverified, but transaction.finish() is not called
The app is then launched on Device B and listens for Transaction.updates
Question:
In this scenario, is it expected that Device B will or will not receive a callback for this unfinished consumable transaction?
Or is it by design that unfinished consumable transactions are not guaranteed to be delivered across devices, regardless of verification state?
Topic:
App & System Services
SubTopic:
StoreKit
Our app is supposed to be removed from sale on May 31st.
Subscriptions our app is offering will also be removed on May 1st one month before our app removal.
I would like to know if AppStoreServerNotificationV2 EXPIRED event will be sent to a specified endpoint after the removal of these subscriptions.
I think each subscription will be canceled automatically from May 1st to May 31st and it will send EXPIRED event to our server, but is it true?
Thank you in advance.
Topic:
App & System Services
SubTopic:
StoreKit
Tags:
Subscriptions
Developer Tools
App Store Server Notifications
**Environment
Platform:** iOS
Distribution: TestFlight
Product type: Consumable In-App Purchase
Account used for testing: Real Apple ID (not Sandbox)
StoreKit: StoreKit 1
iOS version: iOS 17+ (also reproduced on earlier versions)
Issue Description
We are encountering an issue when testing consumable in-app purchases in a TestFlight build using a real Apple ID.
Under normal circumstances, consumable products should be purchasable repeatedly. However, in TestFlight, after a successful purchase flow, the same product may become unavailable for repurchase, and the transaction appears to be stuck, even though:
• finishTransaction: is correctly called
• The transaction state is .purchased
• No pending transactions are left in the payment queue
Once this happens, subsequent purchase attempts result in behavior similar to a non-consumable product (e.g. “already purchased” or no purchase UI shown).
I had published an App, and my app has App Clip supported. The issue I faced is that I had received complaints where the user keep seeing the pop up "Apple Media Services Terms and Conditions Have Changed" when user clicked on the "Open" Button in the App Clip.
What we had tried so far:
Let user switch the Apple Id's region to our supported region.
Let user try to log out and log in to Apple Id within the supported region.