Miniwall Docs
Mobile SDK

Purchases and prices

Pass prices to the SDK by package ID, run your own purchase with StoreKit or Play Billing, and report purchases that finish elsewhere.

Miniwall renders; it does not charge. Prices and payment come from your app, matched to the screen by package ID. The SDK never sees card data or the amounts you charge.

Package IDs

Each package card in the editor has an ID, such as monthly or annual (see Packages and pricing). Your app gives each ID a price. packageIds lists the IDs a screen uses. The Install SDK page also lists them.

let ids = Miniwall.packageIds(in: paywallJSON) // ["annual", "monthly"]

If a screen uses an ID with no price, that card shows without a price.

products

products maps each package ID to a ProductInfo.

FieldMeaning
priceIn major units: 9.99, not 999.
currencyISO 4217 code, such as USD.
periodBilling period: day, week, month, year, lifetime, or a unit with a count (every 3 months).
titleShown by {{ product.store_product_name }}.
offerIntroductory or trial offer: a price and a period. A free trial is price 0.
options.products = [
    "monthly": ProductInfo(price: 9.99, currency: "USD", period: .every(.month)),
    "annual": ProductInfo(price: 59.99, currency: "USD", period: .every(.year),
                          offer: .init(price: 0, period: .every(.day, count: 7))),
    "lifetime": ProductInfo(price: 199, currency: "USD", period: .lifetime),
]

Text variables the SDK fills

Screen text can use these (the editor lists them under Price and plan; see Variables). The SDK fills them with the same rules as the Web SDK, and prices are formatted for the screen's language.

VariableValue
product.price$9.99
product.currency_code, product.currency_symbolUSD, $
product.periodmonth, 2 weeks, lifetime
product.period_abbreviatedmo, 2 wk
product.period_with_unit1 month, 2 weeks
product.period_in_days, _weeks, _months, _yearsRounded counts (years round down)
product.periodlymonthly, every 2 weeks
product.price_per_day, _week, _month, _yearThe price converted to that unit
product.price_per_period$9.99/month
product.price_per_period_abbreviated$9.99/mo
product.store_product_nametitle
product.relative_discount33%. Compares each recurring package's monthly price with the most expensive one. Only for cheaper packages, and only when at least two recurring packages exist.
product.offer_price, product.offer_period and the other offer_ formsFrom offer
custom.NAMEFrom customVariables

Period variables need a period. price_per_* is not set for lifetime. Use variablesPerPackage to override any value as text, per package.

Store prices

Use the price your store reports, so the screen always matches what the user is charged.

Miniwall.products(from:) turns StoreKit 2 Products into products, keyed by your package IDs. Prices, currencies, periods and introductory offers come from the App Store.

let storeProducts: [String: Product] = ["monthly": monthly, "annual": annual]
options.products = Miniwall.products(from: storeProducts)

Purchase

Run it in onPurchase. See Callbacks.

The SDK includes a ready StoreKit 2 purchase and restore. They are optional: use your own billing code if you prefer.

options.onPurchase = Miniwall.storeKitPurchase(storeProducts)
options.onRestore = Miniwall.storeKitRestore()

storeKitPurchase buys the product of the tapped package, finishes verified transactions and returns false when the user cancels. storeKitRestore syncs with the App Store and returns true when an entitlement is active.

Both stores require a way to restore purchases on screens that sell subscriptions. Pass onRestore: without it the Restore purchases button is hidden.

reportPurchase

If a purchase finishes outside the screen (for example a store transaction that completes later, or a purchase made from another screen of your app), call reportPurchase:

Miniwall.reportPurchase(packageId: "annual")
  • It credits the screen where the user last tapped buy.
  • Without a recent buy tap, it credits the last placement the user met (shown or held out) in the last 30 days. If they were held out it records a holdout purchase.
  • Pass paywallId to name the screen yourself.
  • It sends at once. It does nothing when analytics are off or there is nothing to credit.
  • With a holdout, call it after every purchase so the groups compare fairly.

On this page