Реализация Win-Back кампаний для отменённых подписок в мобильном приложении
Пользователь отменил подписку. Через 2 недели он открывает приложение снова — либо по привычке, либо после пуш-уведомления. Это окно возврата. Win-back кампания — комбинация технических инструментов: специальный оффер через StoreKit, push-уведомление через APNs, и логика определения «правильного момента» для показа.
Три канала win-back
1. Push-уведомление с deep link на оффер — отправляется через FCM / APNs на устройства пользователей, которые отменили подписку N дней назад.
2. In-app оффер при следующем открытии — для пользователей, которые всё ещё открывают приложение после отмены.
3. Apple Win-Back Offers — нативный механизм Apple (iOS 18+), который позволяет настроить автоматическую рассылку офферов через App Store без серверной инфраструктуры.
Apple Win-Back Offers (iOS 18+)
Новейший инструмент — настраивается в App Store Connect → Subscriptions → Win-Back Offers. Apple сама определяет eligible пользователей (бывшие подписчики конкретной Subscription Group) и отображает оффер на странице приложения в App Store.
На клиенте нужно обработать транзакцию, которая приходит когда пользователь активирует win-back оффер:
// Слушаем Transaction.updates при запуске
for await result in Transaction.updates {
if case .verified(let transaction) = result {
if transaction.offerType == .winBackOffer {
// Пользователь вернулся через Win-Back — разблокируем
await restoreSubscriptionAccess(transaction)
await transaction.finish()
// Логируем для аналитики
Analytics.logEvent("win_back_reactivated", parameters: [
"offer_id": transaction.offerID ?? "unknown",
"product_id": transaction.productID
])
}
}
}
Promotional Offers для win-back (iOS 14+)
Для iOS ниже 18 или для in-app win-back использую Promotional Offers с серверной подписью (об архитектуре подписи — в отдельной услуге):
// Определяем кандидатов для win-back
func isWinBackCandidate() async -> Bool {
// Проверяем: есть ли истёкшая транзакция и нет активной
var hasExpiredSubscription = false
var hasActiveSubscription = false
for await result in Transaction.all {
if case .verified(let tx) = result,
tx.productType == .autoRenewableSubscription {
if tx.expirationDate ?? Date() < Date() {
hasExpiredSubscription = true
} else {
hasActiveSubscription = true
}
}
}
return hasExpiredSubscription && !hasActiveSubscription
}
// Показываем win-back paywall при входе в приложение
func showWinBackOfferIfNeeded() async {
guard await isWinBackCandidate() else { return }
guard let offerSignature = try? await apiClient.fetchWinBackSignature() else { return }
await MainActor.run {
presentWinBackPaywall(signature: offerSignature)
}
}
Push-уведомления для win-back
Серверная логика: выбираем пользователей, у которых subscription_expired_at BETWEEN NOW() - 7 DAYS AND NOW() - 3 DAYS и last_app_open > NOW() - 30 DAYS (всё ещё активны). Отправляем push через APNs:
{
"aps": {
"alert": {
"title": "Вернитесь к Premium",
"body": "Специальное предложение: первый месяц за полцены"
},
"badge": 1,
"sound": "default"
},
"deep_link": "app://paywall?offer=win_back_50&utm_source=push&utm_campaign=winback_d7"
}
Deep link открывает paywall напрямую с pre-selected win-back оффером. UTM-параметры нужны для аналитики конверсии по каналу.
Segmentation — не всем одинаковый оффер
Win-back офферы работают лучше при сегментации:
| Сегмент | Триггер | Оффер |
|---|---|---|
| Отменил < 7 дней назад | Следующий open | Pause вместо отмены (Google Play) |
| Отменил 7–30 дней | Push на 7-й день | Скидка 30% на первый месяц |
| Отменил 30–90 дней | Push на 30-й день | Free trial на 2 недели |
| Отменил > 90 дней | Сезонные кампании | Максимальная скидка |
Чем дольше пользователь не возвращается, тем агрессивнее оффер — это стандартная модель churned user re-engagement.
Измерение эффективности
Обязательные метрики:
- Win-back rate: (реактивированные / кандидаты на win-back) × 100
- Time to reactivation: медиана дней между отменой и возвратом
- LTV reactivated: сравниваем с LTV пользователей без отмены
- Offer conversion by segment: какой оффер работает лучше для какого сегмента
// Логируем показ win-back оффера
Analytics.logEvent("win_back_offer_shown", parameters: [
"days_since_cancellation": daysSinceCancellation,
"offer_type": offerType,
"segment": userSegment
])
Что входит в работу
- Определение win-back кандидатов (клиент + сервер)
- Apple Win-Back Offers (iOS 18+) или Promotional Offers как fallback
- In-app paywall с win-back оффером при следующем открытии
- Push-нотификация с deep link на оффер
- Сегментация по времени с момента отмены
- Аналитика: воронка показ → клик → покупка
Сроки
3–5 дней — в-app flow с Promotional Offers. С push-инфраструктурой и серверной сегментацией — 5–10 дней. Стоимость рассчитывается индивидуально после анализа требований.







