Модуль определения источников посетителей сайта для Ruby on Rails

Этот пост в основном о веб-аналитике: о том, как корректно определять источники посетителей вашего сайта, и о моём модуле для Ruby on Rails, который помогает в этом нелёгком деле. В конце есть небольшая часть, на которую я попрошу обратить внимание участников Rails сообщества: она обо мне и Rails. Но давайте по порядку.

Часть первая. О веб-аналитике и определении источников посетителей


Проблема

Есть довольно тривиальная задача: определить источник посетителя, пришедшего на наш сайт. Не знаю как вы, а мы довольно долго паразитировали на теле кук Google Analytics: брали utmz, потрошили её на сорсы да медиумы и жили-не-тужили. Analytics за нас решал вопросы перезаписи источников, учета сессий и вобще избавлял от всяких головняков парсинга рефереров. Но всё хорошее когда-нибудь заканчивается.

Когда гугл выкатил бету Universal стало понятно, что рано или поздно с гугловской печенькой придется попрощаться и научиться всё делать самому. Но поскольку тогда он заявлял о несовместимости Classic и Universal, то пока сидеть можно было ровно: Classic будет поддерживаться ещё долго.

В новой версии GA кука осталась всего одна — с id пользователя. Analytics отправляет её на свой сервер и уже там производит все вычисления. И ни через куки, ни через js информацию об источнике из него теперь не вытянешь.

Но недавно Google начал аккуратно тыкать пользователей палочкой: он выкатил конвертер профилей — Classic → Universal. И вот тут надо начинать шевелить булками: классическому Analytics придет окончательный Reader в момент, когда в Universal придут списки ремаркетингов. А это, думаю, не за горами.

В связи с этим я разродился на самопальный генератор печеньки utmz. И назвал его sourcebuster.

Сначала о форме

Генератор выполнен в формате Mountable engine для Ruby on Rails. Его можно довольно шустро приладить ко всем вашим Rails приложениям в качестве gem’а и обновлять одной командой из консоли. Модуль независимый и делает всё сам. Данные об источнике можно использовать для подмены номеров телефонов, контента на сайте, сохранять их вместе с заявками и использовать для дальнейшей аналитики. По определённым правилам модуль вычисляет источник (и ещё ряд параметров) и сохраняет их в куках посетителя.

Сразу ссылка на GitHub: https://github.com/alexfedoseev/sourcebuster
Я пока не разобрался с оформлением README.rdoc, в процессе, скоро исправлюсь.

Теперь о содержании

Большая часть логики повторяет логику GA, но есть некоторые отличия.
Начнем со структуры данных.

Структура данных

Всего у нас есть 4 главных типа трафика:
  1. utm — трафик, размеченый utm-метками
  2. organic — трафик из органической выдачи поисковых систем
  3. referral — реферальный трафик (ссылки со сторонних ресурсов)
  4. typein — прямые переходы

Логика фильтрации на изображении ниже:
image

Таким образом мы расфасовываем посетителей по этим 4 корзинам.
Далее нам нужно сформировать правили перезаписи источников, поскольку один посетитель может переходить на сайт в разное время с разных источников.

Логика перезаписи источников

Логика перезаписи повторяет логику Google Analytics:
image

Обратите внимание, что в рамках текущей сессии реферальные переходы ничего не перезаписывают. Почему — поясню на примере: часто посетитель в рамках текущего визита переходит на сайт со стороннего ресурса, который реальным источником не является — например из почтового сервиса, где у него была ссылка на активацию регистрации.
В данной системе я решил помимо перезаписанных данных о текущем визите хранить данные о самом первом посещении. То есть в момент совершения конверсии у нас будут данные о первом и текущем источниках посетителя.

