Auto-renewable subscriptions — найскладніший тип IAP. Не тому що StoreKit складний сам по собі, а тому що навколо нього виростає ціла екосистема: grace periods, billing retry, downgrade/upgrade між тирами, promo offers, introductory pricing, і нарешті — обробка churn через expirationIntent. Помилка на будь-якому етапі веде до втрат доходу. Ми впроваджуємо підписки під ключ за 3–5 днів, гарантуючи коректну логіку на всіх етапах життєвого циклу.
Життєвий цикл підписки і де він ламається
Підписка в iOS існує не тільки поки активна. Apple автоматично продовжує її за 24 години до завершення. Якщо оплата не пройшла — починається billing retry period (до 60 днів). У цей час статус підписки expired, але Apple продовжує спроби списання. Більшість додатків блокують доступ одразу після expirationDate — це невірно.
Правильна логіка: перевіряти renewalInfo.isInBillingRetryPeriod. Якщо true — даємо grace period (налаштовується в App Store Connect, зазвичай 6 днів для річних, 3 дні для місячних). Користувач із проблемою картки не повинен втрачати доступ негайно.
StoreKit 2 обробляє grace period прозоро, що знижує churn на 20–30% порівняно з ручною реалізацією на StoreKit 1. Ось приклад коректної перевірки:
for await result in Transaction.currentEntitlements {
guard case .verified(let transaction) = result else { continue }
if transaction.productType == .autoRenewable {
let renewalInfo = try? await transaction.subscriptionStatus.first?.renewalInfo
let isInGracePeriod = renewalInfo?.gracePeriodExpirationDate != nil
let isRetrying = renewalInfo?.isInBillingRetryPeriod == true
if transaction.revocationDate == nil &&
(transaction.expirationDate ?? .distantPast > .now || isInGracePeriod || isRetrying) {
unlockPremium()
}
}
}
Чому важливий grace period?
Без grace period користувачі з проблемами оплати миттєво втрачають доступ. Apple дозволяє налаштувати до 16 днів відстрочки — за цей час клієнт встигає змінити картку, а ви зберігаєте його. Наш досвід показує, що 70% користувачів повертаються до оплати протягом grace period. Якщо ж блокувати доступ одразу — вони йдуть назавжди.
Тири та переходи між ними
Якщо в додатку декілька тирів (Basic, Pro, Enterprise) — потрібна subscription group в App Store Connect. Всі тири в одній групі, користувач може мати лише одну активну підписку в групі одночасно.
Upgrade (перехід на дорожчий тир) — діє одразу, Apple перераховує залишок. Downgrade — набирає чинності в наступний розрахунковий період. Crossgrade (одна ціна, інший тир) — залежить від налаштування: можна зробити immediate або deferred.
Відстежувати це на клієнті через originalTransactionID та subscriptionGroupID. На сервері — зберігати повну історію транзакцій та обробляти Apple Server Notifications v2 (App Store Server Notifications). Типи подій, які обов'язково обробляти: DID_RENEW, DID_FAIL_TO_RENEW, EXPIRED, GRACE_PERIOD_EXPIRED, REFUND.
Як обробляти переходи між тирами?
Upgrade активується негайно — Apple пропорційно перераховує вартість. Downgrade відкладається до наступного циклу. Crossgrade можна налаштувати як immediate або deferred в App Store Connect. Важливо коректно оновлювати UI, показуючи користувачеві дату набрання чинності зміни. Для цього використовуйте renewalInfo.renewalDate та offerType.
Introductory та promotional offers
Introductory pricing (перші N періодів за зниженою ціною) налаштовується в App Store Connect і автоматично застосовується для нових підписників. Проблема — користувач, який відписався і хоче повернутися, за замовчуванням не отримує інтро-ціну знову. Для цього існують promotional offers — їх можна видавати за своєю логікою (win-back кампанії).
| Тип пропозиції |
Налаштування |
Кому доступно |
Умови застосування |
| Introductory |
В App Store Connect |
Нові підписники |
Автоматично, один раз |
| Promotional |
Генерація підпису на сервері |
Будь-які користувачі |
За вашою логікою, будь-який період |
| Promo-код |
App Store Connect |
Всі |
Фіксована знижка, обмежена кількість |
Підпис для promotional offer генерується на сервері з приватним ключем із App Store Connect:
// На клієнті створюємо paymentDiscount
let discount = SKPaymentDiscount(
identifier: "winback_3months",
keyIdentifier: keyID,
nonce: nonce, // UUID з сервера
signature: signature, // підпис з сервера
timestamp: timestamp
)
payment.paymentDiscount = discount
Без серверного підпису promotional offer недійсний — Apple перевіряє підпис на своїй стороні.
Що входить в роботу
- Аудит поточної реалізації IAP та підписних груп
- Проектування схеми тирів і груп (subscription group) з урахуванням бізнес-логіки
- Інтеграція StoreKit 2 з підтримкою grace period, billing retry та обробки помилок
- Налаштування App Store Server Notifications (v2) на бекенді з обробкою всіх критичних подій
- Реалізація win-back логіки з використанням promotional offers
- Документування коду та інтеграція аналітики відписок
- Навчання команди роботі з Sandbox та тестуванням підписок
- Підтримка після запуску (1 місяць безкоштовно)
Процес роботи
Аудит поточної реалізації → проектування структури підписних груп і тирів → інтеграція StoreKit 2 з підтримкою grace period та billing retry → налаштування App Store Server Notifications на бекенді → реалізація логіки win-back та промо-оферів → тестування в Sandbox з імітацією завершення підписки (Sandbox скорочує періоди: місяць = 5 хвилин).
Терміни — 3–5 днів залежно від кількості тирів, наявності бекенду та вимог до аналітики відписок. Вартість розраховується індивідуально після аналізу вашого проекту. Зв'яжіться з нами — оцінимо обсяг та запропонуємо оптимальне рішення. Отримайте консультацію сертифікованого iOS-розробника з 5+ років досвіду впровадження підписок.
Ми гарантуємо: коректну обробку billing retry, grace period та всіх типів переходів, відповідність App Store Review Guidelines (Section 4.2 та 5.1), а також повну підтримку на етапі тестування та публікації.
Монетизація мобільних додатків: IAP, підписки та рекламна медіація
Додаток з погано реалізованими покупками втрачає гроші не тому що користувачі не хочуть платити, а тому що StoreKit транзакція зависає, Receipt Validation падає з помилкою або restore purchases не працює — і користувач пише в підтримку або залишає 1 зірку. Наш досвід (більше 7 років у мобільній розробці) показує, що грамотна монетизація збільшує LTV на 30–60% вже в перші три місяці після впровадження. Отримайте консультацію з монетизації вашого додатка — проаналізуємо поточну модель і знайдемо точки зростання.
Чому StoreKit 2 — найкращий вибір для IAP?
StoreKit 2 (iOS 15+) — сучасний API з async/await та верифікованими транзакціями на стороні пристрою без сервера. Transaction.currentEntitlements повертає всі активні покупки. Ключова зміна порівняно з StoreKit 1: верифікація JWS-підпису на пристрої через VerificationResult<Transaction> — не потрібно надсилати receipt на сервер для базової перевірки.
Але сервер-сайд валідація все одно потрібна для consumable покупок та проти fraud. App Store Server API замінює старий /verifyReceipt endpoint. Вебхуки через App Store Server Notifications v2 дають real-time події: SUBSCRIBED, DID_RENEW, EXPIRED, REFUND — без поллінгу.
Типова помилка: не обробляють paymentQueue(_:updatedTransactions:) у фоні для незавершених транзакцій. Користувач купив consumable, додаток впав до finishTransaction — покупка висить у черзі, при наступному запуску відновлюється та вимагає повторної обробки на сервері. Без ідемпотентності сервера — подвійне нарахування.
Як не втратити дохід на підписках?
Підписочна модель вимагає відстеження станів: тріал → активна → grace period → expired → refunded. RevenueCat — фактичний стандарт для керування підписками в продакшні. Абстрагує StoreKit та Google Play Billing, дає unified API, webhooks, аналітику когорт та A/B тести paywall.
Альтернатива RevenueCat — власна реалізація з Adapty або Qonversion. Повністю кастомна — тільки якщо дані не повинні залишати інфраструктуру або є нестандартна логіка. Ми гарантуємо, що налаштування webhooks та обробка подій життя підписки виконується без втрат — перевірено на проектах з аудиторією понад 500 тис. DAU.
Google Play Billing Library 6+ вимагає обробки PurchasesUpdatedListener та явного виклику acknowledgePurchase() або consumePurchase() протягом 3 днів — інакше Google автоматично скасовує покупку та повертає гроші. Середня вартість такої помилки — втрата значної суми на користувача на місяць (за даними наших проектів).
Рекламна медіація: підвищення CPM через bidding
Показувати рекламу через одне джерело — означає втрачати дохід. Медіація (waterfall або bidding) запитує рекламу у декількох мереж і показує найкращу ставку. Google AdMob — основа для banner, interstitial, rewarded. Медіація через AdMob Mediation або MAX (AppLovin) — другий де-факто стандарт. MAX використовує In-App Bidding — real-time аукціон без водоспаду. На практиці MAX дає CPM на 15-30% вище класичного waterfall (залежить від гео та аудиторії). У США для rewarded відео CPM може перевищувати певну суму. При 100 000 показів rewarded відео на день перехід з waterfall на In-App Bidding може приносити додатково значну суму щоденно.
ironSource (Unity Ads) — сильна позиція в ігровому сегменті, особливо rewarded video. Mintegral — добре закриває азійську аудиторію.
Налаштування медіації вимагає ATT (App Tracking Transparency) на iOS 14+. Без requestTrackingAuthorization рекламний CPM падає в 3-5 разів для користувачів, які не погодилися. SKAdNetwork та Privacy Manifest (iOS 17) — обов'язкові вимоги, без яких рев'ю падає.
| Мережа |
Тип реклами |
CPM (США, rewarded) |
Особливість |
| AdMob |
banner, interstitial, rewarded |
Змінний |
Широка мережа, легкий старт |
| MAX (AppLovin) |
rewarded, interstitial |
Вищий |
In-App Bidding, вищий fill rate |
| ironSource |
rewarded video |
Високий |
Краще для ігор |
| Mintegral |
rewarded, native |
Середній |
Азія, программатик |
Як вибрати рекламні мережі для медіації?
Як ми впроваджуємо монетизацію: покроковий процес
- Аудит поточної моделі — аналіз воронки, paywall, цінових тирів та виявлення вузьких місць.
- Проектування моделі — вибір типу (subscription, consumable, non-consumable) та оптимізація цінових точок.
- Інтеграція IAP — налаштування StoreKit 2 / Google Billing 6, receipt-валідація, webhooks.
- Рекламна медіація — підключення 3-6 мереж, налаштування waterfall або In-App Bidding, тестування fill rate.
- Аналітика та когорти — інтеграція RevenueCat, Amplitude або Firebase для відстеження LTV.
- A/B тестування paywall — використання Remote Config для експериментів без релізу.
- Запуск та моніторинг — 2 тижні безкоштовної підтримки після запуску, фікс багів по SLA 24 години.
Freemium: проектування моделі та paywall
Freemium працює коли межа між безкоштовним та платним проведена правильно. Занадто жорсткий paywall на старті — користувач видаляє. Занадто щедрий безкоштовний тир — немає стимулу платити.
Як проєктувати paywall для freemium?
Паттерн, який працює технічно: feature flags з сервера (Remote Config у Firebase або LaunchDarkly) керують доступом до фіч. Це дозволяє A/B тестувати paywall без релізу, змінювати умови тріалу, проводити акції.
Реалізація на рівні коду: EntitlementManager — єдина точка перевірки доступу до фіч, яка знає про статус підписки, флаги та промо. Жодних перевірок isPremium розкиданих по всьому коду. Досвід показує: такий підхід знижує кількість багів з paywall на 80% (підтверджено на 30+ проектах).
Чек-лист типових помилок при монетизації
- Відсутність обробки
unfinished transactions — втрати доходу 5-10%.
- Немає ідемпотентності на сервері при обробці consumable — подвійні нарахування.
- Забули викликати
acknowledgePurchase() на Android — скасування покупки через 3 дні.
- Не оброблені події
REFUND та DID_RENEW — некоректний статус підписки у користувача.
- Paywall без A/B тестів — залишають 20-40% потенціалу монетизації.
- Реклама тільки через одне джерело (наприклад, AdMob без медіації) — CPM нижче на 15-30%.
Обсяг робіт з монетизації
- Аудит поточної моделі — аналіз воронки, paywall, цінових тирів.
- Інтеграція IAP — StoreKit 2 / Google Billing 6, receipt-валідація, webhooks.
- Рекламна медіація — налаштування MAX / AdMob, підключення 3-6 мереж, тестування fill rate.
- Налаштування аналітики — RevenueCat, Amplitude / Firebase, когортний аналіз.
- Документація — опис ентайтлментів, процедура відновлення, чек-лист рев'ю.
- Навчання команди — розбір типових помилок, рекомендації з підтримки.
- Гарантія — безкоштовна підтримка 2 тижні після запуску, фікс багів по SLA 24 години.
Терміни орієнтовно
| Етап |
Тривалість |
| Базова IAP (один store) |
1–2 тижні |
| Підписочна система + RevenueCat + paywall |
3–5 тижнів |
| Рекламна медіація (MAX + 3 мережі) |
1–2 тижні |
| Повний цикл (IAP + реклама + аналітика) |
4–8 тижнів |
Вартість розраховується індивідуально. Ми працюємо в цій сфері більше 8 років і реалізували більше 40 проектів з монетизацією — багато з них пройшли App Store Review без жодного блокування. Зв'яжіться з нами для аудиту або замовте консультацію — розповімо, які точки зростання є у вашому додатку.
Джерела: Apple StoreKit 2 Documentation, RevenueCat Best Practices, Wikipedia: Freemium.