About storekit
A StoreKit 2 skill for developers implementing in-app purchases with async/await and SwiftUI. It covers product setup, transactions, subscriptions, verification, and local testing.
Key features
- 01Product loading and purchase flows
- 02Subscription and offer handling
- 03Transaction updates and verification
- 04SwiftUI StoreKit views
- 05Local purchase testing with .storekit
Use cases
- 01Adding in-app product purchases
- 02Implementing auto-renewable subscriptions
- 03Restoring purchases and granting entitlements
- 04Testing purchase flows in Xcode
Install
Copy the command and run it in a terminal.
npx skills add https:/ / github.com/ johnrogers/ claude-swift-engineering --skill storekitAfter installing, type/storekitin Claude Code to confirm it loaded.
Bundled files
References and scripts installed along with SKILL.md.
references/getting-started.mdproducts.mdstorekit-views.mdsubscriptions.mdtransactions.mdDetails
From the project READMEStoreKit
StoreKit 2 patterns for implementing in-app purchases with async/await APIs, automatic verification, and SwiftUI integration.
Reference Loading Guide
ALWAYS load reference files if there is even a small chance the content may be required. It's better to have the context than to miss a pattern or make a mistake.
| Reference | Load When |
|---|---|
| Getting Started | Setting up .storekit configuration file, testing-first workflow |
| Products | Loading products, product types, purchasing with Product.purchase() |
| Subscriptions | Auto-renewable subscriptions, subscription groups, offers, renewal tracking |
| Transactions | Transaction listener, verification, finishing transactions, restore purchases |
| StoreKit Views | ProductView, SubscriptionStoreView, SubscriptionOfferView in SwiftUI |
Core Workflow
- Create
.storekitconfiguration file first (before any code) - Test purchases locally in Xcode simulator
- Implement centralized
StoreManagerwith@MainActor - Set up
Transaction.updateslistener at app launch - Display products with
ProductViewor custom UI - Always call
transaction.finish()after granting entitlements
Essential Architecture
@MainActor
final class StoreManager: ObservableObject {
@Published private(set) var products: [Product] = []
@Published private(set) var purchasedProductIDs: Set<String> = []
private var transactionListener: Task<Void, Never>?
init() {
transactionListener = listenForTransactions()
Task { await loadProducts() }
}
}
Common Mistakes
-
Missing
.finish()calls on transactions — Forgetting to calltransaction.finish()after granting entitlements causes transactions to never complete. The user won't see their purchase reflected. Always callfinish(). -
Unsafe StoreManager state — Shared
StoreManagerwithout@MainActorcan have race conditions. Multiple async tasks can update@Publishedproperties concurrently, corrupting state. Use@MainActorfor thread safety. -
No transaction listener at app launch — Not setting up
Transaction.updateslistener means app crashes or misses refunded/canceled purchases. Listen for transactions immediately in@main, not when user taps purchase button. -
Hardcoded product IDs — Hardcoded IDs make testing and localization hard. Use configuration files or environment variables for product IDs. Same applies to prices (fetch from App Store, don't hardcode).
-
Ignoring verification failures — App Store verification fails silently sometimes. Not checking verification status means accepting unverified transactions (security risk). Always verify before granting entitlements.