Перейти до основного вмісту

A/B testing + conversion goals

Translator note: machine-translated baseline. Needs human review by a native UK speaker. EN source is canonical.

Per-campaign N variants з deterministic per-player assignment + conversion attribution проти будь-якої канонічної події.

Variants

Кожна campaign має 1..N rows у campaign_variants:

{
"name": "Variant A",
"label": "A", // короткий badge label
"template_id": "...", // оператор clones template, tweaks copy
"weight": 50, // relative weight 0..10000
"sort_order": 0
}

Weights не повинні sum to 100 — assignment normalises по total. Дві variants at weight=1 each = 50/50 split. Одна at 70, одна at 30 = 70/30.

Deterministic assignment

bucket = FNV1a32(`${campaign_id}|${player_id}`) mod sum_weights
variant = перший variant where cumulative_weight > bucket

Той самий гравець на тій самій campaign завжди потрапляє у той самий variant — навіть через re-sends. Запобігає variant-drift attribution mud.

Той самий гравець на різних campaigns може потрапляти у різні variants (campaign_id varies hash input).

Conversion goals

// На campaign:
{
"goal_event": "deposit_confirmed", // canonical event name
"goal_attribution_days": 7, // 1..90
"goal_value_property": "amount_base" // jsonpath для revenue attribution
}

GET /v1/campaigns/:id/conversion-stats joinить message_sends (PG) з raw_events (CH):

  • Для кожного гравця, що отримав message в (sent | delivered | opened | clicked) статусі,
  • Знайти найраніший goal_event у [sent_at, sent_at + attribution_days * 24h)
  • Group by variant_id → count + value sum

Earliest, тому що гравець може зробити goal кілька разів — credit ОДНУ conversion per гравець per campaign.

Stats response

{
"campaign_id": "...",
"goal_event": "deposit_confirmed",
"goal_attribution_days": 7,
"total_recipients": 3085,
"total_conversions": 151,
"variants": [
{
"variant_id": "...",
"variant_name": "Variant A",
"variant_label": "A",
"recipients": 1547,
"conversions": 87,
"conversion_rate": 0.0563,
"conversion_value": 870000 // sum у tenant base валюті у cents
},
{
"variant_id": "...",
"variant_name": "Variant B",
"variant_label": "B",
"recipients": 1538,
"conversions": 64,
"conversion_rate": 0.0416,
"conversion_value": 640000
}
],
"winner_variant_id": "...A's id"
}

Winner picker

Variant declared winner коли:

  1. Має найвищу conversion rate серед усіх variants
  2. Його recipients count is ≥ 30 (avoids declaring winners on noise)
  3. Tie-break: найвищий recipient count (more confidence) → first by sort_order

Below 30 sample size, winner_variant_id is null until more sends accumulate.

Mid-campaign weight changes

Operators можуть edit weights mid-campaign — only нові sends respect новий split. Already-enqueued message_sends keep their assigned variant_id so conversion attribution stays clean.