Sandbox user can't see StoreKit subscriptions

Hi everyone,

I’m struggling to get StoreKit 2 to fetch products in my SwiftUI app while using a sandbox user. I think I’ve followed all necessary setup steps in Xcode, App Store Connect, and my physical test device, but Product.products(for:) always returns an empty array. I’d appreciate any insights!

What I’ve Done

  1. Local App Setup (Xcode 16.2)
  • Created a blank SwiftUI Xcode project.
  • Enabled In-App Purchase capability under Signing & Capabilities.
  • Implemented minimal StoreKit 2 code to fetch available products (see below).
  • Using the correct bundle identifier, which matches App Store Connect.
  1. App Store Connect Configuration
  • Registered the app with the same bundle identifier.
  • Created an Auto-Renewable Subscription with:
  • Product ID: v1 (matches my code).
  • All fields filled (pricing, localization, etc.).
  • Status: Ready for Review.
  • Linked the subscription to the latest app version in App Store Connect.
  1. Sandbox User & Testing Setup
  • Created a sandbox tester account.
  • Logged in with the sandbox user under Settings → Developer → Sandbox Apple ID. This was on my physical device (iOS 18.2).
  • Installed and ran the app directly from Xcode (⌘+R).
  1. Issue: StoreKit Returns No Products
  • Product.products(for:) does not return any products.
  • There are no errors thrown, just an empty array.
  • I confirmed that StoreKit Configuration is set to None in Xcode.
  • No StoreKit-related logs appear in the Console.

Code Snippets

//StoreKitManager.swift

import StoreKit
import SwiftUI

@MainActor
class StoreKitManager: ObservableObject {
    @Published var products: [Product] = []
    @Published var errorMessage: String?

    func fetchProducts() async {
        do {
            let productIDs: Set<String> = ["v1"] // Matches App Store Connect
            let fetchedProducts = try await Product.products(for: productIDs)
            print(fetchedProducts) // Debug output

            DispatchQueue.main.async {
                self.products = fetchedProducts
            }
        } catch {
            DispatchQueue.main.async {
                self.errorMessage = "Failed to fetch products: \(error.localizedDescription)"
            }
        }
    }
}
//ContentView.swift
import SwiftUI

struct ContentView: View {
    @StateObject private var storeKitManager = StoreKitManager()

    var body: some View {
        VStack {
            if let errorMessage = storeKitManager.errorMessage {
                Text(errorMessage).foregroundColor(.red)
            } else if storeKitManager.products.isEmpty {
                Text("No products available")
            } else {
                List(storeKitManager.products, id: \.id) { product in
                    VStack(alignment: .leading) {
                        Text(product.displayName).font(.headline)
                        Text(product.description).font(.subheadline)
                        Text("\(product.price.formatted(.currency(code: product.priceFormatStyle.currencyCode ?? "USD")))")
                            .bold()
                    }
                }
            }

            Button("Fetch Products") {
                Task {
                    await storeKitManager.fetchProducts()
                }
            }
        }
        .padding()
        .onAppear {
            Task {
                await storeKitManager.fetchProducts()
            }
        }
    }
}

#Preview {
    ContentView()
}

Additional Information

  • iOS Version: 18.2
  • Xcode Version: 16.2
  • macOS Version: 15.3.1
  • Device: Physical iPhone (not simulator)
  • TestFlight Build: Not used (app is run directly from Xcode)
  • StoreKit Configuration: Set to None

To get closer to the root cause of the issue, I recommend trying the following things:

  1. Try replacing your Manager and presentation code with StoreKit's view. This will tell if the issue is in the code or in the environment/apstore connect.

Replace you content view with this super minimal example:

import SwiftUI
import StoreKit

struct ContentView: View {
    var body: some View {
        SubscriptionStoreView(productIDs: ["v1"])
    }
}
  1. If the issue still exists, then add a StoreKit configuration file to you project and when creating it tick "Sync this file with an app in App Store Connect". Verify the app and team are auto filled. After creation, the file should sync with Appstore connect automatically. Do you see the product in the list?

  2. Finally try to run with this store kit configuration.

Additional thing, you wrote "Registered the app with the same bundle identifier." which makes me think that you did not distribute your app even once (product -> archive -> organizer -> distribute app). I don't know if this is a must in your case but I do recommend to do it. It can also reveal a typo in bundle identifier if you accidentally made one.

Personally, I never create an app in AppStore Connect "manually" but always start by distributing it. It will create a stub if this app does not exist.

Sandbox user can't see StoreKit subscriptions
 
 
Q