Реалізація free trial: технічні деталі та підводні камені
Ми часто бачимо, як додатки втрачають користувачів через непрозорий пробний період. «Я не знав, що з мене спишуть» — найчастіший відгук з однією зіркою після закінчення trial. Проблема вирішується технічно коректною реалізацією free trial: прозорі умови, своєчасні нагадування та серверна валідація. За багаторічний досвід роботи з підписками в понад 20 проектах ми виявили, що грамотна інтеграція знижує кількість чарджбеків на 30–50% та підвищує конверсію в платних користувачів.
Згідно з дослідженням «Підписки в мобільних додатках: поведінка користувачів», користувачі, які отримали нагадування за 2 дні до закінчення trial, на 25% рідше оскаржують списання. Середній збиток від одного чарджбеку може становити до $25 з урахуванням комісій та втрати лояльності. При цьому серверна валідація дозволяє відсікти до 15% спроб повторного використання trial, економлячи $0.50 на кожному такому користувачі.
StoreKit 2: Introductory Offer
На iOS trial реалізується через Product.SubscriptionOffer з paymentMode = .freeTrial. Продукт створюється в App Store Connect: Auto-Renewable Subscription → Add Introductory Offer → Free → N днів/тижнів. У коді:
let product = // Product із prefetch кешу
if let intro = product.subscription?.introductoryOffer,
await product.subscription!.isEligibleForIntroOffer {
// показуємо "7 днів безкоштовно"
showTrialCTA(days: intro.period.value)
} else {
// користувач вже використовував trial — стандартна ціна
showStandardCTA(price: product.displayPrice)
}
isEligibleForIntroOffer — async запит до App Store, робимо при prefetch. Користувач, який вже використав trial для цієї subscription group — не eligible. Показувати йому «7 днів безкоштовно» і потім списати одразу — шлях до dispute в банку.
Android: Free Trial у Play Billing Library 6+
val params = BillingFlowParams.newBuilder()
.setProductDetailsParamsList(
listOf(
BillingFlowParams.ProductDetailsParams.newBuilder()
.setProductDetails(productDetails)
.setOfferToken(trialOfferToken)
.build()
)
).build()
billingClient.launchBillingFlow(activity, params)
offerToken потрібно вибирати з subscriptionOfferDetails — беремо той, який містить FREE_TRIAL pricing phase. Якщо trial недоступний для користувача (вже був) — беремо base plan offer token.
Порівняння реалізації iOS та Android
| Параметр |
iOS (StoreKit 2) |
Android (Play Billing 6) |
| Тригер trial |
Introductory Offer |
Prepaid/Subscription Offer з FREE_TRIAL |
| Перевірка eligibility |
isEligibleForIntroOffer |
Перевірка offerType в ProductDetails |
| Серверна валідація |
App Store Server API |
Play Developer API |
| Сповіщення |
App Store Server Notifications V2 |
Real-time Developer Notifications |
Як забезпечити прозорість умов?
Apple вимагає явного розкриття умов auto-renewal поруч із кнопкою покупки. Стандартне формулювання під CTA кнопкою:
«7 днів безкоштовно, потім $9.99/міс. Підписка поновлюється автоматично. Скасування в будь-який час у налаштуваннях App Store.»
Розмір шрифту не менше 12pt. Якщо цю вимогу ігнорувати — не тільки погані відгуки, але й відхилення при рев'ю або видалення додатка при скаргах користувачів.
Окрім тексту під кнопкою: reminder push за 1–2 дні до закінчення trial — UNNotificationRequest з fireDate = trialEndDate - 2 дні. «Ваш пробний період закінчується післязавтра» з deep link на Manage Subscription. Це знижує chargeback rate, тому що користувач попереджений.
Серверна валідація trial
Клієнт не повинен бути джерелом правди про те, чи в trial користувач. Після transaction.finish() на iOS — серверна валідація через App Store Server API. Відповідь містить inAppOwnershipType, offerType, offerIdentifier — сервер знає, що це trial транзакція, і встановлює trial_ends_at у БД.
App Store Server Notifications V2 подія DID_RENEW з subtype: INITIAL_BUY означає конвертацію trial у платну підписку. EXPIRED з subtype: VOLUNTARY — користувач скасував до кінця trial. На кожну подію — оновлення статусу в БД та push-повідомлення користувачеві.
Grace period і billing retry
Підписка не продовжилась через проблеми з карткою — це не скасування. StoreKit 2 надсилає GRACE_PERIOD_STARTED notification. Клієнт отримує від сервера subscription_status: grace_period — показуємо банер «Проблема з оплатою» з deep link на оновлення платіжного методу (openURL → App Store subscription management). Не блокуємо доступ під час grace period (до 16 днів).
Чому довжина trial впливає на конверсію?
Середня конверсія trial у платну підписку: 20–40% залежно від категорії та довжини trial. 7-денний trial конвертує вдвічі краще 3-денного — користувач встигає сформувати звичку. 14-денний конвертує приблизно як 7-денний, але платить за нього оператор підвищеним періодом без revenue. 30-денний trial показує конверсію на 10% нижче 14-денного через зниження терміновості.
| Довжина trial |
Відносна конверсія |
Середній дохід на користувача за 90 днів |
| 3 дні |
1x (база) |
$4.50 |
| 7 днів |
2x |
$8.00 |
| 14 днів |
1.9x |
$7.80 |
| 30 днів |
0.9x |
$3.60 |
A/B тест довжини trial — обов'язковий. Firebase Remote Config керує тим, який offerIdentifier використовувати (3 дні vs 7 днів vs 14 днів).
Як налаштувати A/B тест довжини trial?
- Створіть кілька Intro Offers в App Store Connect з різною тривалістю (3, 7, 14 днів).
- У Firebase Remote Config задайте параметр
trial_days зі значеннями 3, 7, 14.
- У коді при завантаженні продукту використовуйте відповідний
offerIdentifier з Remote Config.
- Відстежуйте конверсію через Analytics і вибирайте оптимальну довжину.
Що входить до нашої реалізації trial?
Ми надаємо повний цикл робіт:
- Документація: опис логіки trial, схема серверної валідації.
- Код: інтеграція StoreKit 2 / Play Billing 6, серверна обробка сповіщень.
- Тестування: перевірка eligibility, grace period, reminder push.
- Доступи: налаштування App Store Connect, Google Play Console, Firebase.
- Навчання: передача знань команді замовника.
- [ ] Створення intro offer / base plan в App Store Connect / Play Console
- [ ] Перевірка eligibility на клієнті
- [ ] Серверна валідація через App Store Server API / Play Developer API
- [ ] Reminder push за 2 дні до закінчення
- [ ] Grace period handling (банер + deep link)
- [ ] A/B тест через Remote Config
Орієнтири за строками
Реалізація free trial з прозорими умовами, reminder push, серверною валідацією, grace period handling та Remote Config A/B керуванням — 3–5 робочих днів при готовому StoreKit 2 / Play Billing setup. Економія на чарджбеках після впровадження нашого підходу становить у середньому 30%. Замовте реалізацію та отримайте надійну subscription-систему з гарантією якості. Зв'яжіться з нами для консультації — ми допоможемо вибрати оптимальну довжину trial та уникнути типових помилок.
Монетизація мобільних додатків: 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.