Персонализация инвайтов в приложении с использованием AppsFlyer
Все, кто выстраивал взаимодействие пользователя с приложением, знают, какой это непростой процесс. Один из механизмов такого взаимодействия — Deep Linking. От его работы зависят пуши, привлечение пользователей и ретеншн.
Далее расскажу про некоторые инструменты AppsFlyer и их использование на примере фичи для приглашения пользователей, которая поможет сделать регистрацию более персонализированной.
Интеграция SDK и получение атрибуции
AppsFlyer — платформа для атрибуции и аналитики мобильного трафика со множеством платных и бесплатных сервисов. Для реализации фичи приглашения в приложение будем использовать получение атрибуции после установки и инструмент для создания коротких ссылок.
Первым делом интегрируем SDK в проект — в документации есть подробная инструкция.
После интеграции можно проверить, как приходит атрибуция после установки. Для этого добавим в метод onConversionDataSuccess
простой лог.
override fun onConversionDataSuccess(map: MutableMap?) {
Timber.d("Attribution - ${map ?: "empty"}")
if (map.isNullOrEmpty()) {
return
}
//handle attribution here
После этого на тестовом устройстве нужно открыть специально сгенерированную ссылку. Так как приложение не установлено на смартфон, произойдёт перенаправление в стор для установки.
Скорее всего после установки и запуска будет выведено «Attribution — empty». Для этого может быть несколько причин:
Неправильно настроен проект в AppsFlyer.
Имя пакета отличается от использованного в AppsFlyer, например, если вы используете дополнительный суффикс для debug сборок.
Ваше устройство не добавлено в тестовые.
Если всё сделано правильно, то от AppsFlyer придёт атрибуция, она выглядит примерно так (для наглядности я отфильтровал пустые значения через debbuger):
Пример атирибуции после установкиПримерно такие данные лежат внутри map. Тут много всего интересного, например, поле http_referrer показывает, откуда был переход по ссылке, а is_first_launch можно использовать для отслеживания первого запуска.
Сейчас наиболее важно поле af_dp — в него приходит информация о содержимом ссылки, в конкретном случае это мем с id — hSPRMKbU8. Мы используем этот id, чтобы сделать открытие приложения более органичным — при таком переходе мем будет первым в ленте.
Кажется, что всё хорошо, но есть подводные камни.
Получение данных об установке будет происходить при каждом запуске приложения. Это небольшая перестраховка на тот случай, если атрибуцию не удалось обработать в первый раз. Поэтому, если у вас есть логика, которая должна отрабатывать только при первом запуске — стоит поддержать это отдельно. Например, через флаг в префах или любой другой механизм.
Время, которое пройдёт от запуска приложения до вызова метода, может быть разным, особенно при первом запуске. На тестовых прогонах оно менялось от 2 до 15 секунд. Если код в методе не влияет на UI, то это не проблема, но если на основе атрибуции нужно собрать экран — всё становится хуже. Здесь нет хорошего решения, потому что каждое из них будет блокировать пользователя на некоторое время после запуска приложения, или оно сложно для реализации.
Итак, теперь мы умеем получать информацию об установке, отлично! Не забудьте порадовать аналитиков этими данными.
Сервис коротких ссылок
Аналитика говорит о том, что охотнее всего открывают короткие ссылки. Возможно это связано с тем, что для обычных людей параметры в ссылке выглядят страшно и непонятно. Вероятно, короткие ссылки более органично смотрятся на экране из-за отсутствия переносов, но факт остается фактом — короткие ссылки предпочтительнее для наших пользователей.
У AppsFlyer уже есть API для генерации таких ссылок, но не бесплатное. Не стоит опускать руки, если вы не готовы платить, в SDK для клиентов есть аналог. Его имя — LinkGenerator.
with(generator) {
setReferrerName("user nick")
setReferrerUID("user unique id")
setReferrerImageURL("user avatar url")
addParameter("is_retargeting", true.toString())
addParameter("af_dp", "link for content in application")
addParameter("af_web_dp", "additional link for web page")
generateLink(context, listener)
}
Теперь при переходе по короткой ссылке будет происходить редирект на сайт, потом в Google Play и, наконец, в приложение.
Вроде получилось, но давайте попробуем открыть ссылку на устройстве с установленным приложением. Вся цепочка переходов повторится снова — это выглядит не очень красиво, было бы отлично открывать ссылки сразу через приложение. Оказывается, это тоже можно сделать.
Во-первых, нужно добавить в манифест приложения соответствующий intent-filter.
Во-вторых, обработку ссылки в методе onAppOpenAttribution. Сюда придут все данные, которые были закрыты короткой ссылкой.
override fun onAppOpenAttribution(map: MutableMap?) {
if (map.isNullOrEmpty()) {
return
}
val data = AppsFlyerConversionAttrs.init(map as Map)
if (!TextUtils.isEmpty(data.afDeeplink)) {
handleDeeplink(data.afDeeplink)
}
}
Так как требуется участие сервера, при получении данных тоже есть задержка, но в отличие от метода onConversionDataSuccess она не такая существенная.
Фича с приглашением новых пользователей
Теперь мы готовы реализовать фичу из начала статьи. В упрощённом виде она выглядит так: клиент должен уметь создавать специальные ссылки-приглашения, содержащие данные о клиенте. Эти данные должны использоваться на новых установках для отображения специального персонализированного экрана с регистрацией.
Проведя декомпозицию, получаем две подзадачи:
Создание и шаринг ссылок-приглашений.
Обработка ссылок-приглашений после установки.
Пойдём по порядку. Фактически всё, что нужно для создания ссылки-приглашения, у нас уже есть. Добавляем данные о пользователе, который шарит ссылку: его id, имя и аватар.
private val inviteLinkPlaceholder = "Click this link to add %1$s as friend"
private val listener = object : CreateOneLinkHttpTask.ResponseListener {
override fun onResponse(inviteLink: String?) {
if (!TextUtils.isEmpty(inviteLink)) {
generatedLinkSubject.onNext(String.format(inviteLinkPlaceholder,
authSessionManager.authSession.nick,
inviteLink))
} else {
generatedLinkSubject.onNext("")
}
}
override fun onResponseError(p0: String?) {
generatedLinkSubject.onNext(p0 ?: "")
}
}
fun generate(content: Content): Observable {
generatedLinkSubject = PublishSubject.create()
with(generator) {
setReferrerName(authSessionManager.authSession.nick)
setReferrerUID(authSessionManager.authSession.uid)
setReferrerImageURL(authSessionManager.authSession.photoUrl)
addParameter("is_retargeting", true.toString())
addParameter("af_dp", content.link)
addParameter("af_web_dp", content.webLink)
generateLink(context, listener)
}
return generatedLinkSubject
}
Готовая ссылка с текстом для шаринга выглядит так: Click this link to add Rick_Rick as friend in ABPV https://abpv.onelink.me/nWMv/344e6258, остаётся только передать её в шаринг.
Отлично, ссылка ушла в свободное плавание, теперь любой, кто установит приложение после перехода, будет считаться приглашённым и автоматически подпишется на автора ссылки.
Теперь можно реализовать вторую часть с поддержкой приглашений после установки.
Добавим в метод onConversionDataSuccess обработку ссылок-приглашений. От обычных ссылок их можно отличить по полю media_source, внутри него должно быть значение af_app_invites.
if (data.afMediaSource == "af_app_invites") {
//handle data from invite link
onInstallationAttributionSubject.onNext(ACTION_PERFORMED)
}
Дальше данные передаются в onInstallationAttributionSubject, стейт экрана приглашения меняется в зависимости от значения этого subject.
Итоговый экран приглашенияЗаключение
Описанный кейс довольно простой, но с его помощью можно сделать регистрацию более персонализированной, что при должном подходе и аудитории может повысить конверсию.
Этот пример можно использовать как фундамент для дальнейшего развития полноценной реферальной системы, или придумать что-то ещё.
Кроме коротких ссылок и атрибуции после установки, AppsFlyer предоставляет большое количество других инструментов, например, защиту от фрода или управление аудиторией, но это уже совсем другая история.