Каждый сайт в целом, и страница в частности, состоят из отдельных блоков. Одним из таких блоков является, так называемый, CallToAction (Призыв к действию) – какая-то побудительная фраза или предложение + элемент для действия (номер телефона для звонка, кнопка заказа…). Часто такие блоки являются типовыми не только по своему строению, но и по содержанию. Со строением всё просто: сперва (обычно) идет торговое предложение, затем призыв к действию и само действие. Например:
Нужна помощь вебмастера? Звоните мне по телефону +7(985)287-83-73
или оставьте заявку
Знакомый блок? Конечно, все мы такое видим чуть ли не на каждом сайте, да и на своих используем. А как правильно составлять такие блоки? Указывать ли в них цену, или лучше писать что-то типа «Узнайте стоимость по телефону…»? Нужно ли писать на кнопке: «Заказать», «Купить», «Оформить заказ»…? В некоторых случаях ответ будет очевиден, в других – нет. Найти истину помогает только A/B тестирование. Вот и я решил такое тестирование провести на одном из рабочих сайтов. И теперь делюсь с вами моим вариантом решения этой задачи.
Анализ исходных данных и планирование действий
Итак, что мы имеем:
- Есть несколько тестируемых вариантов CallToAction;
- Трафик из рекламных систем (Директ и Adwords);
- Лендинг на Joomla;
- Конверсия в заявки и звонки;
С первым пунктом всё примерно понятно, составили несколько (в нашем случае 6) вариантов «Призывов к действию» и будем мерить их конверсию. Для простоты, будем называть их УТП – универсальные торговые предложения, чем они и являются по сути.
С трафиком всё гораздо сложнее, ведь он и от времени суток зависит и от региона, и от объявления…
CMS сайта особой роли не играет, хотя у Битрикса есть встроенный модуль А/Б тестов. В моем случае сайт работает на Джумле и я буду писать собственный скрипт.
С замером конверсии тоже есть один нюанс: тестируемый блок может влиять не только на количество кликов на кнопку заказа, но и на звонки. Замерить эффективность кнопки – задача элементарная, всего-то нужно разные цели в Метрике привязать. А вот со звонками всё гораздо сложнее. Сами звонки мы и так отслеживаем и анализируем с помощью КоМеджика (CoMagic) и динамических номеров. Но у нас планируется 6 вариантов страниц. Даже на одной странице используется несколько динамических телефонных номеров (каждый из которых стоит денежку), а 6 разных страниц означает расширение пула номеров (а значит и финансовые траты). Так что разные страницы (а именно так обычно и делают) – для меня не вариант. Я буду делать всё на одной странице.
Теперь можно составить примерную логику будущего скрипта с учетом исходных данных и технических особенностей.
Для начала нужно понять все шаги пользователя от захода на сайт, до целевого действия:
- Посетитель перешел на страницу;
- Отрабатывает CMS и PHP до загрузки страницы (серверная часть);
- Загружается страница;
- Загружается скрипт КоМеджика и прочие скрипты (пользовательская часть);
- Подставляются динамические данные и пользователь видит конечный вариант страницы;
- Пользователь совершает одно из целевых действий (отправка формы, или звонок).
Первая проблема – посетитель получает идентификационные метки только после загрузки JS-скрипта CoMagic. Если подмена номеров с помощью JS это довольно быстрый процесс, то замена блоков сайта может занять несколько секунд (в зависимости и от скорости загрузки скриптов, и мощности компа пользователя), так что посетитель может заметить изменение информации, что на мой взгляд, является недопустимым.
Вторая проблема – идентификация пользователя при звонке. Работает это примерно так: посетителю подставляется один из номеров телефона (этот же номер будет подставляться ему при последующих заходах). В карточку клиента заносятся данные об источнике трафика… Система отслеживает звонки на динамические номера и сопоставляет номера с пользователями, находившимися на тот момент на сайте.
Третья проблема – выдать уникальный УТП. Сперва я планировал генерировать их рандомом, но этот вариант был подвергнут некоторым сомнениям. В моем случае вариантов УТП будет 6, сможет ли рандом адекватно генерировать уникальное УТП (1 из 6)? В рамках одной сессии – возможно. А вот учитывая поток трафика (т.е. множество сессий) это под вопросом. Значит нужно как-то понять – какое УТП было выдано и какое выдавать следующим.
Теперь сформировалось некоторое видение картины в целом, и можно переходить к следующему этапу.
Составление технического ТЗ
Составить грамотное техническое задание – это уже половина дела, ведь оно описывает необходимые действия…
Начнем с посетителей: они могут быть как уникальными (У), так и вернувшимися (В). Группе У можно смело выдавать новый вариант УТП, а вот группе В нужно выдать то УТП, которое они получили при первом посещении, и при этом, как я уже говорил, УТП должно генерироваться на уровне сервера, чтобы пользователь не видел меняющихся блоков. Единственный способ «запомнить» посетителя – Cookie (печеньки). Значит если условие У, то генерируем вариант УТП и даем соответствующую печеньку, иначе (условие В) – проверяем печеньку и выдаем УТП из нее. Выпечкой у нас будет заниматься PHP.
Далее идут звонки. Чтобы сопоставить звонок и УТП нужно передать в CoMagic (далее КМ) нечто вроде печеньки. Для этого в КМ есть «Свойство пользователя», т.е. какие-то метки, которые мы можем прикреплять к пользователям. Помним, что КМ грузится через JS, значит и передачу свойства нужно сразу после загрузки КМ. Ок, будем использовать JS.
Ну и генерация вариантов. Т.к. генерация УТП производится на уровне PHP, нужно в него как-то передать информацию о предыдущем посетителе, а точнее об УТП, которое ему было присвоено. Также нам нужно не только генерировать варианты УТП, но и подсчитывать, какой вариант сколько раз использовался. Чтобы не создавать отдельных таблиц в БД и не писать запросы к ней – будем сохранять данные в файл и из него же эти данные считывать.
Готово. С логикой разобрались и знаем, как и что должно работать. Остается заключительный этап:
Скрипты для А/Б теста
Как известно: не важно, какой скрипт написал программист, важно – чтобы скрипт решал поставленные задачи. Вот и мои скрипты не претендуют на звание простых, или правильных… Главное – что они работают и выполняют необходимые задачи. Я никого не учу, а просто делюсь опытом.
Итак, приступим к реализации. Сперва подготовим вспомогательные функции для генерации идентификатора УТП, чтения и записи в файл. Все данные будем записывать в массив, а он будет лежать в файле abtestlog.txt
.
1. Переменная для хранения имени файла (если хранить в корне. Если файл будет лежать в папке – указываем путь + имя файла):
<?php $file_name = "abtestlog.txt"; ?>
2. Функция для выбора идентификатора, на основе предыдущего:
<?php
function get_id($last){
if($last === 6):
return 1;
else:
return $last+1;
endif;
}
?>
В функцию передается 1 параметр – последний использованный вариант (его ИД). Если предыдущий вариант был с ИД равным максимальному количеству вариантов (у меня их всего 6), то выдаем вариант под номером 1, т.е. начинаем сначала. Если же предыдущий вариант не равен максимальному, тогда мы его увеличиваем на единицу.
3. Функция записи массива в файл. Тут есть нюанс - массив нельзя просто так записать в файл, его сначала нужно сериализовать, поэтому скрипт будет такой:
<?php
function array_to_file($data, $filename){
$serial_data = serialize($data);
$f = fopen($filename, 'w');
fwrite($f, $serial_data);
fclose($f);
}
?>
Теперь подготовим функцию чтения массива из файла + десериализация:
<?php
function array_from_file($filename){
$data = file_get_contents($filename);
$array = unserialize($data);
return $array;
}
?>
Инструменты готовы, теперь создадим наш главный файл. Я планирую и дальше использовать эти скрипты, поэтому чтобы не забыть создать нужный файл, если его еще нет - я буду его генерировать и добавлять в него массив с последним вариантом и счетчиками для каждого варианта:
<?php
if (file_exists($file_name)){
$file = fopen($file_name, "r+");
}else{
$file = fopen($file_name, "w+");
$array = array( 'last' => 1, 'var1' => 0, 'var2' => 0, 'var3' => 0, 'var4' => 0, 'var5' => 0, 'var6' => 0);
$serialized_array = serialize($array);
fwrite($file, $serialized_array);
}
?>
Пока файл открыт – получим из него наш массив с данными
<?php $abtest_log_data = array_from_file($filename); ?>
Обработка Cookie. Как уже было решено, если посетитель У – генерируем и присваиваем ИД УТП, если В – выдаем прикрепленный. Для скрипта я немного переделаю условие на: если В – ИД УТП из печенья; Иначе – уникальный ИД УТП + печенье.
Скрипт получается такой:
<?php
if(isset($_COOKIE['ABTest'])):
$variant_id = $_COOKIE['ABTest'];//если кука есть – берем ИД УТП из нее
else:
$variant_id = get_id($abtest_log_data['last']);//генерируем текущий ИД из предыдущего
setcookie("ABTest", $variant_id, time()+60*60*24*30);//записываем в куку текущий ИД, закрепляемый за посетителем. Ставим время жизни куки 30 дней.
$abtest_log_data["var$variant_id"]+=1;//увеличиваем счетчик у текущего варианта
$abtest_log_data['last'] = $variant_id;//записываем текущий ИД в качестве «последнего»
array_to_file($abtest_log_data, $file_name);//записываем данные в файл
endif;
fclose($file);//закрываем файл
?>
Вот в принципе и всё, PHP-скрипты для обработки данных готовы, теперь каждому уникальному посетителю будет выдаваться новый (по очереди) вариант УТП. Остается подготовить эти самые варианты. Я сделаю это через switch
<?php
switch($variant_id):
case 1:
$code = '<a class="button-1" href="#">Вариант №1</a>';
break;
case 2:
$code = '<a class="button-2" href="#">Вариант №2</a>';
break;
case 3:
$code = '<a class="button-3" href="#">Вариант №3</a>';
break;
case 4:
$code = '<a class="button-4" href="#">Вариант №4</a>';
break;
case 5:
$code = '<a class="button-5" href="#">Вариант №5</a>';
break;
case 6:
$code = '<a class="button-6" href="#">Вариант №6</a>';
break;
default:
$code = '<a class="button-default" href="#">Вариант по умолчанию</a>';
break;
endswitch;
?>
На тот случай, если возникнут проблемы с обработкой вариантов, или файла… - буду подставлять стандартную УТП
На этом серверная обработка закончена. Остается только в нужном месте заменить кнопку на <?php echo $code; ?>
и в принципе тестирование уже будет работать. Но без учета звонков.
Чтобы при А/Б тестировании учитывать и звонки – мне нужно передать закрепленный за клиентом ИД УТП в CoMagic в виде пользовательского свойства. Для этого напишу такой скрипт JS:
<script>
window.onload = function(){
function getABCookie(cookie_name){//функция для проверки Cookie
var results = document.cookie.match('(^|;) ?'+cookie_name+'=([^;]*)(;|$)');//ищем нужную куку
if(results){
return(unescape(results[2]));//если нашли – берем из нее ИД УТП и возвращаем
}else{
return null;//если не нашли – возвращаем ничегошку
}
}
var variantID = getABCookie("ABTest");//получаем ИД
if(variantID !==null){//если вернулась не ничегошка
Comagic.hasProperty('ABTest', function(resp){//проверяем наличие свойства в CM
if(resp !== true){
Comagic.setProperty('ABTest', variantID);//если свойства нет - устанавливаем
}
});
}
}
</script>
Готово. Все скрипты написаны, можно запускать в работу.
Нужна помощь вебмастера? Звоните мне по телефону +7(985)287-83-73
или оставьте заявку