Hello,
I noticed the Product.SubscriptionInfo subscriptionPeriod (of type Product.SubscriptionPeriod) is different for the same product between StoreKit Testing in Xcode and the sandbox/App Store (production) environment.
For a “1 week” auto-renewable subscription, we get the following:
StoreKit Testing in Xcode: 1 week gives a subscriptionPeriod with value of 1 and a unit of Product.SubscriptionPeriod.Unit.week
Sandbox/App Store: 1 week gives a subscriptionPeriod with value of 7 and a unit of Product.SubscriptionPeriod.Unit.day
This created issues in my app because I used the localizedDescription of a Product.SubscriptionPeriod to display a text similar to “$4.99 per week”. This is what I obtain with the StoreKit Testing in Xcode, but in the Sandbox/App Store environment, it displays “$4.99 per day” (because the subscriptionPeriod is “7 Days” and the unit is then .day). Obviously, this is not what I wanted to display.
Other periods like “1 month”, “2 months”, “3 months”, “6 months, and “1 year”, the period provided by both StoreKit Testing and Sandbox/App Store correspond to the period unit specified in App Store Connect.
In addition, I want to report that for a weekly subscription/offer or a 2 weeks offer, Product.SubscriptionInfo.subscriptionPeriod or Product.SubscriptionOffer.period == .weekly or .everyTwoWeeks is always false.
We observe the following:
With Sandbox or App Store live production:
1 week, Product.SubscriptionInfo.subscriptionPeriod == .weekly is false (because it’s “7 days”)
1 week, Product.SubscriptionOffer.period == .weekly is false (because it’s “7 days”)
2 weeks (offer), Product.SubscriptionInfo.subscriptionPeriod == .everyTwoWeeks is false (because it’s “14 days”)
2 weeks (offer), Product.SubscriptionOffer.period == .everyTwoWeeks is false (because it’s “14 days”)
But with an Xcode StoreKit configuration file:
1 week, Product.SubscriptionInfo.subscriptionPeriod == .weekly is true (because it’s “1 week”)
1 week, Product.SubscriptionOffer.period == .weekly is true (because it’s “1 week”)
2 weeks, Product.SubscriptionInfo.subscriptionPeriod == . everyTwoWeeks is true (because it’s “2 weeks”)
2 weeks, Product.SubscriptionOffer.period == . everyTwoWeeks is true (because it’s “2 weeks”)
So in sandbox and production, .weekly and .everyTwoWeeks is never possible.
If someone from Apple could check the feedback FB19605865 🙂
Thank you
Regards,
Axel, @alpennec
Code:
do {
let productIDs: [String] = ["revenueSocks_weekly_trial"]
let products: [StoreKit.Product] = try await Product.products (for: productIDs)
let weeklySubscription: StoreKit.Product = products.first!
let displayPrice: String = weeklySubscription.displayPrice
// For a weekly subscription in App Store Connect
// With an Xcode StoreKit configuration file: subscriptionPeriod unit is Week (week), value is 1 → "1 Week"
// With the Sandbox + App Store: subscriptionPeriod unit is Day (.day), value is 7 → "7 Days"
let unitString: String = weeklySubscription.subscription!.subscriptionPeriod.unit.localizedDescription
print("\(displayPrice) per \(unitString.localizedLowercase)")
// StoreKit configuration file → "$4.99 per week"
// Sandbox + App Store → "$4.99 per day"
} catch {
print(error)
}
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
Created
Hello,
I am currently implementing External Purchase Link and External Purchase Custom Link and am encountering an issue where both
ExternalPurchaseLink.canOpen and ExternalPurchaseCustomLink.isEligible always return false under all test conditions.
I would like to confirm whether my setup is missing any required steps or whether this behavior is expected.
Below are the details of my current environment and configuration:
🔧 1. Development Environment
Xcode: 16.3, 16.4, 26.0 beta 4
Devices:
iPhone running iOS 26.2 beta
iPhone running iOS 16.7.12
macOS 15.5 (real device testing)
Simulator iOS 18.0
Build Type: Local development build using a Developer Provisioning Profile
Sandbox account signed in during testing
🔑 2. Entitlements (Developer site & Xcode)
In Certificates → Identifiers → App ID, both capabilities are enabled:
StoreKit External Purchase
StoreKit External Purchase Link
The .entitlements file in Xcode includes:
com.apple.developer.storekit.external-purchase = YES
com.apple.developer.storekit.external-purchase-link = YES
The Provisioning Profile also contains both entitlements (confirmed via codesign -d --entitlements :-).
📄 3. Info.plist Configuration
Both keys are configured with correct region codes according to documentation:
SKExternalPurchase
SKExternalPurchaseCustomLinkRegions
🌍 4. Test Storefront
Device storefront verified as United States (US) or Portugal (PT) (US = target region for External Purchase Link, PT = EU region)
But despite all the above configuration,
both API calls consistently return false:
ExternalPurchaseLink.canOpen // false
ExternalPurchaseCustomLink.isEligible // false
So I cannot proceed to testing the remaining flow (token retrieval, link opening, etc.)
------ Questions ------
❓ Q1) Local Development Build Limitation
Is it expected behavior that Developer-signed local builds always return
canOpen = false / isEligible = false
for External Purchase Link & Custom Link?
Is there a technical or policy restriction that prevents eligibility in local dev builds?
❓ Q2) App Store Connect Configuration Requirement
Are there mandatory App Store Connect settings (such as external purchase URLs, support URL, disclosures, or country configuration) that must be enabled before eligibility becomes true?
Currently, no External Purchase Link or Custom Link menu is visible in my App Store Connect app settings.
Is this menu only available after certain approvals or under specific conditions?
❓ Q3) TestFlight Requirement
Do External Purchase Link and Custom Link only return eligibility = true on:
TestFlight builds, or
Distribution-signed builds?
Or should eligibility also work on developer builds?
Formal confirmation would be helpful.
❓ Q4) Developer Account Type Limitation
We are using an Individual Developer Account (not Organization).
Can Individual accounts fully request, test, and ship apps using:
External Purchase Link
External Purchase Custom Link
Or are there limitations on account type?
🙏 Request
We have completed all documented setup steps (Entitlements → Provisioning → Info.plist),
but eligibility remains false, blocking feature validation.
Please clarify which of the following is the cause:
Local development builds do not support eligibility
Missing App Store Connect configuration (not visible to us)
Account type restriction
Region rollout or entitlement approval requirement
Any additional setup not documented publicly
Thank you for your assistance.
If an app on the App Store still uses StoreKit 1 (a.k.a. the Original StoreKit) to handle In-App Purchases, would IAPs work for users who download such app on iOS 26.2?
Would the app allow the users to purchase an IAP via StoreKit 1 or would it be impossible to buy the IAP on iOS 26?
The iOS Documentation says that SKPaymentQueue (which is a part of StoreKit 1) is "Deprecated" and "No longer supported.", with the support being for iOS 3.0–18.0.
Does this mean that apps using StoreKit 1 won't be able to make IAP purchases when running on iOS 26?
The app review prompt on iOS/iPadOS 26.1 has the "Not Now" button greyed out:
On iOS/iPadOS 26.0, this was working:
Before filing a radar, is there anything I'm missing? The only way to dismiss it is to tap a star rating and then a Cancel button appears which lets you dismiss it without reviewing.
Topic:
App & System Services
SubTopic:
StoreKit
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 tried deleting the configuration file, but I ended up with an alert asking me to sign in with my sandbox ID. I did, and it returned an error: "Request Canceled".
It is as if the purchase function doesn't update the currentEntitlements. This is my purchase function. Am I doing something wrong?
func purchase(_ product: Product) async throws {
let result = try await product.purchase()
switch result {
case .success(let verificationResult):
switch verificationResult {
case .verified(let transaction):
// Successful purchase - deliver content
await updatePurchasedProducts()
await transaction.finish()
// Go back to the map
integratePlanAhead()
case .unverified(_, let error):
// Purchase failed verification
throw error
}
case .userCancelled:
// User cancelled the purchase
break
case .pending:
// Purchase is pending (e.g., parental approval needed)
break
@unknown default:
break
}
}
It looks like purchases are never updated for my sandbox user...
Thanks for any help :)
Topic:
App & System Services
SubTopic:
StoreKit
Hi folks,
How can I check the URL we have configured for SKAdNetwork install postback requests? Sadly we've lost any record of this via email on our end, and Apple developer support have asked that I reach out via the forums.
Topic:
App & System Services
SubTopic:
StoreKit
I need help understanding how the In-App purchase subscription works within the same subscription group and how the Order plays a role at the time of auto-renewal.
In my case, I have 5 in-app products in the same group as given below with their Order,
Order Product
----------------------
1 Gold Annual
2 Gold Monthly
3 Silver Annual Old,
3 Silver Annual New
4 Silver Monthly
One user purchased Silver annual New, at the time of expiry, after a year, it auto-renewed to Silver annual Old.
My understanding is that if a user has purchased Silver annual New, at the time of renewal, it should renew with the same product, not with different product id.
Is this behaviour expected? Is there any official document which can explain this behaviour?
Note: There was no Order given before, recently we have changed the Order to manage Upgrade and Downgrade for In-App subscriptions.
Hi everyone,
I’m seeing a strange behavior with StoreKit 2 and I’d like to know if anyone else experienced this.
My subscription group “ROTA Premium” (Monthly + Annual) is currently Waiting for Review in App Store Connect.
What works
In Xcode’s StoreKit sandbox, everything loads correctly:
Products appear
Trial starts
Purchases work
What doesn’t work
In TestFlight and App Review, StoreKit 2 returns zero products, so my paywall shows:
“No subscription options found.”
There are:
No geo restrictions
No backend
No VPN/IP filtering
Paid Apps Agreement is accepted
App Review said the device was online, but couldn’t give technical help.
My question
Has anyone seen StoreKit 2 fail to load subscription products when the subscription group is still in Waiting for Review?
Do subscription groups need to be reviewed together with the app version for StoreKit 2 to return them in TestFlight/App Review?
Any advice would be appreciated!
Thanks.
I'm using code similar to the following to conditionally show the SubscriptionStoreView and the .storeButton(.visible, for: .restorePurchases) modifier is used to allow the user to restore an existing subscription.
How can I listen for events that would allow me to close this view once the subscription is restored?
The .onInAppPurchaseCompletion closure does not handle this and it also appears that listening for results in Transaction.currentEntitlements also doesn't handle the fact that a subscription is restored.
Any guidance on how to determine if the subscription has been restored would be greatly appreciated.
Finally, how can this be tested effectively in both TestFlight and in Xcode with the simulator.
if subscriptionManager.subscription == .none {
SubscriptionStoreView(groupID: "1234567") {
SubscriptionMarketingView(transparency: false)
.containerBackground(for: .subscriptionStoreFullHeight) {
GradientBackground()
}
}
.backgroundStyle(.clear)
.storeButton(.visible, for: .restorePurchases)
.storeButton(.visible, for: .redeemCode)
.onInAppPurchaseCompletion { product, result in
Task {
await subscriptionManager.entitlements()
}
}
}
Hi everyone,
I’m experiencing an issue with In-App Purchases during App Review.
What works
My consumable IAP products load correctly using StoreKit2.
TestFlight (sandbox) purchases work perfectly.
Localizations are filled in and valid.
Paid Apps Agreement, banking, and tax forms are active.
IAP products are properly created in App Store Connect and marked as “Developer Action Needed” only because they wait for approval with the new binary.
What fails
During review I received:
“We found that your in-app purchase products exhibited one or more bugs which create a poor user experience.
Specifically, we were not able to complete a purchase.”
They didn’t provide any more technical details.
Additional context
The StoreKit configuration file is not included in the app archive.
Product identifiers perfectly match those in App Store Connect.
StoreKit2 purchase() works as expected on TestFlight.
The app does not use server-side receipt validation - purchases are handled purely through StoreKit2 APIs, as recommended.
My questions
What could cause a situation where TestFlight purchases work but App Review cannot complete a purchase?
Does Apple expect server-side receipt validation even for simple one-time consumables?
Could there be a delay or sync issue causing IAP products to not be available to the reviewer yet?
Is there anything I should check on the App Store Connect side beyond what I already verified?
Any help or hints would be greatly appreciated - I’m stuck because everything works in sandbox but fails only for reviewers.
Thanks!
My app offers auto renewable subscriptions,
I have couple of questions regarding how to model the subscriptions at server side,
Is originalTransactionId will ever change for a subscription? Will it stay same in case of subscription upgrade/downgrade/crossgrade? If it changes on product change then how do i keep track that the subscription was a continuous subscription and not a new one?
Is the webhook payload contains any identifier of which apple account purchase the subscription?
I am having issues maintaining sync between the app account's current subscription and the local apple account's subscription, is there any doc regarding this? Will be really helpful
I am finding that the verifyReceipt endpoint used to verify a receipt is failing on occassion starting around October 27, 2015. I realize this API is deprecated. I am using cURL to call verifyReceipt. The specific errors are 52 - Empty reply from server and 56 - Connection closed abruptly. This indicates an issue with Apple's server as I understand it.
Is anyone else experiencing this as well?
In a recent update to developer news, Apple posted more details about compliance tools for the new laws coming into effect in Texas on Jan 1.
https://developer.apple.com/news/?id=2ezb6jhj
It is not explicitly stated in the news update or documentation but when the new RESCIND_CONSENT notification is sent to the developer, what happens on the child account devices? Does the app just disappear. Does the developer need to take any action in the App itself?
https://developer.apple.com/documentation/appstoreservernotifications/notificationtype
Thanks,
Eric
Topic:
App & System Services
SubTopic:
StoreKit
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! 🙏
💬 Post Content
Hello everyone,
I’m currently testing In-App Purchases (auto-renewable subscriptions) for my iOS app,
and I’m experiencing an issue where the product information cannot be fetched from StoreKit.
❓ Questions
For sandbox testing, is it absolutely necessary to submit a new app version for review (with the in-app purchase included)? Or can I test subscriptions without submitting a new build to App Review?
Under what conditions does the error
IAPError(code: storekit_no_response,
source: app_store,
message: StoreKit: Failed to get response from platform.)
🧪 What I’ve Tried
• Confirmed that the bundle identifier matches the App Store Connect record
• Verified that In-App Purchase capability is enabled in Xcode
• Ensured the sandbox tester account is logged in (Settings → App Store)
• Removed the StoreKit configuration file to use the sandbox environment
• Tried both real device and simulator (same error)
• Accepted the Paid Apps Agreement in App Store Connect
• Products are created but currently not yet submitted for review
🔍 Environment
• App type: iOS app built with Flutter (using in_app_purchase plugin)
• Build type: Archive build installed via Xcode (Run on device) and testFlight
• StoreKit Configuration File: Currently removed (for sandbox test);
• Status: Ready to submit in App Store Connect
Topic:
App & System Services
SubTopic:
StoreKit
On this page:
https://developer.apple.com/documentation/storekit/testing-age-assurance-in-sandbox
It says:
Start with a Sandbox account.
What is a Sandbox account and how does one set one up?
Just it just simply mean an Apple account id used for testing, or something else?
Hey guys, somehow I used my real ID(not sandbox test ID) to purchase a non-consumable item in the TestFlight package, no actual payment was made, but this payment record cannot be erased. Even though I know the transaction ID, I cannot initiate a refund like using refundRequestSheet().
Does anyone know how to deal with this, or there is no way to solve it?
Hello Fellow Developers,
I recently built a simple craft related app called "Genie Crystals" with a landing page. there is a button on landing page which redirects to a main template generator page.
Here the user can play with the parameters and create an output which can be exported. to export there is an unlock button which is linked to the in-app purchase configured in the app. Initially it was not capturing price properly so I modified the code slightly to keep the button in disabled state until the product details got fetched in background asynchronously.
But when I released the app and downloaded it on a different device at the time of load itself, I am getting the alert - product not available. I have used correct product Id in the program. I have confirmed that.
I think I am missing something. Any help will be appreciated.
I am new to this so if I need to share any additional information kindly let me know.
Thanks.
Is the following subscription cancellation flow possible for an iOS in-app subscription?
(Note: This is during the feature planning stage, not actual app deployment.)
Planned user flow:
User taps the “Cancel Subscription” button
Display a “Wait a moment!” screen showing how much the user has enjoyed BFLIX content (to encourage retention)
User taps “Proceed to Cancel”
Collect cancellation reason from the user
Redirect the user to the Apple subscription management page to complete cancellation
Can this flow be implemented under Apple’s current in-app purchase and App Store Review guidelines?
Topic:
App & System Services
SubTopic:
StoreKit