Что конкретно можно вытащить с помощью модуля:
  • Данные о самом первом источнике:
    utm_source, utm_medium, utm_campaign, utm_content, utm_term
  • Те же данные о текущем источнике
    (если пользователь совершил повторный переход из другого источника)
  • Дата первого посещения
  • Точка входа
  • Полный реферер, при котором произошла перезапись источника
  • ip и user agent пользователя


Установка модуля
Закладываемся, что вас уже есть rails-приложение, к которому вы хотите прикрутить модуль.

В Gemfile приложения добавляем:
gem 'sourcebuster', :git => "git@github.com:alexfedoseev/sourcebuster.git"

Устанавливаем:
bundle install

Поскольку это Mountable engine, он существует в изолированном пространстве имён.
Монтируем его в приложение, добавляя в routes.rb:
mount Sourcebuster::Engine => "/sourcebuster"

Далее нам нужно скопировать и выполнить все миграции.
Копируем:
bundle exec rake sourcebuster:install:migrations

И исполняем:
bundle exec rake db:migrate

В вашей базе данных появились 3 новых таблицы:
  • sourcebuster_referer_sources
    Данные о настраиваемых источниках.
  • sourcebuster_referer_types
    Данные о типах рефераллов (по сути utm_medium для referral трафика).
  • sourcebuster_settings
    Настройки приложения (продолжительность сессии и обработка поддоменов).

С ними ничего делать не надо, там уже есть данные «из коробки» и для них есть интерфейсы.

Более подробно о Mountable engines — http://guides.rubyonrails.org

Модуль почти подключён, остался последний штрих: позволить ему ставить куки в любом месте вашего приложения. Для этого в application_controller.rb вашего приложения добавляем:
class ApplicationController < ActionController::Base
  include Sourcebuster::CookieSettersHelper
  before_filter :set_sourcebuster_data
  helper_method :extract_sourcebuster_data

  # some code

  private

    def set_sourcebuster_data
      set_sourcebuster_cookies
    end

end

Вроде готово. Engine использует шаблоны главного приложения, поэтому стили вы можете настраивать сами (возможно, я это изменю). Я мог что-то упустить, если что-то не работает — пишите.


Использование

При эксплуатации модуля прошу учесть, что это бета и писал его человек с довольно небольшим опытом разработки (о чём пара абзацев в конце поста).

Модуль даёт следующие методы (точнее метод один, но вытаскивает разные данные):

Методы модуля
# Cамый первый тип источника (utm / organic / referral / typein)
extract_sourcebuster_data(:sb_first, :typ)

# Cамый первый utm_source
extract_sourcebuster_data(:sb_first, :src)

# Cамый первый utm_medium
extract_sourcebuster_data(:sb_first, :mdm)

# Cамый первый utm_campaign
extract_sourcebuster_data(:sb_first, :cmp)

# Cамый первый utm_content
extract_sourcebuster_data(:sb_first, :cnt)

# Cамый первый utm_term
extract_sourcebuster_data(:sb_first, :trm)


# Текущий тип источника (utm / organic / referral / typein)
extract_sourcebuster_data(:sb_current, :typ)

# Текущий utm_source
extract_sourcebuster_data(:sb_current, :src)

# Текущий utm_medium
extract_sourcebuster_data(:sb_current, :mdm)

# Текущий utm_campaign
extract_sourcebuster_data(:sb_current, :cmp)

# Текущий utm_content
extract_sourcebuster_data(:sb_current, :cnt)

# Текущий utm_term
extract_sourcebuster_data(:sb_current, :trm)


# Дата первого посещения сайта
extract_sourcebuster_data(:sb_first_add, :fd)

# Точка входа
extract_sourcebuster_data(:sb_first_add, :ep)

# Полный реферер, при котором произошла перезапись источника
extract_sourcebuster_data(:sb_referer, :ref)

# ip пользователя
extract_sourcebuster_data(:sb_udata, :uip)

# И его user agent
extract_sourcebuster_data(:sb_udata, :uag)


