Skip to content

aligutierrez/PaywallKit

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

4 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

PaywallKit Core

A complete StoreKit 2 wrapper in ~150 readable lines. Product loading, purchase, verification, restore, live transaction updates, entitlement gating — no RevenueCat, no third-party SDKs, no per-transaction fees.

import PaywallKit

// One store per app. Product IDs come from App Store Connect.
@State private var store = PaywallStore(productIDs: ["pro.monthly", "pro.yearly"])

Gate content anywhere:

if store.hasEntitlement {
    ProFeatureView()
} else {
    Button("Unlock Pro") { showPaywall = true }
}

Install

In Xcode: File → Add Package Dependencies… and paste:

https://github.com/aligutierrez/PaywallKit

Or in Package.swift:

.package(url: "https://github.com/aligutierrez/PaywallKit.git", from: "1.0.0")

What you get

  • PaywallStore@Observable, @MainActor. Fetches products (in your ID order), purchases with StoreKit 2's built-in verification, restores, listens to Transaction.updates for the app's lifetime, and exposes hasEntitlement for gating.
  • PaywallPlan — a plain display model built from real products: name, price, period, trial ("7-day free trial"), and an automatic "Save X%" badge when you sell both a 1-month and a yearly plan.
  • PaywallStore.preview(plans:) — fixed plans, no App Store connection. Your paywall previews render without StoreKit setup.
  • Offline-safe entitlements — verified entitlements are cached, so a StoreKit flake (offline, ASDErrorDomain 500) never locks a paying user out. Real refunds still revoke via Transaction.updates.
  • App Store promoted purchasesPurchaseIntent.intents handled automatically (iOS 16.4+/macOS 14.4+).
  • Ask to Buy — parental-approval purchases surface a pending message instead of failing silently; AppStore.canMakePayments is checked before purchasing.
  • Unit tests included.

Usage

// Load products (call from .task or onAppear)
await store.load()

// store.plans is ready for your UI
ForEach(store.plans) { plan in
    Text("\(plan.name)\(plan.price)")
}

// Purchase and restore
let success = await store.purchase(planID: "pro.yearly")
await store.restore()

Test offline with an Xcode StoreKit Configuration file: File → New → File… → StoreKit Configuration File, then select it under Product → Scheme → Edit Scheme → Run → Options.

Requirements: iOS 17+ / macOS 14+, Swift 5.9+. Zero dependencies.

Want the UI too?

This is the engine. PaywallKit is the same module plus three production-ready SwiftUI paywall templates — drop-in upgrade, same package name:

Hero paywall template

  • 🏆 Hero — symbol, headline, feature list, plan picker
  • 📊 Free-vs-Pro comparison — for freemium apps
  • Trial timeline — the Blinkist-style pattern with the best trial-start rates in the industry
  • Localized in English, German, and Spanish; App Review requirements (restore, terms/privacy) built into every template
  • One config object for all three → A/B test layouts by changing one word

Get PaywallKit — $59 →

License

MIT — see LICENSE.

About

StoreKit 2 wrapper in ~150 readable lines — products, purchase, verification, restore, entitlement gating. Zero dependencies. iOS 17+

Topics

Resources

License

Stars

9 stars

Watchers

0 watching

Forks

Packages

 
 
 

Contributors

Languages