Duolingo спрашивает «Зачем ты учишь язык?» и показывает разный контент в зависимости от ответа. Headspace — «Что тебя беспокоит?» и предлагает соответствующие медитации. Это не просто UX-паттерн — это механизм, который значительно увеличивает вероятность возврата пользователя: приложение с первых секунд релевантно именно ему. Без персонализации пользователь видит одинаковый интерфейс, а контент не соответствует его ожиданиям. Анкета решает эту проблему: она собирает ключевые данные и сразу настраивает приложение. В результате retention вырастает на 20–40%, а стоимость привлечения пользователя окупается быстрее.
С нами вы получаете 10+ лет опыта в мобильной разработке и более 50 реализованных проектов с персонализированным онбордингом.
Почему персонализированный онбординг важен для мобильного приложения?
По данным Localytics, персонализированный онбординг увеличивает retention на 25%. Когда пользователь видит релевантный контент с первого запуска, вероятность повторного визита растёт. Анкета — эффективный инструмент сбора данных: она занимает 30–60 секунд, но даёт профиль, который определяет поведение приложения на недели вперёд.
Архитектура анкеты
Анкета персонализации — это не просто набор экранов с кнопками «Далее». Это поток с ветвлением: ответ на вопрос 2 может определять, какой вопрос будет третьим. И результат — не просто сохранённые ответы, а набор параметров, влияющих на начальное состояние приложения.
Data-driven конфигурация. Каждый вопрос — объект с метаданными:
struct OnboardingQuestion {
let id: String
let type: QuestionType // .singleChoice, .multiChoice, .slider, .text
let title: String
let subtitle: String?
let options: [QuestionOption]
let nextQuestionId: [String: String] // optionId -> nextQuestionId, или "default"
let analyticsKey: String
}
Логика ветвления через словарь nextQuestionId: если пользователь выбрал опцию «Снижение стресса» — следующий вопрос q_stress_level, если «Лучший сон» — q_sleep_problems. «default» — для вопросов без ветвления. Конфигурация загружается с сервера или бандлится в приложении как JSON-файл.
QuestionnaireCoordinator управляет стеком вопросов: history: [String] для поддержки кнопки «Назад», currentQuestionId: String, answers: [String: Any] для накопления ответов. При нажатии «Назад» — history.popLast() и переход к предыдущему вопросу с сохранением выбранного ответа.
Как реализовать ветвление вопросов на Swift?
В центре — QuestionnaireCoordinator. Он получает конфигурацию, управляет историей и определяет следующий вопрос. Пример:
class QuestionnaireCoordinator {
private var history: [String] = []
private var currentQuestionId: String = "q_goal"
private var answers: [String: Any] = [:]
private let configuration: [String: OnboardingQuestion]
func goToNext(selectedOptionId: String) {
guard let question = configuration[currentQuestionId],
let nextId = question.nextQuestionId[selectedOptionId] ?? question.nextQuestionId["default"]
else { return }
history.append(currentQuestionId)
currentQuestionId = nextId
}
func goBack() {
guard let previous = history.popLast() else { return }
currentQuestionId = previous
}
func currentQuestion() -> OnboardingQuestion? {
configuration[currentQuestionId]
}
}
UI анкеты
Навигация между вопросами
Переход между экранами вопросов — горизонтальная анимация. На iOS: UIPageViewController в .scroll стиле или UIView.transition(with:duration:options:animations:) с .transitionCurlUp для необычного ощущения. В SwiftUI — TabView с tabViewStyle(.page) при фиксированном selection не даёт автосвайп назад пользователем — это нужно контролировать через interactiveDismissDisabled.
Лучший вариант — кастомная анимация через withAnimation(.spring(response: 0.4, dampingFraction: 0.8)) с offset и opacity. Дает полный контроль: вперёд — слайд влево, назад — слайд вправо.
Типы вопросов
Single choice — список карточек или пунктов, тап немедленно переходит к следующему вопросу (без «Далее»). Haptic .selection при выборе. Выбранная карточка — анимированное изменение background и border.
Multi choice — чекбоксы или карточки с multiple selection. Кнопка «Далее» появляется после выбора хотя бы одного варианта. LazyVGrid / FlowLayout для карточек с тегами.
Slider — UISlider / Slider в SwiftUI для числовых значений (возраст, частота, уровень). Лейблы по краям для понятного контекста. Haptic .selection при кратных значениях.
Progress indicator
Прогресс-бар сверху показывает положение в анкете. Анимированный LinearProgressView / LinearProgressIndicator. Не показываем точный шаг («3 из 7») — пользователь видит конец и может бросить. Показываем только bar без числовых меток.
Сравнение линейной и ветвящейся анкеты
| Параметр | Линейная анкета | Анкета с ветвлением |
|---|---|---|
| Количество вопросов | Фиксированное (5-7) | Зависит от ответов (3-10) |
| Конфигурация | Хардкод | Server-driven JSON |
| Аналитика | Минимальная | Детальная (Firebase Analytics) |
| Срок разработки | 2 дня | 3 дня |
Компоненты UI по платформам
| Компонент | iOS | Android |
|---|---|---|
| Single choice | SwiftUI List + onTapGesture |
Jetpack Compose LazyColumn + clickable |
| Multi choice | SwiftUI LazyVGrid с чекбоксами |
Compose LazyVerticalGrid с Checkbox |
| Slider | SwiftUI Slider |
Compose Slider |
| Progress bar | SwiftUI ProgressView |
Compose LinearProgressIndicator |
Пример конфигурационного JSON
{
"questions": [
{
"id": "q_goal",
"type": "singleChoice",
"title": "Зачем вы используете приложение?",
"options": [
{ "id": "stress", "title": "Снижение стресса" },
{ "id": "sleep", "title": "Лучший сон" }
],
"nextQuestionId": {
"stress": "q_stress_level",
"sleep": "q_sleep_problems",
"default": "q_time"
},
"analyticsKey": "goal_selection"
}
]
}
Персонализация результата и аналитика
После завершения анкеты собираем UserProfile из ответов:
struct UserProfile {
let primaryGoal: Goal // из вопроса q_goal
let experienceLevel: Level // из вопроса q_experience
let preferredTopics: [Topic] // из вопроса q_topics (multi)
let availableTime: Int // минут в день из вопроса q_time
}
Этот профиль определяет: какой контент показывается на главном экране, какие push-уведомления отправляются, какие разделы скрыты/показаны, с каким уровнем сложности начинается пользователь. Профиль сохраняется локально (UserDefaults / DataStore) и синхронизируется с сервером — чтобы при переустановке или смене устройства пользователь не проходил анкету снова.
Аналитика. Firebase Analytics: questionnaire_started, questionnaire_step_completed (с step_id и time_spent), questionnaire_skipped (с at_step), questionnaire_completed. По этим данным видно — на каком вопросе пользователи уходят, какие ответы самые популярные, как влияет анкета на retention. Firebase Analytics — рекомендуемый инструмент для мониторинга.
Пропуск анкеты и редактирование
Кнопка «Пропустить» — всегда. Не все хотят рассказывать о себе. Пропустившим показываем дефолтный контент и периодически (через 3–7 дней) ненавязчиво предлагаем заполнить «для лучших рекомендаций».
Возможность изменить ответы позже — в настройках профиля. Не запирать пользователя в первоначальном выборе. OnboardingQuestionnaireView переиспользуется в settings с режимом edit — те же компоненты, но с pre-filled ответами и другим completion-action (обновление профиля вместо перехода к главному экрану).
Что входит в работу
- Конфигурационный JSON-файл анкеты с поддержкой ветвления
-
QuestionnaireCoordinatorна Swift или Kotlin - UI-компоненты (SingleChoice, MultiChoice, Slider, ProgressBar)
- Интеграция аналитики Firebase
- Возможность редактирования профиля в настройках
- Документация по использованию
Срок: 2–3 дня. Линейная анкета из 5–7 вопросов с simple choice и применением результата к начальному контенту — 2 дня. Анкета с ветвлением, server-driven конфигурацией, несколькими типами вопросов, аналитикой и редактированием в профиле — 3 дня. Свяжитесь с нами для оценки проекта. Получите консультацию по онбордингу бесплатно.







