В инете есть куча сервисов для АБ тестов, и у всех одна проблема - они работают в браузере. При сравнении двух страниц у юзера сперва скачивается контент оригинальной, потом отрабатывает код эксперимента, который решает показать "счастливчику" альтернативный вариант, и только после этого наконец стартует закачка нужной страницы. В итоге пользователи видят прыгающий UI, ждут дольше необходимого и вообще получают 👎 экспириенс, что не может не сказаться на конверсии.
Тем не менее, у сторонних сервисов часто бывают шире возможности по сегментации трафика, они позволяют быстро тестировать мелкие изменения, которые вполне можно реализовать на клиенте, и самое главное - они экономят время аналитика на адхоки с текущим срезом. То есть, за нами остаётся выбор варианта на сервере там, где это важно. Теперь разберем серверную реализацию в Google Optimize.
Содержание
Как устроены АБ тесты в Google Optimize
Optimize в основе использует проверенную систему из Google Analytics. Для каждого сеанса участника передаются параметры с идентификатором эксперимента и номером варианта. Причем эту информацию достаточно отправить один раз, далее она приклеится к clientId
и будет сопровождать его, пока эксперимент не остановят.
Как завести там эксперимент, подробно описано в доке. Потыкайте че-нибудь, лишь бы получить идентификатор эксперимента, он выглядит примерно так:
Нумерация вариантов начинается с 0 и соответствуют порядку, указанному в настройках эксперимента.
Итого
Для каждого нового посетителя нужно хотя бы разок намекнуть аналитиксу, в каком эксперименте он участвует, и в какой группе относится.
Как сделать эксперимент на серверной стороне
Естественно, не обойтись без доработки на бэкэнде, но алгоритм простой, не волнуйтесь и держите меня за ✋
- проверяем 🍪
- выбираем вариант
- отдаем контент для выбранного варианта на клиент вместе с записью в 🍪
Как передать данные в Google Analytics
Теперь, чтобы магия случилась, нужно передать инфу в аналитикс. Бэкэнд разработчик еще не успел далеко уйти, так что просим they/them вместе с выбранным вариантом контента отправлять на клиент примерно такой код:
window.dataLayer = window.dataLayer || []
window.dataLayer.push({
event: 'testAB',
details: {
// идентификатор эксперимента из Optimize или внутренний
expId: 'QdJh06NITaWQ6N9RNR3N1g',
// номер варианта
expVar: '0',
},
})
На данном этапе необязательно указывать значение
expId
именно из оптимайза, можно любое, лишь бы до поры до времени уникальное.
В Tag Manager понадобится триггер, реагирующий на Пользовательское событие testAB
, и тег, который осуществит передачу.
О зелененьком подробнее:
expId и expVar - поля счетчика, в которые нужно передать всю инфу об эксперименте
{{DL - details.expId}} - идентификатор эксперимента из
dataLayer
{{DL - details.expVar}} - номер варианта из
dataLayer
{{AB_NAMES}} - таблица поиска, которая превращает бездушный номер эксперимента во что-то понятное и незабываемое.
Для умненьких аналитиков рекомендую завести еще {{AB_IDS}}, которая будет отражать соответствие вашей внутренней нумерации тестов идентификаторам из Оптимайза. Это удобно, потому что какой-нибудь 42 в разговоре маглам проще осознать, чем набор 6ук30цифр, и потому что иногда тесты приходится заводить заново 😊.
Ответы на вопросы
- Нет, не надо плодить хиты. Достаточно отправить инфу о тесте в аналитикс один раз. Например, отдать код с
dataLayer
на клиент только при первичной простановке куки с вариантом. - Да, мы так и не поставили контейнер оптимайза на сайт, это необязательно.
- Да, никакие предпросмотры вариантов не работают, с чего бы.
- Да, в активных юзерах пусто, и это нормально.
- Да, оптимайз будет ждать конверсию юзера и в этом сеансе, и в следующем, и еще у их внуков.
- Да, экспериментальные сеансы продолжатся, даже если перестать отправлять данные в GA.
Новые участники больше не добавляются, но старые продолжают ходить на сайт, и пока мы не стопнем тест в самом Оптимайзе, принадлежность к группе так и будет сопровождать все их сеансы.
Данные АБ тестов в Bigquery
Для изучающих BQ вот пример запроса, которым можно получить общие данные по эксперименту.
with dates as (
select
'20190901' as first
, '20190915' as last
),
exp as (
select
experiment.experimentVariant as v
, count(distinct fullVisitorId) as u
from
`project.property.ga_sessions_*`
, dates
, unnest(hits) hits
, unnest(hits.experiment) experiment
where _table_suffix between dates.first and dates.last
and experiment.experimentId = 'QdJh06NITaWQ6N9RNR3N1g'
--and regexp_contains(hits.page.pagePath, r'/фильтр/по/странице')
group by 1
),
conv as (
select
experiment.experimentVariant as v
, count(distinct fullVisitorId) as u
from
`project.property.ga_sessions_*`
, dates
, unnest(hits) hits
, unnest(hits.experiment) experiment
where _table_suffix between dates.first and dates.last
and experiment.experimentId = 'QdJh06NITaWQ6N9RNR3N1g'
--and regexp_contains(hits.page.pagePath, r'/фильтр/по/странице')
and hits.eventInfo.eventCategory = 'конверсионное'
and hits.eventInfo.eventAction = 'событие'
group by 1
),
pivot as (
select
exp.v as variant
, exp.u as all_participants
, conv.u as converted
, replace(cast(round(conv.u/exp.u * 100, 2) as string), '.', ',') as conversion
from exp
left join conv
on exp.v = conv.v
)
select *
from pivot
order by 1 asc