Problem Description:
1、I have two sandbox accounts from different countries. Account A is from Mainland China (CHN), and Account B is from the United States (USA). When I switch the sandbox account from Account A (CHN) to Account B (USA) in the system settings and restart the app, the value of SKPaymentQueue.defaultQueue.storefront.countryCode always returns "CHN" instead of the expected "USA".
2、This issue only occurs on iOS 18.2 and above.
3、On the same device running iOS 17.5.1, the behavior is correct. However, after upgrading the system to iOS 18.3.2, the error occurs.
4、In the sandbox environment, although SKStorefront.countryCode returns the wrong value, the currency type for Apple's in-app purchase is correct when initiating the payment.
5、The issue only exists in the sandbox environment and does not occur in the App Store-downloaded package.
Demo Code:
- (IBAction)clickButton:(id)sender
{
NSString *appStoreCountryCode3 = SKPaymentQueue.defaultQueue.storefront.countryCode;
NSLog(@"%@",appStoreCountryCode3);
}
Demo Testing Steps and Results:
1、Sandbox Account A (China) will print "CHN".
2、Go to Settings - Developer - (at the bottom) SANDBOX APPLE ACCOUNT, and switch to another sandbox account B (USA).
3、Restart the Demo App.
4、Print results:
iOS 17.5.1: "USA" ✅ → Upgrade the system of the same device to iOS 18.3.2 → "CHN" ❌
iOS 18.2.1: "CHN" ❌
iOS 18.3.1: "CHN" ❌
iOS 18.3.2: "CHN" ❌
Possible Clues:
Starting with iOS 18.2, Apple changed the entry point for setting up sandbox accounts, which introduced this bug. It seems that when users switch sandbox accounts on iOS 18.2, Apple engineers forgot to notify the SKStorefront class to update the countryCode value.
Before iOS 18.2: Settings - App Store - Sandbox Account
iOS 18.2 and later: Settings - Developer - (at the bottom) Sandbox Account
Although it doesn't affect the App Store package, it does impact our development and testing process. We hope this issue can be fixed in future versions. Thank you!
StoreKit Test
RSS for tagCreate and automate tests in Xcode for your app's submission and in-app purchase transactions.
Posts under StoreKit Test tag
110 Posts
Selecting any option will automatically load the page
Post
Replies
Boosts
Views
Activity
I've been struggling to work with the Storekit framework and specifically to find the current Storefront used by the user of the app.
Context : My app needs to behave differently depending on the country of the user.
For me relying on Locale.current.region?.identifier does not seem very reliable, the user can change it really easily.
I'm trying to use the Storekit framework like so :
if let storefront = await StoreKit.Storefront.current{
return storefront.countryCode
}
As per Apple's Storekit documentation :
Use current to determine a customer's current storefront region and offer in-app products suitable for that region. You maintain your own list of product identifiers and the storefronts in which you make them available.
But I just can't find out what I need to change in my current configuration to get another country. The code keeps returning my original storefront (which is France)
I've tried login in with a sandbox user defined on another country. Changed all settings on my device to another country. Changed my Apple's account region as described here. Also tried to logout from everything.
The only thing that works is setting a local .storekit file as described here and changing the default storefront.
Is Xcode overriding the default storefront when building on debug or TestFlight? does anyone know how can I test different storefronts with sandbox users without the local storekit file ?
Thank you in advance.
Problem:
I'm implementing StoreKit 2 in my SwiftUI app. Products load successfully when I rebuild in Xcode, but on a fresh install, Product.products(for:) returns an empty array. The paywall shows "Unable to load pricing."
Setup:
Using StoreKit Configuration File (
.storekit
) for testing
Product IDs match exactly between config and code:
com..premium.lifetime (non-consumable)
com..premium.monthly (auto-renewable subscription)
com.****.premium.yearly (auto-renewable subscription)
StoreKitManager is a @MainActor singleton with @Published properties
What I've Tried:
Initial delay before loading - Added 1-second delay in init before calling loadProducts()
Product ID verification - Confirmed IDs match exactly between StoreKitConfig.storekit and code
Retry logic with exponential backoff - Implemented 3 retry attempts with 0.5s/1s/1.5s delays
Multiple calls to updatePurchasedProducts() - Called twice after initial load
Verified StoreKit configuration - File is properly added to project, has valid product definitions
Code Structure:
swift
@MainActor
final class StoreKitManager: ObservableObject {
static let shared = StoreKitManager()
@Published private(set) var products: [Product] = []
private init() {
updateListenerTask = listenForTransactions()
Task {
try? await Task.sleep(nanoseconds: 1_000_000_000)
await loadProducts() // Returns empty on fresh install
await updatePurchasedProducts()
}
}
}
Observations:
✅ Works perfectly after Xcode rebuild
❌ Fails on fresh app install (simulator & device)
❌ Product.products(for:) returns empty array (no error thrown)
✅ StoreKit configuration file is valid and properly configured
Question: Why does StoreKit need a rebuild to recognize products? Is there a proper initialization sequence I'm missing for fresh installs?
Environment:
Xcode [Version 26.0 beta 7]
iOS [IOS +17.0]
Testing with StoreKit Configuration File
I'm designing an app, and the purchase function was initially broken because the Distribute Certificate expired. After reinstalling it, the app worked again, but on iPhone 15 Pro (iOS ver:18.6), it still couldn't read the purchased items in the App Store.
I test the same app on iPhone 6S Plus( iOS ver: 15.8.4) , the purchase function work fine.
I'm developing an app and I think I've implemented what I need to in the swift code. However, when I click the Purchase button in my app, I see "Cannot connect to App Store" when the App Store app opens. Attached are images showing how I've configured the Sandbox user. What am I doing wrong? I expect to be able to do a fake purchase to test subscription activation in the app, but it doesn't work.
Hello everyone,
I’m currently working on an iOS app built with Capacitor(5.0.6) with Cordova and vanilla JS. At the moment, my app uses Stripe to handle payments — on iOS I open a Safari View Controller so users can pay with Apple Pay or their credit card.
However, I need to migrate to Apple’s In-App Purchase system to comply with App Store policies. I would really appreciate some guidance or a step-by-step outline on the following:
The exact process to enable and configure In-App Purchases in Xcode and App Store Connect for a Capacitor-based app.
How to properly set up local testing with StoreKit (or any other recommended approach) before submitting to review.
Best practices for integrating In-App Purchases when using RevenueCat, since I’m considering it to simplify the implementation.
Any pitfalls or gotchas that I should be aware of during the first submission (for example, the requirement to include the first IAP with a new app version).
My goal is to fully comply with Apple’s policies and provide a smooth user experience for iOS users. I’m open to suggestions on frameworks, workflows, or tools that could make this easier.
Thank you in advance for any help or examples you can share!
Topic:
App Store Distribution & Marketing
SubTopic:
App Store Connect
Tags:
StoreKit Test
App Store Connect
In-App Purchase
Question:
In the sandbox environment, I attempted to perform an In-App Purchase within an IME (Input Method Extension) using a sandbox test account. The purchase flow completed successfully, and I received the success callback.
However, I encountered an issue: no receipt file is generated. I tried checking with both the main app’s bundle and the IME’s bundle, but the receipt file was not found in either case.
When I attempted to refresh the receipt using SKReceiptRefreshRequest, it failed with an exception (error code: 0).
I would appreciate any guidance on how to resolve this issue.
Withouth authorization Bearer token:
public static JWKSet getApplePublicKeys(String token) throws Exception {
URL url = new URL("https://api.storekit.itunes.apple.com/inApps/v1/jwsPublicKeys");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setRequestProperty("Accept", "application/json");
int status = conn.getResponseCode();
InputStream stream = (status >= 200 && status < 300)
? conn.getInputStream()
: conn.getErrorStream();
String body = new BufferedReader(new InputStreamReader(stream))
.lines()
.reduce("", (acc, line) -> acc + line);
System.out.println("HTTP " + status + ": " + body);
// load JWKSet from JSON string
try (InputStream in = new ByteArrayInputStream(body.getBytes(StandardCharsets.UTF_8))) {
return JWKSet.load(in);
}
}
With authorization Bearer token:
public static JWKSet getApplePublicKeys(String token) throws Exception {
URL url = new URL("https://api.storekit.itunes.apple.com/inApps/v1/jwsPublicKeys");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setRequestProperty("Accept", "application/json");
conn.setRequestProperty("Authorization", "Bearer ");
int status = conn.getResponseCode();
InputStream stream = (status >= 200 && status < 300)
? conn.getInputStream()
: conn.getErrorStream();
String body = new BufferedReader(new InputStreamReader(stream))
.lines()
.reduce("", (acc, line) -> acc + line);
System.out.println("HTTP " + status + ": " + body);
// load JWKSet from JSON string
try (InputStream in = new ByteArrayInputStream(body.getBytes(StandardCharsets.UTF_8))) {
return JWKSet.load(in);
}
}
Below is the my production and sandbox URls:
Sandbox: https://api.storekit-sandbox.itunes.apple.com/inApps/v1/jwsPublicKeys
Production: https://api.storekit.itunes.apple.com/inApps/v1/jwsPublicKeys
Kindly help me with this. If I am doing anything wrong, please let me know. I tried using the token in the URL, and it gives me a 404. If I hit the endpoint without the token, it returns a 401. Please assist me.
Topic:
App Store Distribution & Marketing
SubTopic:
General
Tags:
StoreKit Test
StoreKit
App Store Server Notifications
Hello,
I'm receiving error StoreKit: Failed to get response from platform.
I have user in SandBox, that user is logged on physical device,
I have correct bundleID.
Product is Approved
I tested via StoreKit configuration file and that worked just fine.
also tried to build app and push to test flight, this way same error.
Any recommendations what I can check ?
Thanks
We are experiencing a critical issue where StoreKit 2 is returning empty products when using Product.products(for:), specifically on devices running iOS 18.4.
This issue does not occur on iOS 18.3 or earlier.
Steps:
Created a subscription product (e.g. "upm1") in App Store Connect
Confirmed the product is active, localised, and part of a valid subscription group
Call the following Swift code using StoreKit 2:
Task {
do {
let products = try await Product.products(for: ["upm1"])
print(products)
} catch {
print("Error: (error)")
}
}
4. Result: products is an empty list.
This regression is blocking subscription testing on iOS 18.4.
Kindly someone please advise on a potential fix or workaround.
Hello.
I have setup a StoreKit testing in the app that was and still is perfectly working on iOS 18.
Unfortunately when run on iOS 26 the following error gets printed in the console after calling Transaction.currentEntitlement(for:) method:
Failed to verify certificate chain due to client recoverable failure:
Error Domain=NSOSStatusErrorDomain Code=-67843 "“StoreKit Testing in Xcode” certificate is not trusted" UserInfo={NSLocalizedDescription=“StoreKit Testing in Xcode” certificate is not trusted, NSUnderlyingError=0x109de7e10 {Error Domain=NSOSStatusErrorDomain Code=-67843 "Certificate 0 “StoreKit Testing in Xcode” has errors: Root is not trusted;" UserInfo={NSLocalizedDescription=Certificate 0 “StoreKit Testing in Xcode” has errors: Root is not trusted;}}}
I'm not seeting any StoreKit Testing certificates in phone's certificate trust settings.
This test was performed on iOS 26.0 (23A341) with app built in Xcode 16.4.
FB20339145
I am attempting to test non-consumable sandbox purchases, however I am unable to select the "Approve Transaction" option after initiating a purchase. Leaving the transaction in a permanent pending state. I can view the transaction in the transaction manager by navigating to Debug -> Storekit -> Manage Transactions.. but the only available options to select are "Refund Transaction" or "Delete Transaction".
What am I missing about Xcode or my environment that is preventing me from testing this purchase flow?
Some more information about my set up.
I have a .storekit file synced to AppStore Connect with my product Id.
There's a StoreKitTestCertificate.cert saved in the project.
I've tried running the build on my phone as Debug, Release and ReleaseForRunning all with the same behavior after making a purchase.
My phone is logged into a sandbox test user apple account in the developer iOS settings
I just boxed up AppTransaction API. In the debug environment it appears to always return a VerificationResult that is .verified
Unlike Storekit1 calling AppTransaction.shared does not seem to cause a sandbox receipt to actually get written on the app bundle in Derived data.
I was trying to purposefully mess with the receipt in order to get AppTransaction to fail so I can test how my app behaves when errors occur but there is no receipt to mess with. I tried using the old exit(173) API and it does cause a receipt to be fetched but that seems to be completely ignored by AppTransaction, it validates even if you trash or tamper with the receipt given by exit(173).
Is there a good way to test receipt validation failure using the high level Storekit2 API?
The same store kit configuration file works in iOS and iPadOS, but not in macOS for the same multi platform application project with a single scheme.
Here’s a more detailed write up with the sample code and screenshots. When the simple app is run on
https://www.reddit.com/r/SwiftUI/s/KJsYcggWOa
EDIT: I’m using Xcode 16.4
Hello!
Trying to find any info about how to add In-App Purchase with application Entitlements.plist file manually (NOT with XCode). Is there any reference within keys and description?
What need to be in this file:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>key-for-in-app-purchase</key>
<string>value</string>
</dict>
</plist>
Dear Apple Support Team,
We are experiencing an issue with the Offer Code Redemption Sheet in our iOS app. Despite following Apple’s recommended approaches, the redemption sheet does not close automatically after a user successfully redeems a code.
We have implemented both methods as suggested in the documentation:
StoreKit 2 (iOS 16+):
AppStore.presentOfferCodeRedeemSheet(in: scene)
StoreKit 1 (iOS 14–15):
SKPaymentQueue.default().presentCodeRedemptionSheet()
Expected behavior: The sheet should automatically close after a successful code redemption and provide a receipt for verification.
Observed behavior: The sheet remains open even after a code is successfully redeemed, and we do not receive a receipt to validate the redemption.
We would greatly appreciate guidance or any workaround to ensure that:
The redemption sheet closes automatically after redemption.
A valid receipt is delivered for verification.
For your reference, we are testing on:
iOS versions: 16+, 15+
Device models: iPhone 16 and others
Please let us know if additional information, logs, or screen recordings are needed to investigate this issue.
Topic:
App Store Distribution & Marketing
SubTopic:
App Store Connect API
Tags:
Subscriptions
iPhone
StoreKit Test
StoreKit
Hello!
My application written with CPP and using StoreKit2 functionality based on bridging CPP-ObjectiveCPP-Swift. The question is in correct project properties for adding this library to application.
Configuring library by attaching project.entitlement file (within in-app purchase key) to the library project. Question is how to add library to the application correctly:
Is there requirements to write another one entitlement for Application and switch on 'in-app purchase' in application too or it's enough to add it only to the library?
Is there any examples of using StoreKit2 in libraries and attaching it to the projects?
Is there any requirements for configuring library within StoreKit2 if it's going to be reused in different applications?
Hi,I am facing the 21002 issue.Have you went through it? If you have resolved it, please dive me a hand.
Below is my code,and I Have tested in sand box environment.
NSURL receiptURL = [[NSBundle mainBundle] appStoreReceiptURL];
if (![[NSFileManager defaultManager] fileExistsAtPath:[receiptURL path]]) {
SKReceiptRefreshRequest receiptRefreshRequest = [[SKReceiptRefreshRequest alloc] initWithReceiptProperties:nil];
receiptRefreshRequest.delegate = self;
[receiptRefreshRequest start];
return;
}
NSData data = [NSData dataWithContentsOfURL:receiptURL];
/ receipt_data/
NSString *receipt_data = [data base64EncodedStringWithOptions:0];
After I test the purchase procedure, use the above receipt-data to verify on the server https://sandbox.itunes.apple.com/verifyReceipt,which always response 21002.I have no idea to deal with it.Thanks.
I have a few issues. Support consultants responded to my review file by saying they wanted the image. 1- I logged in with the sandbox account I used for testing and took a screenshot of the Paywall screen. However, they said this screenshot wasn't accepted. The documentation explains how to log in to Testflight with a sandbox account and test it, but even though I tried testing on two different devices, I couldn't log in to Testflight or get the image they requested. 2- I closed my privacy policy and terms of use, and there's no problem. What else should I do? I'm stuck on the Testflight and sandbox sections. Can you help ?
在沙盒环境下或者TestFlight 测试消费型项目会提示此项目将免费恢复