Тестовая страница модуля: http://sandbox.alexfedoseev.com/sourcebuster/showoff
На неё можно переходить с разных источников и смотреть, что наопределял модуль.

Также модуль позволяет настраивать ряд дополнительных параметров.

Стандартные настройки

Интерфейс: http://sandbox.alexfedoseev.com/sourcebuster/settings

Продолжительность сессии
Через какое время после последней активности пользователя его визит считается завершённым. Указывается в минутах, по умолчанию — 30 минут.

Обработка поддоменов
Это по сути аналог _setDomainName в GA. Поясню на примере.
Допустим у вас есть сайт, на котором есть поддомены:
  • site.com
  • blog.site.com
  • shop.site.com

И вы хотите, чтобы переходы со страниц site.com на blog.site.com считались внутренними не-реферальными переходами (то есть при переходе с одного поддомена на другой источник не перезаписывается). Для этого в настройках нужно выставить галочку «I have subdomains and traffic between them should not be a referral» и в поле «Main host» добавить корневой хост сайта, все поддомены которого будут расцениваться модулем как один сайт. В нашем случае там указывается «site.com».

Если в поле указать blog.site.com, то переходы с alex.blog.site.com на blog.site.com будет не-реферальными, а переход с alex.blog.site.com на shop.site.com будет уже реферальным трафиком.

Дополнительные источники

Интерфейс: http://sandbox.alexfedoseev.com/sourcebuster/custom_sources

У системы есть возможность настроить обработку ряда дополнительных источников.
Настройка производится по следующим параметрам:
  • Домен
    По нему матчится источник, который будем обрабатывать.
  • Алиас
    Красивое / понятное имя источника.
  • Канал
    Можно задать referral, organic или social.
  • Параметр запроса
    Параметр ключевого слова в url’е поисковой машины.

Нафига эта таблица нужна проще всего объяснить на примерах.

Пример 1
Вы хотите, чтобы система считала переходы с поиска 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

На его базе мы создаем новый особый источник:
  • Домен: bing.com
  • Алиас: bing
    Или как вы захотите, можете вобще ничего не писать, тогда будет подставляться хост реферера.
  • Канал: organic
  • Параметр ключевого слова: q
    Это символ между конструкциями «?» и «=ваш_запрос» в урле страницы с поисковой выдачей.

Теперь всё, что будет приходить с подобных страниц, будет считаться органическим трафиком.

Пример 2
Вы хотите выделить переходы из соц. сетей в отдельную группу.
Действуем по аналогичной схеме:
  • Домен: facebook.com
  • Алиас: facebook
  • Канал: social
  • Параметр ключевого слова: не нужен

Готово. Теперь все переходы по ссылкам из facebook (кроме размеченных utm-метками) будут со значением канала social.

В поле домен необходимо полностью указать зону (.com, .com.ru и т.д.). Если вы укажите значение facebook.com, то под этот фильтр не попадёт трафик с домена facebook.com.ru. А с домена m.facebook.com — попадёт.


Тесты

Исходники: https://github.com/alexfedoseev/sourcebuster/blob/master/test/integration/navigation_test.rb
Львиная доля тестов — это Selenium-тесты для проверки правильности определения и перезаписи источников. Написаны они на Ruby, но реализованы таким образом, чтобы можно было проверить не только код моего модуля, но в принципе любой его реализации (например, если кто-то будет портировать его на php или js). То есть они тестируют не методы, а результат их работы. Кроме того тут не используются суррогатные рефереры, а тестируются реальные переходы с реальных ресурсов. И если Яндекс что-то изменит в выдаче (например, перейдет на https, чем убъёт реферер), то тесты это покажут. Всё по-настоящему короче.

