Давно вы залезали в доки гугла? Иногда мне кажется, что разночтений у них больше, чем у Библии, и они точно так же плодятся с добавлением новых глав и не слишком качественными переводами с языка оригинала. Сегодня попробуем разобраться в некоторых статьях, а заодно замутим ролевую игру с собаками и Павловым.
Содержание
Как создать эксперимент в Google Optimize
Сперва конечно же нужно в нем зарегистрироваться. После простановки всех галочек вы попадете на страницу контейнера
Здесь справа написано, что нужно потыкать в интерфейсе, и лучше я объяснить не в силах, а вот что мы рассмотрим подробно, так это установку на сайт. Есть две категории людей два варианта:
- Подключить контейнер Optimize в коде сниппета установки Google Analytics
- Создать тег в Google Tag Manager (но в код сайта придется лезть все равно)
Установка Optimize через Tag Manager
Страница в доках
https://support.google.com/tagmanager/answer/7164339?hl=ru
Возьмите идентификатор контейнера Optimize, который скрывается под первым пунктом на предыдущем скрине, и создайте вот такой тег:
Теперь идем в настройки тега Google Analytics и указываем, что перед ним нужно активировать тег Optimize:
Если ваш эксперимент каким-то образом переделывает внешний вид сайта, то скорее всего пользователь при загрузке увидит скачущие элементы, и это может повлиять на результат. Чтобы подобного не произошло, Google предлагает вот такой костыль:
<!-- Page-hiding snippet (recommended) -->
<style>
.async-hide {
opacity: 0 !important;
}
</style>
<script>
;(function (a, s, y, n, c, h, i, d, e) {
s.className += ' ' + y
h.start = 1 * new Date()
h.end = i = function () {
s.className = s.className.replace(RegExp(' ?' + y), '')
}
;(a[n] = a[n] || []).hide = h
setTimeout(function () {
i()
h.end = null
}, c)
h.timeout = c
})(window, document.documentElement, 'async-hide', 'dataLayer', 4000, {
'GTM-XXXXXX': true,
})
</script>
// здесь мог быть id именно вашего контейнера GTM
Он скрывает страницу на время внесения изменений. Обратите внимание, что в коде указывается id контейнера GTM, а не Optimize, если Optimize вы подключаете через GTM. Этот код рекомендуется вставлять сразу после meta тегов на сайте. Если изменение страницы занимает слишком много времени, то оно прерывается, пользователю показывается исходный вариант, и его участие в эксперименте отменяется.
Установка Optimize через сниппет Analytics
**Страница в доках **
https://support.google.com/360suite/optimize/answer/6262084?hl=ru
В этом случае просто подключите свой контейнер, добавив строку между созданием счетчика и отправкой pageview:
<script>
;(function (i, s, o, g, r, a, m) {
i['GoogleAnalyticsObject'] = r
;(i[r] =
i[r] ||
function () {
;(i[r].q = i[r].q || []).push(arguments)
}),
(i[r].l = 1 * new Date())
;(a = s.createElement(o)), (m = s.getElementsByTagName(o)[0])
a.async = 1
a.src = g
m.parentNode.insertBefore(a, m)
})(
window,
document,
'script',
'https://www.google-analytics.com/analytics.js',
'ga'
)
ga('create', 'UA-XXXXXXXX-X', 'auto')
ga('require', 'GTM-XXXXXX') // код контейнера Optimize
ga('send', 'pageview')
</script>
Код, делающий хорошо, в этом случае такой же, только вместо id GTM, в нем нужно указать идентификатор контейнера Optimize.
<!-- Page hiding snippet (recommended) -->
<style>
.async-hide {
opacity: 0 !important;
}
</style>
<script>
;(function (a, s, y, n, c, h, i, d, e) {
s.className += ' ' + y
h.start = 1 * new Date()
h.end = i = function () {
s.className = s.className.replace(RegExp(' ?' + y), '')
}
;(a[n] = a[n] || []).hide = h
setTimeout(function () {
i()
h.end = null
}, c)
h.timeout = c
})(window, document.documentElement, 'async-hide', 'dataLayer', 4000, {
'GTM-XXXXXX': true,
})
</script>
// идентификатор контейнера Optimize
Сравнение скорости загрузки
Конечно все эти эксперименты на клиентской стороне по большей части полная ерунда, но если уж пришлось строить из говна и палок, то давайте хотя бы выберем сорта получше. Чтобы отвлечься от тонны отчетов на работе определить оптимальный вариант, я написал скрипт для автоматического тестирования, сделал несколько сотен прогонов и вот результаты:
GA | GTM | |
---|---|---|
Тестов | 165 | 162 |
Среднее время (мс) | 414 | 753 |
Хотя вариант с GTM и грузится в два раза дольше, в реальности разница составляет всего 0,3 секунды, так что можно спокойно забить. Тем не менее вот инструкция, как повторить тест в домашних условиях:
- создаем две страницы с установкой через сниппет GA и через контейнер GTM
- рассчитываем время от начальной загрузки страницы до отработки изменения в контейнере Optimize
- собираем результаты в Google Spreadsheet
- зацикливаем, чтобы было весело, запускаем и смотрим
Код страницы с GTM
<html>
<head>
<script>
window.a = new Date().getTime()
</script>
<style>
.async-hide {
opacity: 0 !important;
}
</style>
<script>
;(function (a, s, y, n, c, h, i, d, e) {
s.className += ' ' + y
h.start = 1 * new Date()
h.end = i = function () {
s.className = s.className.replace(RegExp(' ?' + y), '')
}
;(a[n] = a[n] || []).hide = h
setTimeout(function () {
i()
h.end = null
}, c)
h.timeout = c
})(window, document.documentElement, 'async-hide', 'dataLayer', 4000, {
'GTM-XXXXXXXX': true,
})
</script>
// укажите свой id GTM, не Optimize
<!-- Google Tag Manager -->
<script>
;(function (w, d, s, l, i) {
w[l] = w[l] || []
w[l].push({ 'gtm.start': new Date().getTime(), event: 'gtm.js' })
var f = d.getElementsByTagName(s)[0],
j = d.createElement(s),
dl = l != 'dataLayer' ? '&l=' + l : ''
j.async = true
j.src = 'https://www.googletagmanager.com/gtm.js?id=' + i + dl
f.parentNode.insertBefore(j, f)
})(window, document, 'script', 'dataLayer', 'GTM-XXXXXXXX')
</script>
// укажите свой id GTM
<!-- End Google Tag Manager -->
</head>
<body>
<!-- Google Tag Manager (noscript) -->
<noscript
><iframe
src="https://www.googletagmanager.com/ns.html?id=GTM-XXXXXXXX"
height="0"
width="0"
style="display:none;visibility:hidden"
></iframe
></noscript>
<!-- End Google Tag Manager (noscript) -->
</body>
</html>
Код страницы c GA
<html>
<head>
<script>
window.a = new Date().getTime()
</script>
<style>
.async-hide {
opacity: 0 !important;
}
</style>
<script>
;(function (a, s, y, n, c, h, i, d, e) {
s.className += ' ' + y
h.start = 1 * new Date()
h.end = i = function () {
s.className = s.className.replace(RegExp(' ?' + y), '')
}
;(a[n] = a[n] || []).hide = h
setTimeout(function () {
i()
h.end = null
}, c)
h.timeout = c
})(window, document.documentElement, 'async-hide', 'dataLayer', 4000, {
'GTM-XXXXXXX': true,
})
</script>
// id контейнера Optimize
<script>
;(function (i, s, o, g, r, a, m) {
i['GoogleAnalyticsObject'] = r
;(i[r] =
i[r] ||
function () {
;(i[r].q = i[r].q || []).push(arguments)
}),
(i[r].l = 1 * new Date())
;(a = s.createElement(o)), (m = s.getElementsByTagName(o)[0])
a.async = 1
a.src = g
m.parentNode.insertBefore(a, m)
})(
window,
document,
'script',
'https://www.google-analytics.com/analytics.js',
'ga'
)
ga('create', 'UA-AAAAAAAA', 'auto') // id счетчика GA
ga('require', 'GTM-YYYYYYY') // id контейнера Optimize
ga('send', 'pageview')
</script>
</head>
<body>
Hello, test!
</body>
</html>
В настройках эксперимента в Optimize нужно выставить распределение 99,9% трафика на измененный вариант, чтобы скрипт всегда отрабатывал. Вот сам скрипт:
const b = new Date().getTime() - window.a
const c = ~document.location.href.indexOf('gtm') ? 'GTM' : 'Site'
const s = 'GTM' === c ? 'site' : 'gtm'
const t = !!~document.location.href.indexOf('test')
var promise = new Promise(function (resolve, reject) {
var img = new Image()
img.src =
'https://script.google.com/macros/s/AKfycbzSWcVj6kDobWCEK0qzljfNsfqCrpqpjBBVvd2GHyzohRp9N7W0/exec?s=' +
c +
'&Time=' +
b
resolve()
})
promise.then(() => {
if (!t) location.replace('https://burgerdata.com/exp/' + s + '/')
})
В этом куске я беру глобальную переменную window.a
, которая определяется при создании самих страниц и содержит время в миллисекундах на тот момент, и вычитаю из него текущее время. Результат отправляется в созданное приложение в Apps Script
, который записывает его в таблицы Spreadsheet
. Обратите внимание, что я использую вкладки GTM и Site, куда направляются результаты со страницы /gtm/ и /site/. Присутствует одна колонка с заголовком Time. Если захотите сравнить что-то еще, добавьте новую колонке и новый параметр в вызове скрипта.
Код приложения Apps Script:
var SHEET_KEY = "16FnXWKhtvGHyfqMjWy-PqIWpbm83M7VxGloAUNlrv2M"; // идентификатор таблицы, берется из url
function doGet(e){
SHEET_NAME = e.parameter.s;
var lock = LockService.getDocumentLock();
lock.waitLock(3000);
try {
var doc = SpreadsheetApp.openById(SHEET_KEY);
var sheet = doc.getSheetByName(SHEET_NAME);
var headRow = e.parameter.header || 1; //параметр header определяет ряд заголовков, по умолчанию первая строка
var headers = sheet.getRange(headRow, 1, 1, sheet.getLastColumn()).getValues()[0];
var row = [];
for (i in headers){
var l = e.parameter[headers[i]];
row.push(l);
}
sheet.getRange(sheet.getLastRow() + 1, 1, 1, row.length).setValues(\[row\]);
} catch(e){
return ContentService
.createTextOutput(JSON.stringify({"result":"error", "error": e}))
.setMimeType(ContentService.MimeType.JSON);
} finally {
lock.releaseLock();
}
}
В заключение
Все это ерунда, читайте про серверный вариант https://developers.google.com/analytics/solutions/experiments-server-side