Hello everyone,
I’m currently stuck in App Review and would appreciate input from anyone who has dealt with a similar situation.
App setup
iOS app, SwiftUI, StoreKit 2
No user accounts (no login, no username/password, no backend)
No subscriptions
Monetization model:
App was paid before version 1.0.5
Since 1.0.5 the app is free
Unlocking full functionality is done via a non-consumable, one-time IAP (“Pro Unlock”)
Existing users who bought the app when it was paid are automatically granted Pro access
New users get a 24-hour local trial, then must purchase the non-consumable IAP
All state is local / device-based, no server
There is no concept of an account, subscription renewal, or expired subscription in the app.
Rejection from App Review
Apple rejected the app with the following message:
Guideline 2.1 – Information Needed
We are not able to continue our review because we need access to a demo account with an expired subscription to review the entire purchase flow.
Please provide a user name and password for a demo account with expired subscriptions in the App Review Information section of App Store Connect.
This is where I’m confused.
Why this doesn’t seem applicable
The app does not use subscriptions
The app does not have user accounts
The IAP is non-consumable, one-time purchase
Trials are not subscription-based and expire automatically on-device
There is no “expired subscription account” that could exist technically
StoreKit testing is done via sandbox Apple IDs, but those are:
not app-level accounts
not usernames/passwords inside the app
only used in the Apple purchase sheet
Additional complication
Because old paid users are automatically recognized as “Pro” via AppTransaction.originalAppVersion, the Unlock Pro button is hidden once Pro is active.
This means that on some devices (including mine), the purchase sheet never appears anymore because the app already considers the user entitled.
This might be confusing App Review and causing them to assume the app uses subscriptions and gated accounts.
Questions
Has anyone seen App Review request a demo account with expired subscription for an app that uses only non-consumable IAPs?
Is there a correct way to respond other than explicitly explaining that:
there are no accounts
there are no subscriptions
StoreKit sandbox Apple IDs are sufficient?
Would providing a sandbox Apple ID (clearly labeled as such) help, or is that inappropriate since Apple reviewers already have sandbox accounts?
Is this likely just a misclassification by App Review, or is there something in Apple’s guidelines that I’m missing?
What I’ve already tried
Explained the purchase flow step-by-step in App Review notes
Clarified that the Paid Apps Agreement is already accepted
Clarified that Pro access is automatically granted to previous paid users
Verified that the IAP is correctly configured and available in App Store Connect
At this point I’m unsure whether I should:
escalate / push back on the incorrect assumption, or
modify the UI to make the purchase path permanently visible even for entitled users
Any insight from people who have gone through similar review issues would be greatly appreciated.
Thanks in advance.
StoreKit
RSS for tagSupport in-app purchases and interactions with the App Store using StoreKit.
Posts under StoreKit tag
200 Posts
Selecting any option will automatically load the page
Post
Replies
Boosts
Views
Activity
Hello,
I'm sure I've probably missed a checkbox somewhere.. I have a mulitiplatform app, when building from Xcode, and not using the testing config, both iOS and macOS show the correct App Store currency..
When I distribute a build through TestFlight, my Mac version shows a
different country/currency price (the US one). I can't find anywhere to change this. My Mac is signed into the same sandbox account as my iOS device.
Can anyone help?
My app has in app purchase for subscriptions, available in many countries. When using Sandbox App Store accounts on TestFlight with a locale different from my own in the iOS 26 RC, I'm getting incorrect currency coming back from Product.products(for: identifiers), and so my app displays the wrong price for the locale. However, the actual Apple Pay buy sheet shows the proper currency symbol and currency amount. This did not happen on prior versions of iOS.
Is anyone else experiencing this?
Since January 28, 2026, we’ve noticed an increase in StoreKit-related errors during purchase flows.
Specifically, we’re seeing a spike in errors reported as “Unable to Complete Request”, categorized as unknown StoreKit errors. This correlates with a noticeable drop in the overall purchase success rate.
A few observations:
The issue is not limited to the latest app version, it also affects older versions.
It appears to occur only on iOS 17+.
The impact seems country-specific: some regions are affected more heavily, while others show no significant change compared to previous days.
At the moment, there are no related incidents reported on Apple’s System Status page.
Given these symptoms, this looks like a potential StoreKit / Apple API issue, but we haven’t found any official confirmation yet.
Has anyone else observed similar StoreKit behavior recently on iOS 17+?
Any insights or known issues would be greatly appreciated.
**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'm implementing PurchaseIntent.intents for App Store in-app purchase promotions, following Apple's WWDC guidance. The API only works on cold launch (killed→launch), but fails on background→foreground transitions, making App Store promotions unusable.
Sample code as followed from WWDC23 video "What's new in StoreKit 2 and StoreKit Testing in Xcode".
In the StoreKitManager observable class, I have this function which is initialized in a listening task:
func listenForPurchaseIntent() -> Task<Void, Error> {
return Task { [weak self] in
for await purchase in PurchaseIntent.intents {
guard let self else { continue }
let product = purchase.product
await self.purchaseProduct(product)
}
}
}
where purchaseProduct() will perform the call to:
try await product.purchase()
ISSUE:
When the app is in background (after previously launched), and the purchase intent is initiated from Xcode Transaction Manager or using the "itms-services://?action=purchaseIntent" method, the system foregrounds my app but the purchase intent is never delivered to the waiting listener. The intent remains queued until the next cold launch (quit app and relaunch app). This could mean that if a user has installed the app, and has run the app, then tapped the promotional IAP from the App Store, the purchase intent will not show up until the next cold launch.
If the app is in quit state, then the system will foreground the app, and purchase intent is delivered correctly.
STEPS TO REPRODUCE
Launch app (listener starts in StoreKitManager.init())
Background app
Add purchase intent via Xcode Transaction Manager
Foreground app
Result: No purchase sheet appears, no intent delivered
Workaround attempts:
Using this either in a view or the main app:
func checkForPurchaseIntents() async {
for await purchaseIntent in PurchaseIntent.intents {
await storeKit.purchaseProduct(purchaseIntent.product)
}
}
Applied to .onChange(of: scenePhase) - Doesn't work, nothing happens.
Using UIApplication.willEnterForegroundNotification - Only works on the first time the app goes from background to foreground when purchase intent is sent. Doesn't work on second time or third time.
• Attempting to creating fresh listening task on each foreground - Does not work.
The question is:
How are we supposed to implement the PurchaseIntent API?
I have checked Apple sample projects like BackyardBirds, and sample projects from WWDC on StoreKit 2 but they never implemented Purchase Intent.
Hello everyone,
I'm having trouble testing custom offer codes for my auto-renewable subscription in the Sandbox environment.
I am using the modern StoreKit 2 API to display the redemption sheet:
try await StoreKit.AppStore.presentOfferCodeRedeemSheet(in: windowScene)
When I enter a valid custom code that I created in App Store Connect, the system sheet immediately returns the following error:
"Cannot Redeem Code. The code entered is not valid. [environment: sandbox]"
To be clear, I am manually typing the custom code string itself into the redemption sheet's text field, not using a one-time code link or URL.
I believe my configuration is correct, and I've already spent a significant amount of time troubleshooting. Here is a list of everything I have checked and tried so far:
App Store Connect Configuration:
The Offer Code is marked as "Active".
The parent subscription product is approved and its status is "Ready for Sale".
The offer's eligibility is set correctly
The start and end dates for the offer are valid.
Despite all these steps, the error persists. At this point, I suspect this might be a temporary issue with the Sandbox environment itself, but I want to make sure I haven't missed any crucial configuration steps.
Has anyone else encountered this issue recently? Is there anything else I should be checking?
Any help would be greatly appreciated.
Thank you.
I updated the price of subscriptions within an app in App Store Connect, however the new price does not show within the test app. I would just like to make sure that if the app is released that the subscription price is set to the most recent price. Is there any way to confirm that and is there a way to see the new price in the test app?
Topic:
App Store Distribution & Marketing
SubTopic:
App Store Connect
Tags:
Subscriptions
StoreKit
App Store Connect
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
SKStorefront.countryCode always returns "US" in TestFlight and sandbox,
even when sandbox Apple ID is set to a different country.
Is this expected behavior?
Is SKStorefront guaranteed to return the correct storefront
only for production App Store builds?
Topic:
Developer Tools & Services
SubTopic:
Apple Developer Program
Tags:
StoreKit Test
StoreKit
In-App Purchase
TestFlight
Hello everyone, I achieved my MacOs app and distributed for "App Store Connect" and I already have setup the Product In App Purchase in the App Store connect, and I even tested the purchase flow using the local .storekit file using the "Edit Schema". And now, when I remove the edit scema's storekit file and archieved the app and used the Internal testing and installed the app using Testflight, I see that the product is not showing, an empty product array is being returned and there is no option to purchase.
I don't want to sumit the full app until I test the StoreKit integration in real test
Topic:
App Store Distribution & Marketing
SubTopic:
App Store Connect
Tags:
StoreKit
App Store Connect
In-App Purchase
TestFlight
I'm using StoreKit 2 with Product.products(for:) to fetch my auto-renewable subscriptions. It works in the Xcode simulator with a local StoreKit configuration file, but returns an empty array (no error) in TestFlight.
iOS 15+, using async/await API
Products are configured in App Store Connect
Paid Apps agreement is active
Sandbox tester account set up
Has anyone experienced this? What am I missing?
Topic:
App & System Services
SubTopic:
StoreKit
Tags:
Subscriptions
StoreKit Test
StoreKit
TestFlight
I have a $4 USD, one-time-purchase app (Dash Calc) and sales have been rough. In a crowded category, an paid-upfront app feels like a tough sell without a way to try it first. I’d like to offer a simple 7-day free trial followed by a single lifetime purchase, but App Store Connect still doesn’t officially support trials for paid apps.
In Jan 2023, an App Store Commerce Engineer recommended the $0 non-consumable IAP + paid non-consumable IAP workaround:
https://developer.apple.com/forums/thread/722874
I haven’t implemented it yet, but the subsequent discussion suggests the approach is overly complex. Handling refunds, reinstalls, activation timing, and purchase history requires non-obvious logic, and some developers report customer confusion and drop-off when presented with a $0 trial IAP.
Has anything improved since 2023?
Any new StoreKit APIs or App Store Connect changes that make this simpler or less error-prone?
Is the $0 non-consumable IAP still the recommended approach in 2026?
Any updated guidance for time-limited access on one-time purchases?
I’m happy to use the workaround if it’s still the official path—I just want to confirm there isn’t a better option now.
Topic:
App Store Distribution & Marketing
SubTopic:
App Store Connect
Tags:
StoreKit
In-App Purchase
I’m implementing a subscription purchase flow using promo code redemption via an external App Store URL.
Flow:
User taps “Purchase” in the app (spinner shown)
App opens the promo redemption URL (apps.apple.com/redeem)
User completes redemption in the App Store
User returns to the app
The app must determine whether the subscription was purchased within a reasonable time window
The app listens to Transaction.updates and also checks
Transaction.currentEntitlements when the app returns to the foreground.
Issue:
After redeeming a subscription promo code via the App Store and returning to the
app, the app cannot reliably determine whether the subscription was successfully
purchased within a short, user-acceptable time window.
In many cases, neither Transaction.updates nor
Transaction.currentEntitlements reflects the newly redeemed subscription
immediately after returning to the app. The entitlement may appear only after a
significant delay, or not within a 60-second timeout at all, even though the
promo code redemption succeeded.
Expected:
When the user returns to the app after completing promo code redemption,
StoreKit 2 should report the updated subscription entitlement shortly thereafter
(e.g. within a few seconds) via either Transaction.updates or
Transaction.currentEntitlements.
Below is the minimal interactor used in the sample project. The app considers
the purchase successful if either a verified transaction for the product is received via Transaction.updates, or the product appears in Transaction.currentEntitlements when the app returns to the foreground. Otherwise, the flow fails after a 60-second timeout.
Questions:
Is this entitlement propagation delay expected when redeeming promo codes through the App Store?
Is there a recommended API or flow for immediately determining whether a subscription has been successfully redeemed?
Is there a more reliable way to detect entitlement changes after promo code redemption without triggering user authentication prompts (e.g., from AppStore.sync())?
import UIKit
import StoreKit
final class PromoPurchaseInteractor {
private let timeout: TimeInterval = 60
private struct PendingOfferRedemption {
let productId: String
let completion: (Result<Bool, Error>) -> Void
}
private var pendingRedemption: PendingOfferRedemption?
private var updatesTask: Task<Void, Never>?
private var timeoutTask: Task<Void, Never>?
enum DefaultError: Error {
case generic
case timeout
}
init() {
NotificationCenter.default.addObserver(self, selector: #selector(willEnterForeground), name: UIApplication.willEnterForegroundNotification, object: nil)
}
deinit {
NotificationCenter.default.removeObserver(self)
updatesTask?.cancel()
timeoutTask?.cancel()
}
func purchaseProduct(using offerUrl: URL, productId: String, completion: @escaping (Result<Bool, Error>) -> Void) {
guard pendingRedemption == nil else {
completion(.failure(DefaultError.generic))
return
}
pendingRedemption = PendingOfferRedemption(productId: productId, completion: completion)
startPurchase(using: offerUrl)
}
@objc private func willEnterForeground() {
guard let pendingRedemption = pendingRedemption else { return }
startTimeoutObserver()
Task {
if await hasEntitlement(for: pendingRedemption.productId) {
await MainActor.run {
self.completePurchase(result: .success(true))
}
}
}
}
private func startPurchase(using offerURL: URL) {
startTransactionUpdatesObserver()
UIApplication.shared.open(offerURL) { [weak self] success in
guard let self = self else { return }
if !success {
self.completePurchase(result: .failure(DefaultError.generic))
}
}
}
private func completePurchase(result: Result<Bool, Error>) {
stopTransactionUpdatesObserver()
stopTimeoutObserver()
guard let _ = pendingRedemption else { return }
pendingRedemption?.completion(result)
pendingRedemption = nil
}
private func startTransactionUpdatesObserver() {
updatesTask?.cancel()
updatesTask = Task {
for await update in Transaction.updates {
guard case .verified(let transaction) = update else { continue }
await MainActor.run { [weak self] in
guard let self = self,
let pending = self.pendingRedemption,
transaction.productID == pending.productId
else { return }
self.completePurchase(result: .success(true))
}
await transaction.finish()
}
}
}
private func stopTransactionUpdatesObserver() {
updatesTask?.cancel()
updatesTask = nil
}
private func startTimeoutObserver() {
guard pendingRedemption != nil else { return }
timeoutTask?.cancel()
timeoutTask = Task {
try? await Task.sleep(nanoseconds: UInt64(timeout * 1_000_000_000))
await MainActor.run { [weak self] in
self?.completePurchase(result: .failure(DefaultError.timeout))
}
}
}
private func stopTimeoutObserver() {
timeoutTask?.cancel()
timeoutTask = nil
}
private func hasEntitlement(for productId: String) async -> Bool {
for await result in Transaction.currentEntitlements {
guard case .verified(let transaction) = result else { continue }
if transaction.productID == productId {
return true
}
}
return false
}
}
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.
one of my app users cancelled the subscription from settings. After that, she tried to buy the subscription from app which she could not as I receive same transaction id and previous exp date.
Hello, I'm currently experiencing issues with IAP subscription setup.
The following error appears:
"Billing Problem, There was a problem with your subscription renewal. To resolve, turn on Allow Purchases & Renewals, or leave off to test failed in-app purchase attempts and subscription renewals."
I'm testing with a sandbox account, and automatic subscription renewal is turned on in the sandbox settings.
A notification screen appears at the OS level, and consequently, a DID_FAIL_TO_RENEW error occurs on our payment server.
I cannot determine the cause at all, so I would appreciate your assistance in checking this issue.
One of our apps has 85% stuck in Billing Retry -- We are so confused. All the users are from the US, and have a one-week free trial.
We had 1,000 subscriptions expire from this issue.
So any help would be so appreciated.
Topic:
App & System Services
SubTopic:
StoreKit
Tags:
Subscriptions
StoreKit
App Store Connect
App Store Server API
a UK-based user is having trouble completing an in-app purchase.
after going through the typical purchase flow (tapping the button to trigger the in-app purchase sheet, completing Face ID) they see this verification sheet appear over my app and have to go to their banking app to approve the purchase.
after approving the purchase from their banking app, they tap "Payment confirmed on Mobile App" to close the sheet, but then see an alert that suggests the result is .userCancelled.
the purchase does not seem to have completed. the user reports not being charged (despite numerous attempts). plus, i have a "restore purchases" function on App init that would've restored a purchase if it existed.
i have implemented what i think is a typical Storekit.purchase() method (again, the message the user sees is for the .userCancelled case):
func purchase(productId: String) async -> (Bool, String?) {
guard let product = subscriptionProducts.first(where: { $0.id == productId }) else {
return (false, "Product not found")
}
do {
let result = try await product.purchase()
switch result {
case .success(let verification):
switch verification {
case .verified(let transaction):
await transaction.finish()
hasSubscription = true
return (true, nil)
case .unverified:
return (false, "Transaction verification failed")
}
case .userCancelled:
return (false, "No worries, take your time. 😌")
case .pending:
return (false, "Purchase is pending")
u/unknown default:
return (false, "Error purchasing product. If this keeps happening, please contact [email].")
}
} catch {
return (false, "Error purchasing product: \(error.localizedDescription)")
}
}
has anyone dealt with this issue? i was seeing an unusually high number of .userCancelled purchase events from users outside the US, and i'm wondering if some of them were genuine purchase attempts that were blocked by this verification step. 😕
I'm in the final phase before app approval and I'm struggling to implement store kit for in app purchases. I'm using base 44 and really need help finishing this set up.
I have an iOS app (SwiftUI + WKWebView) with auto-renewable subscriptions using StoreKit and SubscriptionStoreView.
The app was rejected under Guideline 3.1 because payments were defaulting to Stripe instead of storekit.
What’s already done:
Subscriptions created in App Store Connect (monthly + annual)
SubscriptionStoreView implemented and visible in app
WKWebView bridge triggers native StoreKit paywall
Sandbox test account created
Stripe fully disabled on iOS
What I need:
Verify StoreKit implementation is App Review compliant
Confirm subscriptions are correctly attached to the app version
Ensure paywall is discoverable by App Review
Help me pass App Review (reply guidance + final checks)
This is a short engagement (1–3 hours). Looking for someone with real StoreKit + App Review experience + Base44 knowledge.
Topic:
Developer Tools & Services
SubTopic:
Apple Developer Program
Tags:
Subscriptions
StoreKit
In-App Purchase