Эта история началась около 6 месяцев назад. Я тогда написал свой первый осмысленный модуль для Rails — Sourcebuster. И заодно получил инвайт на хабр за пост об этом модуле. На самом деле большая часть теории уже изложена по ссылке, и я не хочу копипастить старое. Вместо этого предлагаю вам перед прочтением этого поста ознакомится с предыдущим.
Для тех, кому лень — буквально абзац краткого содержания предыдущих серий. 6 месяцев назад я написал модуль для Ruby on Rails, который помогает определять источники постетителей сайта и использовать полученные данные для разных маркетингово-аналитических садомазо развлечений. Сейчас я решил познакомиться поближе с JS и портировал его на JavaScript, о чём и собираюсь рассказать в этом посте.
Github · Download from GitHub · Changelog · Test page
Далее документация будет обновляться на sbjs.rocks
Поскольку модуль написан на чистом JavaScript, не имеет зависимостей от сторонних библиотек и ему положить на фактическое содержание DOM’а, вызываться он может так рано, как вы посчитаете нужным. Чем выше вы поставите его в
Для тех, кому лень — буквально абзац краткого содержания предыдущих серий. 6 месяцев назад я написал модуль для Ruby on Rails, который помогает определять источники постетителей сайта и использовать полученные данные для разных маркетингово-аналитических садомазо развлечений. Сейчас я решил познакомиться поближе с JS и портировал его на JavaScript, о чём и собираюсь рассказать в этом посте.
Основные тезисы
- скрипт определяет параметры источников посетителей сайта и сохраняет данные в куки
- логика определения и перезаписи источников полностью повторяет логику Google Analytics
- скрипт полностью автономен в плане получения данных и не имеет зависимостей от сторонних штук (типа куки _utmz)
- написан на чистом JavaScript, без зависимостей от сторонних библиотек
- полученные данные можно использовать:
- для подмены номеров телефонов
- подмены контента на сайте (например, заголовков)
- сохранять вместе с формами, отправляемыми с сайта
- экспортировать в свои CRM или системы аналитики.
Ссылки
Github · Download from GitHub · Changelog · Test page
Далее документация будет обновляться на sbjs.rocks
Установка и настройка
Поскольку модуль написан на чистом JavaScript, не имеет зависимостей от сторонних библиотек и ему положить на фактическое содержание DOM’а, вызываться он может так рано, как вы посчитаете нужным. Чем выше вы поставите его в
страницы, тем раньше вы получите куки, данные из которых могут использоваться для манипуляций с объектами DOM’а.
Простая установка
Вставляем в страницы:
<script src="/path/to/sourcebuster.min.js" id="sbjs"></script>
Подходит для тех, кто:
- не использует поддомены на сайте
- считает органическим трафиком только переходы с Яндекса и Гугла (а остальное — неважно / погрешность / вставьте свой вариант)
Что вы получаете из коробки
- По умолчанию органическим трафиком считаются только переходы из выдачи Яндекс и Google.
- Продолжительность пользовательской сессии: 30 минут.
- В логику по умолчанию заложено, что на сайте не используются поддомены. Подробное разъяснение о настройке скрипта для работы с поддоменами см. ниже.
- ip пользователя по умолчанию не сохраняется.
Установка «для продвинутых пользователей ПК»
<script>
var _sbjs = _sbjs || [];
_sbjs.push(['_setSessionLength', 15]);
_sbjs.push(['_setBaseHost', 'statica.alexfedoseev.com']);
_sbjs.push(['_setTimeZoneOffset', 4]);
_sbjs.push(['_addOrganicSource', 'yahoo.com', 'p']);
_sbjs.push(['_addOrganicSource', 'bing.com', 'q', 'bing']);
_sbjs.push(['_addReferralSource', 'facebook.com', 'social']);
_sbjs.push(['_addReferralSource', 't.co', 'social', 'twitter.com']);
_sbjs.push(['_addReferralSource', 'plus.url.google.com', 'social', 'plus.google.com']);
</script>
<script src="/path/to/sourcebuster.min.js" id="sbjs"></script>
Вам нужно пульнуть в массив настроек свои хотелки через _sbjs.push
и сразу после этого загрузить основной скрипт.
Всего есть 7 видов пользовательских настроек:
- _setSessionLength
- _setBaseHost
- _setTimeZoneOffset
- _setCampaignParam
- _addOrganicSource
- _addReferralSource
- _setUserIP
Поехали по порядку.
_setSessionLength
_sbjs.push(['_setSessionLength', 15]);
Устанавливаем продолжительность сессии пользователя в минутах.
В рамках данного модуля это показатель влияет только на перезапись / не-перезапись реферального источника.
Несколько слов о перезаписи источников. Когда пользователь приходит в первый раз на сайт, мы получаем данные об источнике перехода. Этот же пользователь может вернуться на сайт с другого источника, и нам нужно либо перезаписать текущий источник, либо этого не делать. Логика перезаписи полностью повторяет логику Google Analytics:
- Переходы с utm-разметкой перезаписывают всё и всегда (даже самих себя).
- Переходы из органической выдачи аналогично — перезаписывают всё и всегда.
- Прямые переходы не перезаписывают никогда и ничего. Они фиксируются только в случае самого первого захода на сайт, при условии что других источников до этого зафиксировано не было.
- Реферальные переходы в рамках текущей сессии ничего не перезаписывают, перезапись происходит только при условии отсутствия сессии у пользователя. Почему — поясню на примере: часто посетитель в рамках текущего визита переходит на сайт со стороннего ресурса, который реальным источником не является — например из почтового сервиса, где у него была ссылка на активацию регистрации.
_setBaseHost
_sbjs.push(['_setBaseHost', 'alexfedoseev.com']);
Устанавливаем базовый хост, в рамках которого все переходы будут считаться внутренним (не реферальным) трафиком. Эта настройка актуальна, только если вы используете на своём сайте поддомены.
Сценарий 1
Предположим у вас есть сайт: site.com. На вашем сайте есть блог: blog.site.com. И вы хотите, чтобы переходы с сайта на блог и обратно считались внутренним трафиком: то есть источник blog.site.com не фиксировался как referral и не перезаписывал другие источники при новой сессии. Для этого нужно на страницах сайта и блога добавить строчку:
_sbjs.push(['_setBaseHost', 'site.com']);
При такой настройке, если пользователь перешел с blog.site.com на site.com (а также с alex.blog.site.com на site.com), источник не перезапишется и такой переход будет равноценен переходу с site.com/about на site.com/contacts.
Сценарий 2
Теперь рассмотрим противоположенный сценарий: когда вы хотите разделять трафик между поддоменами и считать его реферальным. Есть основоной сайт (site.com) и есть блог (blog.site.com), на котором есть поддомены для юзеров (alex.blog.site.com). Вы хотите переходы между blog.site.com и alex.blog.site.com считать внутренним трафиком, а переходы между этими поддоменами и основным сайтом — реферальным. Для этого:
// на страницах основного сайта
_sbjs.push(['_setBaseHost', 'site.com', false]);
// на страницах поддоменов blog.site.com и alex.blog.site.com
_sbjs.push(['_setBaseHost', 'blog.site.com']);
Обратите внимание на третий параметр false
в настройке для основного сайта. Он выставляется тогда и только тогда, когда не-реферальным трафик должен быть исключительно в рамках указанного домена. Весь остальной трафик, включая переходы с поддоменов в этом же домене, будет считаться реферальным.
В нашем примере при такой настройке все переходы между основным сайтом и блогами будут считаться реферальным трафиком. И если пользователь в первый раз перешёл на основной сайт, кликнув по ссылке из блога пользователя, то его источник будет: alex.blog.site.com (тип трафика: referral).
Проверьте ещё раз, что вы правильно поняли, когда использовать параметр false
.
Домен страницы, на которой установлена настройка _setBaseHost
с параметром false
должен совпадать с хостом, указанным в этой настройке.
// ПРАВИЛЬНО: на страницах site.com
_sbjs.push(['_setBaseHost', 'site.com', false]);
// НЕ ИМЕЕТ СМЫСЛА: на страницах blog.site.com
_sbjs.push(['_setBaseHost', 'site.com', false]);
Указанный хост не имеет поддоменов, трафик с которых вы хотите считать не-реферальным.
_sbjs.push(['_setBaseHost', 'site.com', false]);
//=> трафик со ВСЕХ поддоменов на site.com будет реферальным
_setTimeZoneOffset
_sbjs.push(['_setTimeZoneOffset', 4]);
Устанавливаем часовой пояс.
По умолчанию дата сохраняется в UTC. Настройка позволяет изменить дефолтный часовой пояс.
_setCampaignParam
_sbjs.push(['_setCampaignParam', 'custom_campaign']);
Устанавливаем GET-параметр, значение которого будет сохранено в качестве utm_campaign
(если в запросе нет оригинального параметра utm_campaign
). Эта настройка была добавлена в основном из-за метки Google AdWords gclid
.
Пример использования
Если у вас есть трафик с Google AdWords, и вы используете метку gclid
, вы можете сократить урлы, убрав utm-разметку. Sourcebuster всё равно определит, что это utm-трафик с Google AdWords.
Если в урле присутствует только метка gclid
:
http://statica.alexfedoseev.com/sourcebuster-js/?gclid=sMtH
Это даст следующий результат:
- Traffic type: utm
- utm_source: google
- utm_medium: cpc
- utm_campaign: google_cpc
- utm_content: (none)
- utm_term: (none)
Вы можете изменить значение utm_campaign
через _setCampaignParam
:
http://statica.alexfedoseev.com/sourcebuster-js/?gclid=sMtH&custom_campaign=test_custom
Тогда результат будет такой:
- Traffic type: utm
- utm_source: google
- utm_medium: cpc
- utm_campaign: test_custom
- utm_content: (none)
- utm_term: (none)
ВАЖНО
- Если в урле присутсвуют оригинальные utm-метки (utm_source, utm_medium, utm_campaign), то метка
gclid
и параметр, заданный через _setCampaignParam
, будут проигнорированы.
- Если в урле присутствует только параметр, заданный через
_setCampaignParam
, Sourcebuster будет считать этот переход utm-трафиком.
_addOrganicSource
_sbjs.push(['_addOrganicSource', 'yahoo.com', 'p']);
_sbjs.push(['_addOrganicSource', 'bing.com', 'q', 'bing']);
Добавляем источник органического трафика.
Допустим вы хотите, чтобы система считала переходы с поиска bing.com — органическим трафиком. Для этого вам нужно добавить базовый хост — 'bing.com'
, и параметр ключевого слова — 'q'
. Оба параметра обязательны. Также вы можете указать алиас для источника через опциональный третий параметр ('bing'
).
Для получения параметра ключевого слова, нужно зайти на bing.com и вбить в поисковую строку запрос (например, «apple»). После этого вы попадёте на страницу выдачи с адресом вида:
www.bing.com/search? q=apple &go=&qs=n&form=QBLH&pq=apple&sc=8-5&sp=-1&sk=&cvid=718ad07527244c319ecebf44aa261f64
Параметр ключевого слова — 'q'
— это символ между «?» (или «&» если параметр идёт не первым после знака вопроса) и «=apple» в урле страницы поисковой выдачи.
_addReferralSource
_sbjs.push(['_addReferralSource', 'facebook.com', 'social']);
_sbjs.push(['_addReferralSource', 't.co', 'social', 'twitter.com']);
Добавляем источник реферального трафика. Вобще, если вас устраивает, что utm_medium
при переходе например с facebook.com будет иметь значение referral
, то ничего настраивать не надо. Но если вы хотите присваивать таким переходам кастомный канал (например, utm_medium=social
), то вы можете добавить такую настройку через _addReferralSource
. Первый параметр — это базовый хост, второй — желаемое значение utm_medium
.
Кроме того у некоторых ресурсов реферер отличается от основного домена (например, у Twitter хост реферера — t.co). В таких случаях вы можете присваивать алиас источникам через опциональный третий параметр. Через него же вы можете группировать несколько сайтов с разными реферерами в один источник.
_setUserIP
_sbjs.push(['_setUserIP', <%= request.remote_ip %>]);
По умолчанию скрипт не сохраняет ip-адрес посетителя. Если вы хотите сохранять его в пользовательской куке, можете добавить его через _setUserIP
, получив на бэке. В примере показано, как это сделать на Ruby.
Использование
Cookies
Итак, скрипт установлен и настроен. Теперь при переходе на сайт у посетителей появляются следующие куки:
- sbjs_current
- sbjs_first
- sbjs_first_add
- sbjs_session
- sbjs_referer
- sbjs_udata
sbjs_current
Параметры самого крайнего источника перехода.
Если у пользователя менялся источник перехода (1-2-3-много раз), то в данной куке будет самый крайний источник.
Формат содержимого
typ=organic|src=google|mdm=organic|cmp=(none)|cnt=(none)|trm=(none)
Параметры
- typ
Тип трафика. Возможные значения: utm
, organic
, referral
, typein
. Пятого не дано.
- src
Источник. По сути значение utm_source
.
- mdm
Канал. Значение utm_medium
. Может настраиваться через utm-разметку и _addReferralSource
.
- cmp
Рекламная кампания. Значение utm_campaign
.
- cnt
Версия рекламного баннера. Значение utm_content
.
- trm
Ключевой запрос. Значение utm_term
.
Примеры содержимого
# переход с размеченной рекламы
typ=utm|src=yandex|mdm=cpc|cmp=my_adv_campaign|cnt=banner_1|trm=buy_my_stuff
# переход с органики
typ=organic|src=google|mdm=organic|cmp=(none)|cnt=(none)|trm=(none)
# реферальный переход со стороннего сайта
typ=referral|src=site.com|mdm=referral|cmp=(none)|cnt=(none)|trm=(none)
# переход из facebook с настройкой источника через _addReferralSource
typ=referral|src=facebook.com|mdm=social|cmp=(none)|cnt=(none)|trm=(none)
# прямой переход
typ=typein|src=typein|mdm=typein|cmp=(none)|cnt=(none)|trm=(none)
sbjs_first
Кука по составу абсолютно аналогична sbjs_current
, но в ней сохраняются параметры самого первого источника посетителя. Эта кука устанавливается один раз и никогда не перезаписывается.
sbjs_first_add
Дополнительные данные о первом посещении пользователя: дате/времени и точке входа.
Формат содержимого
fd=2014-06-11 17:28:26|ep=http://statica.alexfedoseev.com/sourcebuster-js/
Параметры
- fd
Дата и время самого первого посещения сайта конкретным пользователем. Сохраняется в формате yyyy-mm-dd hh:mm:ss
. По умолчанию в UTC. Часовой пояс можно изменить через _setTimeZoneOffset
.
- ep
Точка входа на сайт.
sbjs_session
Кука-флаг, что у пользователя открыта сессия. Срок жизни: 30 минут или ваша настройка через _setSessionLength
(с момента последней активности).
sbjs_referer
Реферер, при котором произошла запись или перезапись источника.
Формат содержимого
ref=http://habrahabr.ru
Параметры
- ref
Страница «стороннего» сайта, с которой посетитель перешел на сайт.
sbjs_udata
Дополнительные данные о пользователе: ip и user-agent.
Формат содержимого
uip=80.20.123.77|uag=Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.114 Safari/537.36
Параметры
- uip
Текущий ip-адрес посетителя.
- uag
Текущий user-agent (браузер) посетителя.
Получение данных
Данные доступны через get_sbjs
:
get_sbjs.название_куки_без_префикса_sbjs_.название_параметра_в_куке
// например, чтобы достать текущий utm_source
get_sbjs.current.src
// первый utm_medium
get_sbjs.first.mdm
// точку входа
get_sbjs.first_add.ep
// user-agent пользователя
get_sbjs.udata.uag
// и т.д.
Ну и естественно вы можете разобрать куки сами на бэке.
Использование данных
Давайте выведем на странице текущий источник посетителя. Для этого нам нужно, чтобы переменная get_sbjs
была определена. Если же в момент обращения к функции, которая выводит текущий источник, get_sbjs
ещё не успела загрузиться, то мы должны промониторить загрузку скрипта (sourcebuster), и только после этого запустить функцию, которая выведет текущий источник. Также для IE8 и ниже нам потребуется небольшой фикс для запуска этой функции в нужное время (после загрузки sourcebuster).
// сюда мы поместим название текущего источника
<div id="data-box"></div>
<script type="text/javascript">
// фикс/хелпер для IE, запускающий callback-функцию только после загрузки основного скрипта
// в нашем случае callback - это функция, которая выводит текущий источник, а основной скрипт - это sourcebuster
function ie_load_bug_fix(script, callback) {
if (script.readyState == 'loaded' || script.readyState == 'completed') {
callback();
} else {
setTimeout(function() { ie_load_bug_fix(script, callback); }, 100);
}
}
// функция, которая выводит текущий источник
function place_data() {
document.getElementById('data-box').innerHTML = get_sbjs.current.src;
}
// выводим:
// сначала мы проверяем определена ли переменная get_sbjs
// если переменная определена, то запускаем вывод текущего источника
// если нет, то проверяем тип браузера и запускаем вывод только после загрузки sourcebuster
if (typeof get_sbjs !== 'undefined') {
place_data();
} else {
if (window.addEventListener) {
sbjs.addEventListener('load', place_data, false);
} else if (window.attachEvent) {
ie_load_bug_fix(sbjs, place_data);
}
}
</script>
Ограничения
Переходы с https на http
По стандарту при переходе с протокола https
на http
в реквесте нет реферера, и такие переходы будут определяться модулем как typein
(то есть прямые заходы).
Символ «|» в utm-разметке
Если вы его используете, то скорее всего get_sbjs
будет работать некорректно. Сорри е.
Послесловие
Я только начинаю тестировать модуль на живых проектах. Если есть желающие присоединиться, ю а вэлкам. Хорошо, если есть текщее работающее решение, с которым можно сравнивать результаты. Если словите косяк, то желательно сообщать о нём в формате issue на Github.
У меня всё, спасибо за внимание и удач.