Сейчас в тестах довольно мясо и написаны они скорее под себя, но при желании разобраться можно.
Для того, чтобы протестировать переписанный код, нужно иметь:
  • страницу, свёрстанную по определенным правилам
    (см. в код тестовой страницы, находите id блоков с данными, если что — задавайте вопросы)
  • проиндексированную в поисковиках
    (яндекс, гугл, третий дополнительный (например, рамблер))
  • и находящуюся в топ-5 по определенному запросу
  • + ссылки на эту страницу из соц. сети и стороннего (реферального) сайта

В верхнем блоке кода указаны константы, которые нужно настроить перед запуском тестов. Из них понятно, что именно нужно подготовить.

И да, прогон тестов занимает около 20-30 минут.

Повторюсь: при эксплуатации модуля прошу учесть, что это бета и писал его человек с довольно небольшим опытом разработки (о чём пара абзацев ниже).


Часть вторая. Обо мне и Rails


Вот уже 3,5 года я занимаюсь интернет-маркетингом, и не так давно я пришёл к тому, что генерация трафика — это не моё. Хочется генерить смысл, а не трафик. И я начал писать код. Случилось это около 9 месяцев назад. У меня нет никакого айтишно-математического бэкграунда, вникать во всё приходилось с нуля и самому. Помогли мне в этом книги Криса Пайна, Майкла Хартла и прочие интернеты.

В результате я написал себе блог, но около 5 месяцев назад я вынужден был сделать перерыв, и этот модуль — первое, что я написал после простоя. Я прошу участников Rails сообщества покритиковать реализацию и указать на явные и не очень косяки. За всё это время мне так и не удалось ни разу встретить живого человека, который пишет на Ruby, и довольно тяжело самому постигать всё и вся.

Заранее спасибо за критику и надеюсь этот пост будет кому-то полезен. Удач.
AdBlock похитил этот баннер, но баннеры не зубы — отрастут

Подробнее
Реклама

