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

26 KiB
Raw Blame History

🧪 Конкретный анализ 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

{
  "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

📍 Условие отправки:

// В 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]);

🔍 Как проверить в браузере

// 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

{
  "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

📍 Условие отправки:

// В 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]);

🔍 Как проверить в браузере

// 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"
}

Результат: Даже если пользователь вернется назад или перезагрузит страницу, события НЕ отправятся повторно.


🐛 Отладка

Проверка отправки первого теста

# 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

Проверка отправки второго теста

# 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

Проверка что оба события отправлены

// В консоли браузера:
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

useEffect(() => {
  if (currentScreenFlags.length === 0) return;
  
  currentScreenFlags.forEach((flag) => {
    const variant = activeVariants[flag];
    sendUnleashImpression(flag, variant); // ← ЗДЕСЬ
  });
}, [currentScreenFlags, activeVariants]);

Функция: src/lib/funnel/unleash/sendImpression.ts

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");
}