w-funnel/docs/SOULMATE_AB_TESTS_TIMELINE.md
2025-10-23 21:16:09 +02:00

568 lines
26 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 🧪 Конкретный анализ AB-тестов в воронке Soulmate
## 📋 Два AB-теста в воронке
1. **`soulmate-onboarding-image`** - тест картинки/видео на первом экране
2. **`soulmate-trial-grid`** - тест навигации после email экрана
---
## 🎯 AB-тест #1: `soulmate-onboarding-image`
### 📍 Где находится в JSON
**Файл:** `public/funnels/soulmate.json`
**Экран:** `"onboarding"` (первый экран воронки)
**Строки:** 51-106
```json
{
"id": "onboarding",
"template": "soulmate",
"variants": [
{
"conditions": [{
"conditionType": "unleash",
"unleashFlag": "soulmate-onboarding-image",
"unleashVariants": ["v0"]
}],
"overrides": {}
},
{
"conditions": [{
"conditionType": "unleash",
"unleashFlag": "soulmate-onboarding-image",
"unleashVariants": ["v1"]
}],
"overrides": {
"soulmatePortraitsDelivered": {
"mediaUrl": "/images/90b8c77f-c0cd-475d-a4de-bcabb3708c59.png",
"mediaType": "image"
}
}
},
{
"conditions": [{
"conditionType": "unleash",
"unleashFlag": "soulmate-onboarding-image",
"unleashVariants": ["v2"]
}],
"overrides": {
"soulmatePortraitsDelivered": {
"mediaUrl": "/images/275472b0-30e0-47d7-a1ab-8090bc9fb236.mp4",
"mediaType": "video"
}
}
}
]
}
```
### 🎬 Что тестируется
Три варианта картинки/видео на первом экране:
- **v0** - дефолтное изображение `/soulmate-portrait-delivered-male.jpg`
- **v1** - альтернативное изображение (PNG)
- **v2** - видео (MP4)
### ⏱️ КОГДА ОТПРАВЛЯЕТСЯ impression событие
```
┌─────────────────────────────────────────────────────────┐
│ T+0ms: Пользователь открывает /soulmate/onboarding │
│ Это ПЕРВЫЙ экран воронки │
└─────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────┐
│ T+100ms: GoogleAnalytics загружается (gtag.js) │
│ window.gtag становится доступен │
└─────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────┐
│ T+200ms: FunnelUnleashWrapper сканирует ВСЮ воронку │
│ Находит флаги: │
│ • soulmate-onboarding-image (из onboarding) │
│ • soulmate-trial-grid (из email) │
└─────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────┐
│ T+300ms: Unleash SDK возвращает варианты │
│ • soulmate-onboarding-image → "v1" (например) │
│ • soulmate-trial-grid → "grid" (например) │
└─────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────┐
│ T+400ms: FunnelRuntime монтируется │
│ currentScreen = onboarding экран │
└─────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────┐
│ T+410ms: currentScreenFlags вычисляется │
│ Анализирует onboarding экран: │
│ • onboarding.variants → soulmate-onboarding-image│
│ • onboarding.navigation → нет флагов │
│ Результат: ["soulmate-onboarding-image"] │
└─────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────┐
│ T+420ms: useEffect срабатывает │
│ (FunnelRuntime.tsx, строки 136-150) │
│ │
│ ✅ sendUnleashImpression( │
│ "soulmate-onboarding-image", │
│ "v1" │
│ ) │
└─────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────┐
│ T+421ms: ✅ ОТПРАВКА В GOOGLE ANALYTICS │
│ │
│ window.gtag("event", "experiment_impression", { │
│ app_name: "witlab-funnel", │
│ feature: "soulmate-onboarding-image", │
│ treatment: "v1" │
│ }); │
│ │
│ sessionStorage.setItem( │
│ "unleash_impression_soulmate-onboarding-image_v1", │
│ "true" │
│ ); │
└─────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────┐
│ Console (development): │
│ [Unleash Impression] ✅ Sent successfully: │
│ { │
│ feature: "soulmate-onboarding-image", │
│ variant: "v1" │
│ } │
└─────────────────────────────────────────────────────────┘
```
### 📊 Когда КОНКРЕТНО
**✅ Impression отправляется:** Сразу при входе пользователя в воронку на ПЕРВЫЙ экран "onboarding"
**⏰ Timing:** ~420ms после загрузки страницы `/soulmate/onboarding`
**🔧 Код:**
- **Файл:** `src/components/funnel/FunnelRuntime.tsx` (строки 136-150)
- **Функция:** `sendUnleashImpression()` из `src/lib/funnel/unleash/sendImpression.ts`
**📍 Условие отправки:**
```typescript
// В FunnelRuntime.tsx
const currentScreenFlags = useMemo(() => {
const flags = new Set<string>();
// Сканирует onboarding.variants
currentScreen.variants?.forEach((variant) => {
variant.conditions.forEach((condition) => {
if (condition.conditionType === "unleash" && condition.unleashFlag) {
flags.add(condition.unleashFlag); // ← "soulmate-onboarding-image"
}
});
});
return Array.from(flags); // ["soulmate-onboarding-image"]
}, [currentScreen]);
useEffect(() => {
if (currentScreenFlags.length === 0) return;
currentScreenFlags.forEach((flag) => {
const variant = activeVariants[flag]; // "v1"
sendUnleashImpression(flag, variant); // ← ОТПРАВКА
});
}, [currentScreenFlags, activeVariants]);
```
### 🔍 Как проверить в браузере
```javascript
// 1. Открыть /soulmate/onboarding
// 2. Открыть DevTools → Console
// 3. Увидеть:
[Unleash Impression] Sent successfully: {
feature: "soulmate-onboarding-image",
variant: "v1" // или "v0", "v2"
}
// 4. DevTools → Network → Фильтр "collect"
POST /g/collect?...&en=experiment_impression
&ep.feature=soulmate-onboarding-image
&ep.treatment=v1
// 5. DevTools → Application → Session Storage
unleash_impression_soulmate-onboarding-image_v1: "true"
```
---
## 🎯 AB-тест #2: `soulmate-trial-grid`
### 📍 Где находится в JSON
**Файл:** `public/funnels/soulmate.json`
**Экран:** `"email"` (экран ввода email)
**Строки:** 2277-2309
```json
{
"id": "email",
"template": "email",
"navigation": {
"rules": [
{
"conditions": [{
"conditionType": "unleash",
"unleashFlag": "soulmate-trial-grid",
"unleashVariants": ["coupon"]
}],
"nextScreenId": "coupon"
},
{
"conditions": [{
"conditionType": "unleash",
"unleashFlag": "soulmate-trial-grid",
"unleashVariants": ["grid"]
}],
"nextScreenId": "trial-choice"
}
],
"defaultNextScreenId": "coupon"
}
}
```
### 🎬 Что тестируется
Два варианта навигации после email экрана:
- **coupon** - переход на экран с купоном (`coupon`)
- **grid** - переход на экран с выбором тарифов (`trial-choice`)
### ⏱️ КОГДА ОТПРАВЛЯЕТСЯ impression событие
```
┌─────────────────────────────────────────────────────────┐
│ Пользователь прошел всю воронку: │
│ onboarding → gender → partner-gender → ... → email │
└─────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────┐
│ T+0ms: Пользователь попадает на экран /soulmate/email │
│ Это 19-й экран воронки (почти в конце) │
└─────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────┐
│ ВАЖНО: Unleash уже загружен! │
│ activeVariants уже содержит: │
│ { │
│ "soulmate-onboarding-image": "v1", ← уже отправлено │
│ "soulmate-trial-grid": "grid" ← еще НЕ отправлено│
│ } │
└─────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────┐
│ T+100ms: FunnelRuntime обновляется │
│ currentScreen = email экран │
└─────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────┐
│ T+110ms: currentScreenFlags пересчитывается │
│ Анализирует email экран: │
│ • email.variants → нет unleash флагов │
│ • email.navigation.rules → soulmate-trial-grid │
│ Результат: ["soulmate-trial-grid"] │
└─────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────┐
│ T+120ms: useEffect срабатывает │
│ (FunnelRuntime.tsx, строки 136-150) │
│ │
│ ✅ sendUnleashImpression( │
│ "soulmate-trial-grid", │
│ "grid" │
│ ) │
└─────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────┐
│ T+121ms: Проверка sessionStorage: │
│ "unleash_impression_soulmate-trial-grid_grid" │
НЕ найдено ✅ (первый раз на этом экране) │
└─────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────┐
│ T+122ms: ✅ ОТПРАВКА В GOOGLE ANALYTICS │
│ │
│ window.gtag("event", "experiment_impression", { │
│ app_name: "witlab-funnel", │
│ feature: "soulmate-trial-grid", │
│ treatment: "grid" │
│ }); │
│ │
│ sessionStorage.setItem( │
│ "unleash_impression_soulmate-trial-grid_grid", │
│ "true" │
│ ); │
└─────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────┐
│ Console (development): │
│ [Unleash Impression] ✅ Sent successfully: │
│ { │
│ feature: "soulmate-trial-grid", │
│ variant: "grid" │
│ } │
└─────────────────────────────────────────────────────────┘
```
### 📊 Когда КОНКРЕТНО
**✅ Impression отправляется:** Когда пользователь доходит до экрана "email" (19-й экран воронки)
**⏰ Timing:** ~120ms после перехода на `/soulmate/email`
**🔧 Код:**
- **Файл:** `src/components/funnel/FunnelRuntime.tsx` (строки 136-150)
- **Функция:** `sendUnleashImpression()` из `src/lib/funnel/unleash/sendImpression.ts`
**📍 Условие отправки:**
```typescript
// В FunnelRuntime.tsx
const currentScreenFlags = useMemo(() => {
const flags = new Set<string>();
// Сканирует email.variants (пусто)
// ...
// Сканирует email.navigation.rules
currentScreen.navigation?.rules?.forEach((rule) => {
rule.conditions.forEach((condition) => {
if (condition.conditionType === "unleash" && condition.unleashFlag) {
flags.add(condition.unleashFlag); // ← "soulmate-trial-grid"
}
});
});
return Array.from(flags); // ["soulmate-trial-grid"]
}, [currentScreen]);
useEffect(() => {
if (currentScreenFlags.length === 0) return;
currentScreenFlags.forEach((flag) => {
const variant = activeVariants[flag]; // "grid"
sendUnleashImpression(flag, variant); // ← ОТПРАВКА
});
}, [currentScreenFlags, activeVariants]);
```
### 🔍 Как проверить в браузере
```javascript
// 1. Пройти всю воронку до экрана email: /soulmate/email
// 2. Открыть DevTools → Console
// 3. Увидеть:
[Unleash Impression] Sent successfully: {
feature: "soulmate-trial-grid",
variant: "grid" // или "coupon"
}
// 4. DevTools → Network → Фильтр "collect"
POST /g/collect?...&en=experiment_impression
&ep.feature=soulmate-trial-grid
&ep.treatment=grid
// 5. DevTools → Application → Session Storage
// Должно быть 2 ключа:
unleash_impression_soulmate-onboarding-image_v1: "true"
unleash_impression_soulmate-trial-grid_grid: "true"
```
---
## 📊 Сравнительная таблица
| Аспект | soulmate-onboarding-image | soulmate-trial-grid |
|--------|---------------------------|---------------------|
| **Экран** | `onboarding` (1-й экран) | `email` (19-й экран) |
| **Позиция в JSON** | `variants` | `navigation.rules` |
| **Что тестирует** | Картинка/видео на первом экране | Навигация после email |
| **Варианты** | v0, v1, v2 | coupon, grid |
| **Когда отправляется** | Сразу при входе в воронку | При достижении email экрана |
| **Timing** | T+420ms после загрузки | T+120ms после перехода на email |
| **URL** | `/soulmate/onboarding` | `/soulmate/email` |
---
## 🎯 Финальная timeline для полной воронки
```
T+0ms Пользователь открывает /soulmate/onboarding
T+420ms ✅ IMPRESSION #1: soulmate-onboarding-image → v1
T+5min Пользователь проходит всю воронку
│ (gender, partner-gender, analysis-target, partner-age,
│ partner-ethnicity, partner-eye-color, partner-hair-length,
│ burnout-support, burnout-result, birthdate,
│ nature-archetype, love-priority, love-priority-result,
│ relationship-block, qualities, qualities-result,
│ progress, progress-result)
T+5min Пользователь доходит до /soulmate/email
T+5min ✅ IMPRESSION #2: soulmate-trial-grid → grid
+120ms │
T+5min Пользователь вводит email и нажимает Continue
+1min │
└─ Переход на trial-choice (если variant = "grid")
ИЛИ
Переход на coupon (если variant = "coupon")
```
---
## 📝 Ключевые моменты
### 1. Оба флага загружаются ЗАРАНЕЕ
```
FunnelUnleashWrapper сканирует ВСЮ воронку при загрузке
→ Находит оба флага сразу:
• soulmate-onboarding-image
• soulmate-trial-grid
→ Unleash SDK загружает варианты для ОБОИХ флагов
→ Варианты сохраняются в activeVariants
```
**Результат:** Быстрый переход между экранами (флаги уже загружены).
### 2. Impression отправляются ПОСЛЕДОВАТЕЛЬНО
```
Экран onboarding → impression для soulmate-onboarding-image
Экран email → impression для soulmate-trial-grid
```
**Результат:** Точная аналитика - события отправляются только когда пользователь РЕАЛЬНО видит экран.
### 3. Защита от дубликатов работает
```
sessionStorage хранит:
{
"unleash_impression_soulmate-onboarding-image_v1": "true",
"unleash_impression_soulmate-trial-grid_grid": "true"
}
```
**Результат:** Даже если пользователь вернется назад или перезагрузит страницу, события НЕ отправятся повторно.
---
## 🐛 Отладка
### Проверка отправки первого теста
```bash
# 1. Открыть /soulmate/onboarding
# 2. В консоли должно появиться:
[Unleash Impression] ✅ Sent successfully: {
feature: "soulmate-onboarding-image",
variant: "v1"
}
# 3. В Network tab:
POST /g/collect?...
&ep.feature=soulmate-onboarding-image
&ep.treatment=v1
```
### Проверка отправки второго теста
```bash
# 1. Пройти до /soulmate/email
# 2. В консоли должно появиться:
[Unleash Impression] ✅ Sent successfully: {
feature: "soulmate-trial-grid",
variant: "grid"
}
# 3. В Network tab:
POST /g/collect?...
&ep.feature=soulmate-trial-grid
&ep.treatment=grid
```
### Проверка что оба события отправлены
```javascript
// В консоли браузера:
Object.keys(sessionStorage)
.filter(key => key.startsWith("unleash_impression_"))
.forEach(key => console.log(key, sessionStorage.getItem(key)));
// Вывод (если пользователь дошел до email):
// unleash_impression_soulmate-onboarding-image_v1 "true"
// unleash_impression_soulmate-trial-grid_grid "true"
```
---
## ✅ Итоговый ответ
### Когда отправляется `soulmate-onboarding-image`?
**🎯 Сразу при входе в воронку на первый экран "onboarding"**
- URL: `/soulmate/onboarding`
- Timing: ~420ms после загрузки страницы
- Экран: 1-й из ~20 экранов воронки
### Когда отправляется `soulmate-trial-grid`?
**🎯 Когда пользователь доходит до экрана "email" (почти в конце воронки)**
- URL: `/soulmate/email`
- Timing: ~120ms после перехода на экран
- Экран: 19-й из ~20 экранов воронки
### Код отправки (для обоих)
**Файл:** `src/components/funnel/FunnelRuntime.tsx`
**Строки:** 136-150
```typescript
useEffect(() => {
if (currentScreenFlags.length === 0) return;
currentScreenFlags.forEach((flag) => {
const variant = activeVariants[flag];
sendUnleashImpression(flag, variant); // ← ЗДЕСЬ
});
}, [currentScreenFlags, activeVariants]);
```
**Функция:** `src/lib/funnel/unleash/sendImpression.ts`
```typescript
export function sendUnleashImpression(flag: string, variant: string | undefined) {
// Проверки...
window.gtag("event", "experiment_impression", {
app_name: "witlab-funnel",
feature: flag,
treatment: variant,
});
sessionStorage.setItem(`unleash_impression_${flag}_${variant}`, "true");
}
```