491 lines
16 KiB
Markdown
491 lines
16 KiB
Markdown
# 📊 Unleash AB Testing → Google Analytics - Подробная документация
|
||
|
||
## 🎯 Общая схема работы
|
||
|
||
```
|
||
1. Пользователь заходит в воронку
|
||
↓
|
||
2. UnleashProvider инициализируется (layout.tsx)
|
||
↓
|
||
3. FunnelUnleashWrapper собирает все флаги из воронки
|
||
↓
|
||
4. Unleash SDK загружает варианты флагов
|
||
↓
|
||
5. useUnleash подписывается на события "impression"
|
||
↓
|
||
6. При активации флага → отправка в Google Analytics
|
||
```
|
||
|
||
---
|
||
|
||
## 1️⃣ В какой момент отправляется событие
|
||
|
||
### Цепочка инициализации:
|
||
|
||
#### Шаг 1: Загрузка воронки
|
||
```tsx
|
||
// src/app/[funnelId]/layout.tsx
|
||
<UnleashProvider> {/* ← Инициализируется один раз */}
|
||
<PixelsProvider googleAnalyticsId={funnel.meta.googleAnalyticsId}>
|
||
{children}
|
||
</PixelsProvider>
|
||
</UnleashProvider>
|
||
```
|
||
|
||
#### Шаг 2: Сбор флагов из воронки
|
||
```tsx
|
||
// src/components/funnel/FunnelUnleashWrapper.tsx
|
||
export function FunnelUnleashWrapper({ funnel }) {
|
||
// Сканирует все экраны и собирает уникальные флаги
|
||
const allFlags = useMemo(() => {
|
||
const flags = new Set<string>();
|
||
|
||
funnel.screens.forEach((screen) => {
|
||
// Из вариантов экранов
|
||
screen.variants?.forEach(variant => {
|
||
variant.conditions.forEach(condition => {
|
||
if (condition.conditionType === "unleash") {
|
||
flags.add(condition.unleashFlag);
|
||
}
|
||
});
|
||
});
|
||
|
||
// Из правил навигации
|
||
screen.navigation?.rules?.forEach(rule => {
|
||
rule.conditions.forEach(condition => {
|
||
if (condition.conditionType === "unleash") {
|
||
flags.add(condition.unleashFlag);
|
||
}
|
||
});
|
||
});
|
||
});
|
||
|
||
return Array.from(flags);
|
||
}, [funnel.screens]);
|
||
|
||
// Получаем варианты для ВСЕХ флагов сразу
|
||
const flagVariants = allFlags.map(flag => {
|
||
const variant = useVariant(flag);
|
||
return { flag, variant: variant?.name };
|
||
});
|
||
}
|
||
```
|
||
|
||
#### Шаг 3: Подписка на события
|
||
```tsx
|
||
// src/lib/funnel/unleash/useUnleash.ts
|
||
useEffect(() => {
|
||
const handleImpression = (impressionEvent) => {
|
||
if (impressionEvent.enabled) {
|
||
// ✅ ОТПРАВКА В GA
|
||
window.gtag("event", "experiment_impression", {
|
||
app_name: "witlab-funnel",
|
||
feature: impressionEvent.featureName,
|
||
treatment: impressionEvent.variant,
|
||
});
|
||
}
|
||
};
|
||
|
||
unleashClient.on("impression", handleImpression);
|
||
|
||
return () => {
|
||
unleashClient.off("impression", handleImpression);
|
||
};
|
||
}, [unleashClient]);
|
||
```
|
||
|
||
### ⏰ Timing событий:
|
||
|
||
| Момент | Действие | Когда отправляется в GA |
|
||
|--------|----------|-------------------------|
|
||
| **T+0ms** | Пользователь открывает воронку | - |
|
||
| **T+100ms** | UnleashProvider подключается к Unleash | - |
|
||
| **T+300ms** | Unleash возвращает варианты флагов | ✅ **Здесь!** |
|
||
| **T+300ms** | Unleash SDK эмитит событие "impression" | ✅ **И здесь!** |
|
||
| **T+301ms** | useUnleash ловит событие → window.gtag() | ✅ **События отправлены** |
|
||
| **T+500ms** | Воронка рендерится с правильными вариантами | - |
|
||
|
||
### 🔄 Повторная отправка:
|
||
|
||
**НЕТ повторных отправок** для одного флага в рамках сессии:
|
||
- Unleash SDK внутри помнит какие impression уже отправлены
|
||
- События эмитятся только **один раз** при первой активации флага
|
||
- При переходе между экранами события **НЕ отправляются повторно**
|
||
|
||
---
|
||
|
||
## 2️⃣ Какие данные отправляются
|
||
|
||
### Формат события в Google Analytics:
|
||
|
||
```javascript
|
||
window.gtag("event", "experiment_impression", {
|
||
app_name: "witlab-funnel", // Идентификатор приложения
|
||
feature: "trial-button-test", // Название флага из Unleash
|
||
treatment: "v1" // Вариант который получил пользователь
|
||
});
|
||
```
|
||
|
||
### Детали полей:
|
||
|
||
| Поле | Тип | Значение | Описание |
|
||
|------|-----|----------|----------|
|
||
| **event** | string | `"experiment_impression"` | Стандартное название для AB тестов в GA |
|
||
| **app_name** | string | `"witlab-funnel"` | Фиксированное имя приложения |
|
||
| **feature** | string | `impressionEvent.featureName` | Название флага из Unleash |
|
||
| **treatment** | string | `impressionEvent.variant` | Вариант: "v0", "v1", "v2", "disabled" и т.д. |
|
||
|
||
### Пример реальных данных:
|
||
|
||
```javascript
|
||
// AB тест кнопки оплаты
|
||
{
|
||
event: "experiment_impression",
|
||
app_name: "witlab-funnel",
|
||
feature: "trial-payment-button",
|
||
treatment: "v1"
|
||
}
|
||
|
||
// AB тест навигации
|
||
{
|
||
event: "experiment_impression",
|
||
app_name: "witlab-funnel",
|
||
feature: "onboarding-flow-test",
|
||
treatment: "short"
|
||
}
|
||
|
||
// Несколько флагов → несколько событий
|
||
{
|
||
event: "experiment_impression",
|
||
app_name: "witlab-funnel",
|
||
feature: "special-offer-test",
|
||
treatment: "v2"
|
||
}
|
||
```
|
||
|
||
### 📊 Как увидеть в Google Analytics:
|
||
|
||
1. **Realtime → Events**
|
||
- Событие: `experiment_impression`
|
||
- Параметры: `app_name`, `feature`, `treatment`
|
||
|
||
2. **Reports → Engagement → Events**
|
||
- Найти `experiment_impression`
|
||
- Посмотреть breakdown по `feature`
|
||
- Посмотреть distribution по `treatment`
|
||
|
||
3. **Создать кастомный отчет:**
|
||
```
|
||
Dimensions:
|
||
- Event name (experiment_impression)
|
||
- Event parameter: feature
|
||
- Event parameter: treatment
|
||
|
||
Metrics:
|
||
- Event count
|
||
- Users
|
||
```
|
||
|
||
---
|
||
|
||
## 3️⃣ Совпадает ли логика с aura-webapp
|
||
|
||
### ✅ Сходства (95% идентичны):
|
||
|
||
#### 1. Точно такой же механизм отправки:
|
||
```typescript
|
||
// ✅ WITLAB-FUNNEL
|
||
unleashClient.on("impression", (impressionEvent) => {
|
||
window.gtag("event", "experiment_impression", {
|
||
app_name: "witlab-funnel",
|
||
feature: impressionEvent.featureName,
|
||
treatment: impressionEvent.variant,
|
||
});
|
||
});
|
||
|
||
// ✅ AURA-WEBAPP
|
||
unleashClient.on("impression", (impressionEvent: any) => {
|
||
window.gtag?.("event", "experiment_impression", {
|
||
app_name: impressionEvent.context.appName,
|
||
feature: impressionEvent.featureName,
|
||
treatment: impressionEvent.variant,
|
||
});
|
||
});
|
||
```
|
||
|
||
#### 2. Одинаковый формат события:
|
||
- Название: `"experiment_impression"`
|
||
- Параметры: `app_name`, `feature`, `treatment`
|
||
- Условие: только если `impressionEvent.enabled === true`
|
||
|
||
#### 3. Подписка в useEffect:
|
||
- В обоих случаях подписка через `unleashClient.on("impression")`
|
||
- В обоих случаях cleanup через `unleashClient.off("impression")`
|
||
|
||
### ⚠️ Различия (минимальные):
|
||
|
||
| Аспект | witlab-funnel | aura-webapp | Критично? |
|
||
|--------|---------------|-------------|-----------|
|
||
| **app_name** | Хардкод `"witlab-funnel"` | Из `context.appName` | ⚠️ Да* |
|
||
| **window.gtag** | `window.gtag` | `window.gtag?.` | ✅ Нет |
|
||
| **Debug логи** | ✅ Есть в dev | ❌ Нет | ✅ Нет |
|
||
| **Типизация** | Явная типизация | `any` | ✅ Нет |
|
||
|
||
**\* Рекомендация:** Можно улучшить чтобы брать из context:
|
||
|
||
```typescript
|
||
// Улучшенная версия (опционально)
|
||
window.gtag("event", "experiment_impression", {
|
||
app_name: impressionEvent.context?.appName || "witlab-funnel",
|
||
feature: impressionEvent.featureName,
|
||
treatment: impressionEvent.variant,
|
||
});
|
||
```
|
||
|
||
### 📋 Вывод по совместимости:
|
||
|
||
✅ **Логика полностью совместима**
|
||
- События будут выглядеть одинаково в GA
|
||
- Можно создать единые отчеты для обоих приложений
|
||
- Единственная разница - в `app_name` (можно использовать для фильтрации)
|
||
|
||
---
|
||
|
||
## 4️⃣ Что если Google Analytics не установлена
|
||
|
||
### Сценарий: GA не настроена
|
||
|
||
```tsx
|
||
// В воронке:
|
||
{
|
||
"meta": {
|
||
"googleAnalyticsId": undefined // ← Не указан
|
||
}
|
||
}
|
||
```
|
||
|
||
### ✅ Защита от ошибок:
|
||
|
||
```typescript
|
||
// src/lib/funnel/unleash/useUnleash.ts
|
||
if (typeof window !== "undefined" && window.gtag) {
|
||
// ^^^^^^^^^^^^
|
||
// Проверка что gtag существует
|
||
window.gtag("event", "experiment_impression", {...});
|
||
}
|
||
```
|
||
|
||
### Что произойдет:
|
||
|
||
1. ✅ **Unleash продолжит работать нормально**
|
||
- Флаги загружаются
|
||
- Варианты применяются
|
||
- AB тесты работают
|
||
|
||
2. ✅ **Событие "impression" будет эмититься**
|
||
- `unleashClient.on("impression")` сработает
|
||
- `handleImpression()` будет вызван
|
||
|
||
3. ⚠️ **Отправка в GA будет пропущена**
|
||
- Проверка `window.gtag` вернет `false`
|
||
- Блок с `window.gtag()` НЕ выполнится
|
||
- **Никакой ошибки не будет**
|
||
|
||
4. 🐛 **Debug логи все равно работают**
|
||
```javascript
|
||
// В консоли браузера (в dev):
|
||
[Unleash Analytics] {
|
||
feature: "trial-button-test",
|
||
variant: "v1"
|
||
}
|
||
```
|
||
|
||
### Поведение в разных средах:
|
||
|
||
| Среда | GA установлена? | window.gtag? | Что происходит |
|
||
|-------|----------------|--------------|----------------|
|
||
| **Production с GA** | ✅ Да | ✅ Да | ✅ События отправляются |
|
||
| **Production без GA** | ❌ Нет | ❌ Нет | ✅ AB тесты работают, GA молчит |
|
||
| **Development с GA** | ✅ Да | ✅ Да | ✅ События + debug логи |
|
||
| **Development без GA** | ❌ Нет | ❌ Нет | ✅ AB тесты + debug логи |
|
||
| **Preview/Staging** | Зависит | Зависит | Зависит от настройки |
|
||
|
||
### Рекомендации:
|
||
|
||
#### ✅ Текущая реализация безопасна:
|
||
```typescript
|
||
// Нет ошибок если GA отсутствует
|
||
if (typeof window !== "undefined" && window.gtag) {
|
||
window.gtag(...); // Выполнится только если GA загружен
|
||
}
|
||
```
|
||
|
||
#### ⚠️ Можно добавить предупреждение (опционально):
|
||
```typescript
|
||
if (process.env.NODE_ENV === "development") {
|
||
if (typeof window !== "undefined" && !window.gtag) {
|
||
console.warn("[Unleash Analytics] Google Analytics not loaded");
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 🔍 Debug и мониторинг
|
||
|
||
### В development режиме:
|
||
|
||
```javascript
|
||
// Консоль браузера автоматически показывает:
|
||
[Unleash Analytics] { feature: "trial-test", variant: "v1" }
|
||
[Unleash Analytics] { feature: "button-test", variant: "v2" }
|
||
```
|
||
|
||
### Проверка отправки в GA:
|
||
|
||
#### 1. Через Network tab:
|
||
```
|
||
1. Откройте DevTools → Network
|
||
2. Фильтр: "collect" или "analytics"
|
||
3. Ищите POST запросы к:
|
||
- https://www.google-analytics.com/g/collect
|
||
- https://www.google-analytics.com/j/collect
|
||
4. В payload должны быть:
|
||
- en=experiment_impression
|
||
- ep.feature=trial-test
|
||
- ep.treatment=v1
|
||
```
|
||
|
||
#### 2. Через Google Analytics DebugView:
|
||
```bash
|
||
# 1. Включите debug mode
|
||
localStorage.setItem('ga_debug', '1')
|
||
|
||
# 2. Перезагрузите страницу
|
||
# 3. Откройте GA → Admin → DebugView
|
||
# 4. Увидите события в реальном времени
|
||
```
|
||
|
||
#### 3. Через расширение Google Analytics Debugger:
|
||
```
|
||
1. Установите Chrome extension "Google Analytics Debugger"
|
||
2. Включите его
|
||
3. В консоли увидите все GA события с деталями
|
||
```
|
||
|
||
---
|
||
|
||
## 📊 Пример полного flow
|
||
|
||
### Сценарий: Воронка с 2 AB тестами
|
||
|
||
```json
|
||
{
|
||
"meta": {
|
||
"googleAnalyticsId": "G-XXXXXXXXXX"
|
||
},
|
||
"screens": [
|
||
{
|
||
"id": "payment",
|
||
"variants": [
|
||
{
|
||
"conditions": [
|
||
{
|
||
"conditionType": "unleash",
|
||
"unleashFlag": "trial-button-test",
|
||
"unleashVariants": ["v1"]
|
||
}
|
||
]
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "gender",
|
||
"navigation": {
|
||
"rules": [
|
||
{
|
||
"conditions": [
|
||
{
|
||
"conditionType": "unleash",
|
||
"unleashFlag": "onboarding-flow",
|
||
"unleashVariants": ["short"]
|
||
}
|
||
]
|
||
}
|
||
]
|
||
}
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
### Timeline событий:
|
||
|
||
```
|
||
T+0ms: Пользователь открывает /soulmate/payment
|
||
T+50ms: UnleashProvider инициализируется
|
||
T+100ms: FunnelUnleashWrapper собирает флаги:
|
||
["trial-button-test", "onboarding-flow"]
|
||
T+300ms: Unleash возвращает варианты:
|
||
trial-button-test → v1
|
||
onboarding-flow → short
|
||
T+300ms: Unleash эмитит 2 impression события
|
||
T+301ms: useUnleash ловит события
|
||
T+301ms: ✅ Отправка в GA #1:
|
||
{
|
||
event: "experiment_impression",
|
||
app_name: "witlab-funnel",
|
||
feature: "trial-button-test",
|
||
treatment: "v1"
|
||
}
|
||
T+302ms: ✅ Отправка в GA #2:
|
||
{
|
||
event: "experiment_impression",
|
||
app_name: "witlab-funnel",
|
||
feature: "onboarding-flow",
|
||
treatment: "short"
|
||
}
|
||
T+500ms: FunnelLoadingScreen исчезает
|
||
T+501ms: Экран рендерится с правильными вариантами
|
||
```
|
||
|
||
### В консоли разработчика:
|
||
|
||
```
|
||
[Unleash Analytics] { feature: "trial-button-test", variant: "v1" }
|
||
[Unleash Analytics] { feature: "onboarding-flow", variant: "short" }
|
||
```
|
||
|
||
---
|
||
|
||
## 🎯 Итоговые выводы
|
||
|
||
### 1. Момент отправки:
|
||
✅ **При первой активации флага** (~300ms после загрузки воронки)
|
||
✅ **Только один раз** за сессию для каждого флага
|
||
✅ **Автоматически** без необходимости явного вызова
|
||
|
||
### 2. Данные:
|
||
✅ Событие: `"experiment_impression"`
|
||
✅ Параметры: `app_name`, `feature`, `treatment`
|
||
✅ Формат совместим с Google Analytics 4
|
||
|
||
### 3. Совместимость с aura-webapp:
|
||
✅ **95% идентично**
|
||
✅ Можно использовать единые GA отчеты
|
||
⚠️ Единственная разница: `app_name` (легко фильтровать)
|
||
|
||
### 4. Без Google Analytics:
|
||
✅ **AB тесты работают нормально**
|
||
✅ **Никаких ошибок**
|
||
✅ Debug логи в dev режиме
|
||
⚠️ События просто не отправляются (graceful degradation)
|
||
|
||
---
|
||
|
||
## 📚 См. также
|
||
|
||
- `AB_TESTING_GUIDE.md` - Общее руководство по AB тестам
|
||
- `AB_TESTING_UPDATES.md` - Технические детали и оптимизации
|
||
- `UNLEASH_SETUP.md` - Настройка Unleash
|