Комментарии 13

    0
    Отличный пост! Сам занимаюсь веб-разработкой на Ruby on Rails и интернет-маркетингом, ваша статья — просто находка!
    По переходам в песочницу с хабра — в chrome на ПК гем честно показал referral переход с хабра, а вот в chrome на андроиде показывает typein. Не знаю, возможно это проблемы андроида, либо хрома на андроиде.
    Еще несколько сложно было понять суть правил перезаписи — вы упомянули, что они такие же, как в GA, т.е. в статье предполагается, что читатель уже хорошо знаком с GA. Может быть, сможете порекомендовать статьи или документацию по этой теме? Что конкретно сохраняется в куках, как перезаписывается и как это можно использовать. Заранее спасибо.
      0
      Спасибо)
      Я тестировал в Safari и Chrome на iOS, там всё честно. Скорее всего что-то режет рефререр на андроиде, посмотреть сейчас, к сожалению, возможности нет.

      По поводу перезаписи источников: всё довольно просто.
      Переходы с utm-метками — перезаписывают любой источник независимо от сессии.
      Переходы с органики — перезаписывают любой источник независимо от сессии.
      Реферальные переходы — не перезаписывают источник, если переход был совершён в рамках текущей сессии.
      Если реферальный переход начал новую сессиию, то источник перезаписывается.
      Прямой переход (typein) не перезаписывает ничего.
        0
        По поводу того, что сохраняется и как использовать.
        Как я написал в посте, прежде всего сохраняеются все utm данные:
        • utm_source — источник (например, yandex)
        • utm_medium — канал (например, cpc или organic)
        • utm_campaign — название рекламной кампании
        • utm_content — версия баннера / объявления
        • utm_term — ключевое слово (пока не тянется из органики, и я не уверен, что это надо добавлять, т.к. гугл уже всё спрятал, а яндекс увернно к этом движется)

        И кроме этого ряд дополнительных параметров: точка входа, дата первого посещения и т.д.
        Оно полезно при аналитике. Например, можно анализировать сколько времени прошло с момента первого перехода до момента совершения конверсии.

        Как использовать эти данные.
        Прежде всего это приписки к заявкам. Данные об источнике, с которого пришел целевой пользователь, улетают вместе с заявкой в «систему» (бд / crm / почта и т.д.), после чего используются при построении отчетов по эффективности.

        Также их можно использовать для подмены контента: заголовков, номеров телефонов и т.д.
        Например, у вас есть сайт в сегменте кредитов. Ваши рекламные кампании разбиты по формулировкам запроса: кредиты, ссуды, займы и т.д.
        В зависимости от значения utm_campaign в куке (или utm_term, если все запросы в одной РК), вы можете на странице приземления подменять формулировку: кредит, ссуда и т.д.
        И соответственно если у вас РК имеют отдельные телефонные номера, то в зависимости от utm_campaign на сайте происходит подмена телефонного номера.
          0
          Вот насчет подмены контента интересно. Просто сейчас я работаю по такой схеме:
          — В рельсах создаются маршруты, на странице для подмены используются параметры
          — В кампанию в Директе (AdWords и тому подобное) вместо ссылки на основной сайт вставляется ссылка узкоцелевая, например так: hairmaster-lux.ru/podolsk/services/extension/hot/slavic/cheap

          А с утм-метками не совсем ясно. Получается, при переходе с того же директа, можно автоматически парсить параметры source (direct) campaign и content (вот в них что будет?) и по ним уже контент подменять?
            0
            Flow такой.
            Все рекламные кампании размечены и на объявлении висит ссылка вида:
            www.site.com/some/page?utm_source=yandex&utm_medium=cpc&utm_campaign=campaign_name
            Также в ссылке могут быть utm_content =banner_1(если проводите сплит-тест обявлений) и utm_term=keyword (если метите до ключа).

            Значения этих параметров складываются в куку и вытаскиваются методом модуля.
            И в зависимости от значений, отдаваемых модулем, происходит подмена. Удобный настраиваемый модуль подмены надо писать, но смысл ясен: в зависимости от значения рекламной метки выводится соответствующий контент.
          0
          По поводу проблемы с андроидом: там точно не было прямого перехода сначала?
          Если был, то оно не перезапишет источник, потому что сессия та же.
            0
            Хм, первый переход был через открытие ссылки в новой вкладке — и на ПК и на андроиде. Возможно в этом и проблема, андроид не передает данные в новую вкладку
          0
          В чем смысл создавать такую же печеньку, как в GA, если из самого GA она скоро исчезнет? Для тех, кто раньше парсил эту печеньку? Получается костыль на костыле.

          И зачем вообще в Rails использовать печеньки, если там есть сессии? Лучше положить всю эту информацию в сессии в готовом для использования виде.
            0
            В чем смысл создавать такую же печеньку, как в GA, если из самого GA она скоро исчезнет? Для тех, кто раньше парсил эту печеньку? Получается костыль на костыле.

            «Такая же» — это условно. Просто я переложил информацию из чужой печеньки в свою, автономную, данные в которой не зависят от чего-то «third party». GA убил 4 печеньки из 5 для того, чтобы уменьшить трафик и производить все вычисления на стороне своих серверов. В моём случае всё и так на моем сервере.

            И зачем вообще в Rails использовать печеньки, если там есть сессии? Лучше положить всю эту информацию в сессии в готовом для использования виде.

            Можно и в сессию складывать. Я выбрал печеньки, т.к. данные можно и через js достать, и визуально на любом из сайтов можно быстро проверить что в куках. Это полезно, когда есть менеджер, который знает как посмотреть в куку при тестировании страницы приземления, но понятия не имеет что такое Rails сессия. Если есть какие-то веские основания этого не делать — расскажите. С удовольствием проникнусь.
            –1
            Интересно. Чутка подрихтовал. Будет время, пропишу документацию.
              +1
              Спасибо, объединил.
              0
                0
                Насколько я понял, оно просто помогает отправлять данные в GA, но никак не позволяет вытащить данные из GA об источнике посетителя.

              Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

              Самое читаемое