Установка целей - сразу для Метрики и Analytics универсальный и простой скрипт целей для Яндекс Метрика и Google Analytics

  • 06.12.2016
  • 1766
  • 3.8
  • 0
  • Константин Винниченко
Я в своих и клиентских проектах на продающих страницах часто использую 2 цели для Директ и AdWords:
  • SEND – любая отправка данных через форму, конверсионная цель.
  • TIME – человек активно провел 40 секунд на сайте, цель для ретаргетинга и измерения качества трафика.
Для этого разработал простой скрипт, который облегчает установку и теперь делюсь с посетителями моего блога. Данный скрипт будет еще дорабатываться и все изменения будут доступны в этой же статье. Так же жду ваших комментариев для улучшения данного скрипта.

Поясню подробнее о данных целях

Цель SEND вешается каждые 5 секунд на формы заявок в которых присутствует тег FORM, такая частота необходима для таких случаев, когда форма генерируется автоматически. Например: всплывающие окна обратных звонков или онлайн-чат. Но не будет работать, если на форме отправки данных отсутствует тег FORM или/и данные формы отправляются методом JavaSctript.
Цель TIME срабатывает после 40 секунд (это значение можно поменять) активного посещения, то есть счетчик начнет срабатывать после того, как человек выполнил клик или прокрутку на сайте и отключается, если человек ушел со страницы и продолжает отчет, когда, не закрывая вкладу вернулся к вам и продолжает изучать вашу страницу. Можно сказать, эта цель имитирует «отказ», если она не была достигнута.

Установка скрипта на цели TIME и SEND

Устанавливаем код перед закрывающем тегом </BODY> после установки счетчиков:
 
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
<!-- Универсально от SeoUp.su цели TIME и SEND -->
<script type="text/javascript">
    var ymc = true;
    var ymObj = "";
    var gac = true;
    var gaObj = "";
    var bDebug = true;
    var bRecSEND = true;
    var fForm = "FORM,#form,.form";
    var fRequired = ".tel,#tel,.phone,#phone";
    var bRequired = true;
    var fBut = "";
    var rUrlSucces = null;
    var rAjaxUrl = null;
    var rAjaxData = null;
    var rAjaxResponse = null;
    var fMask = "";
    var sMask = "+9999-999-9999";
    var secMax = 40;
    var sNoClass = "fsend";
    var priceTIME = 0;
    var priceSEND = 0;
    /* далее переменные не менять */
    var secCur = 0;
    var bAlert = false;
    var bMen = false;
    var bFocus = false;
    var sConsole = '';
    var sBuf = '';
    var sTimId = '';
    function eventGoal(eg, ec) {
        if (ymc) {
            try {
                if (ymObj != "") {
                    yaCounterJS.reachGoal(eg);
                } else {
                    /* Иначе указать номер Яндекс.Метрики вручную */
                    yaCounter9876543210.reachGoal(eg);
                }
                consoleAlert("Сработал " + eg + " для YM");
            } catch (e) {
                consoleAlert("ОШИБКА отправки " + eg + " для YM.\n" + e);
            }
        }
        if (gac) {
            try {
                gtag('event', 'event_name', {'event_category': 'SEOUP', 'event_action': eg});
                consoleAlert("Сработал " + eg + " для GA");
            } catch (e) {
                consoleAlert("ОШИБКА отправки " + eg + " для GA через gtag().\n" + e);
                try {
                    ga("send", "event", "SEOUP", eg);
                    consoleAlert("Сработал " + eg + " для GA");
                } catch (e) {
                    consoleAlert("ОШИБКА отправки " + eg + " для GA через ga().\n" + e);
                }
            }
        }
        if (ec > 0) {
            window.dataLayer.push({
                "ecommerce": {
                    "currencyCode": "RUB",
                    "purchase": {
                        "actionField": {
                            "id": "auto"
                        },
                        "products": [
                            {
                                "id": 1,
                                "name": eg,
                                "price": ec,
                                "category": "SEOUP/" + eg
                            }
                        ]
                    }
                }
            });
            console.log("ЦЕНА " + eg + "=" + ec);
        }
        return true;
    }
    if ((priceTIME > 0) || (priceSEND > 0)) {
        window.dataLayer = window.dataLayer || [];
    }
    if (gaObj != "") {
        var scGA1 = document.createElement("script");
        scGA1.setAttribute("type", "text/javascript");
        scGA1.setAttribute("src", "https://www.googletagmanager.com/gtag/js?id=" + gaObj);
        document.head.appendChild(scGA1);
        var scGA2 = document.createElement("script");
        scGA2.setAttribute("type", "text/javascript");
        scGA2.innerHTML = "window.dataLayer = window.dataLayer || [];function gtag(){dataLayer.push(arguments);}gtag('js', new Date());gtag('config', '" + gaObj + "');";
        document.head.appendChild(scGA2);
    }
    if (fMask != "") {
        var scMI = document.createElement("script");
        scMI.setAttribute("src", "https://seoup.su/api/jquery.maskedinput.min.js");
        scMI.setAttribute("type", "text/javascript");
        document.head.appendChild(scMI);
    }
    function consoleAlert(text) {
        console.log(text);
        if (bAlert) {
            alert(text);
        }
        return true;
    }
    function formCheck(form) {
        var bOk = true;
        var i = 0;
        if (fRequired != "") {
            fInput = jQuery(fRequired, form);
            console.log("Нашли элементы ввода по шаблону " + fInput.length + " шт.:");
            var vErr = false;
            for (i = 0; i < fInput.length; i++)
                if (fInput[i].value == "") {
                    vErr = true;
                    break;
                }
            if (vErr) bOk = false;
        }
        if (bOk) eventGoal('SEND', priceSEND);
        else consoleAlert("Не сработал SEND, есть пустые элементы INPUT");
        return true;
    }
    jQuery(document).ajaxSuccess(function (event, request, settings) {
        var bOK = false;
        if ((rAjaxUrl != null) && (!bOK)) {
            if (settings.url.search(rAjaxUrl) + 1) {
                bOK = true;
            }
        }
        if ((rAjaxData != null) && (!bOK)) {
            if (settings.data.search(rAjaxData) + 1) {
                bOK = true;
            }
        }
        if ((rAjaxResponse != null) && (!bOK)) {
            if (request.responseText.search(rAjaxResponse) + 1) {
                bOK = true;
            }
        }
        if (bAlert) {
            console.log('ajaxSuccess url: ' + settings.url + ' ; data: ' + settings.data + ' ; responseText: ' + request.responseText);
        }
        if (bOK) {
            eventGoal('SEND', priceSEND);
        }
    });
    jQuery(document).ready(function () {
        if (ymc) sConsole = " YM";
        if (gac) sConsole = sConsole + " GA";
        sBuf = "Библиотека jQuery " + jQuery.fn.jquery + " - Цели работают для" + sConsole + ", где TIME=" + secMax;
        if (bRecSEND) {
            if (fRequired == "") sBuf = sBuf + " и SEND срабатывает при любой отправке " + fForm;
            else sBuf = sBuf + " и SEND срабатывает только в \"" + fForm + "\" с данными \"" + fRequired + "\"";
        }
        if (bRecSEND && fRequired) {
            if (bRequired) {
                jQuery(fRequired, fForm).attr("required", true);
                sBuf = sBuf + " обязательное";
                if (fBut != "") {
                    sBuf = sBuf + " с AJAX кнопкой \"" + fBut + "\"";
                }
            }
            if (fMask != "") {
                sBuf = sBuf + " и маска " + sMask;
            }
        }
        if (bDebug) {
            console.log(sBuf + ". Отладка ?_ym_debug=1");
            if (document.cookie.indexOf('_ym_debug=1') + 1) {
                bAlert = true;
            }
        } else {
            console.log(sBuf + ". Отладка недоступна.");
        }
        if (bAlert) {
            sBuf = "Включен режим отладки и alert() для TIME";
            if (bRecSEND) sBuf = sBuf + " и SEND";
            console.log(sBuf);
        }
        sTimId = setInterval(function () {
            if ((bMen == true) && (bFocus == true)) {
                if (secCur == secMax) {
                    secCur = secCur + 1;
                    clearTimeout(sTimId);
                    eventGoal('TIME', priceTIME);
                }
                else if (secCur <= secMax) {
                    secCur = secCur + 1;
                    if (bAlert) {
                        console.log('TIME = ' + secCur + ' из ' + secMax);
                    }
                }
            }
        }, 1000);
        if ((fForm != "") && (bRecSEND)) {
            setInterval(function () {
                if (!jQuery(fForm).hasClass(sNoClass)) {
                    jQuery(fForm).addClass(sNoClass);
                    if (bAlert) {
                        jQuery(fForm).attr("style", "border: 2px dashed #f00; margin: -2px;");
                        jQuery(fRequired, fForm).attr("style", "border: 2px dashed #9f0; margin: -2px;");
                        jQuery(fBut, fForm).attr("style", "border: 2px dashed #03f; margin: -2px;");
                        console.log("Нашли новые формы на сайте, вешаем события для цели SEND.");
                    }
                    jQuery(fForm).submit(function (e) {
                        formCheck(this);
                        return true;
                    });
                    if (fMask != "") {
                        jQuery(fMask, fForm).mask(sMask);
                    }
                    if (fBut != "") {
                        jQuery(fBut, fForm).click(function (e) {
                            formCheck(this.closest(fForm));
                            return true;
                        });
                    }
                }
            }, 2000);
        }
        jQuery(window).focus();
        if (rUrlSucces != "") {
            if (window.location.href.search(rUrlSucces) + 1) {
                setTimeout(function () {
                    eventGoal('SEND', priceSEND);
                }, 100);
            }
        }
    });
    jQuery("body").click(function () {
        bMen = true;
        bFocus = true;
    });
    jQuery(window).scroll(function () {
        bMen = true;
        bFocus = true;
    });
    jQuery(window).bind("focus", function () {
        bFocus = true;
    });
    jQuery(window).bind("blur", function () {
        bFocus = false;
    });
    if (ymObj != "") {
        (function (d, w, c) {
            (w[c] = w[c] || []).push(function () {
                try {
                    w.yaCounterJS = new Ya.Metrika({
                        id: Number.parseInt(ymObj),
                        clickmap: true,
                        trackLinks: true,
                        accurateTrackBounce: true,
                        webvisor: true,
                        trackHash: true,
                        ecommerce: "dataLayer"
                    });
                } catch (e) {
                }
            });
            var n = d.getElementsByTagName("script")[0],
                    s = d.createElement("script"),
                    f = function () {
                        n.parentNode.insertBefore(s, n);
                    };
            s.type = "text/javascript";
            s.async = true;
            s.src = "https://mc.yandex.ru/metrika/watch.js";
            if (w.opera == "[object Opera]") {
                d.addEventListener("DOMContentLoaded", f, false);
            } else {
                f();
            }
        })(document, window, "yandex_metrika_callbacks");
        jQuery("body").append('<noscript><div><img src="https://mc.yandex.ru/watch/' + ymObj + '" style="position:absolute; left:-9999px;" alt="" /></div></noscript>');
    }
</script>

Описание переменных и настройка

  1. ymc (true|false) - включить захват целей для Yandex Metrika
  2. ymObj (""|"9876543210") - если указать номер Яндекс.Метрики здесь, то не потребуется подключать отдельно счетчик и изменять строку под нужную метрику в коде ниже
  3. gac (true|false) – включить захват целей для Google Analytics
  4. ymObj (""|"UA-9876543210") - если указать номер Google Analytics здесь, то не потребуется подключать отдельно счетчик и данный способ лучше совместим при срабатывании целей в GTM
  5. bDebug (true|false) - разрешить режим отладки в консоли и alert() при посещении c параметром ?_ym_debug=1 во время настройки стоит использовать true и когда за закончена отладка выключать в целях безопасности
  6. bRecSEND (true|false) - использовать захват цели SEND с конверсионных fForm
  7. fForm (jQuery селекторы) - если bRecSEND работает, то используем выделение контейнера в качестве конверсионной формы для следующего захвата по цели SEND
  8. fRequired (jQuery селекторы) - если bRecSEND работает и есть выборка fForm идет проверка значений полей INPUT, которые должны быть обязательно заполнены перед отправкой для срабатывания цели SEND
  9. bRequired(true|false) - если fRequired и bRequired true, тогда на уровне браузера данные INPUT обязательны к заполнению, что позволяет избежать часть ошибок перед отправкой формы
  10. fBut (""|jQuery селекторы) - если значение не пустое, тогда идет срабатывание SEND просто по клику на кнопку внутри fForm, применять метод в последнюю очередь когда другие методы перехвата не работают
  11. rUrlSucces (null|регулярные выражения JS) - если значение не null, тогда идет поиск соответствия регулярному выражению по URL и срабатывает цель SEND при истинном значении вне зависимости от bRecSEND
  12. rAjaxUrl (null|регулярные выражения JS) - при отправке AJAX идет поиск по URL куда эти данные отправляются и если соответствует выражению, срабатывает SEND вне зависимости от bRecSEND
  13. rAjaxData(null|регулярные выражения JS) - при отправке AJAX идет поиск по отправляемым данным с форм и если соответствует выражению, срабатывает SEND вне зависимости от bRecSEND
  14. rAjaxResponse(null|регулярные выражения JS) - при отправке AJAX идет поиск по полученным данным с сервера и если соответствует выражению, срабатывает SEND вне зависимости от bRecSEND
  15. fMask (""|jQuery селекторы) - если значение не пустое, то применяется маска к заполнению INPUT, обычно используется для номера телефона
  16. fMask("+9999-999-9999") - шаблон маски к заполнению INPUT при непустом fMask
  17. secMax (40) - число секунд до срабатывания цели TIME, обнуляется с каждым новым посещением
  18. sNoClass("fsend") - имя класса, которое будет добавляться к fForm чтобы исключить уже известные формы и поймать новые динамические формы через каждые 2 секунды
  19. priceTIME(0) - указываем больше 0 если точно знаем ценность данной цели и хотим видеть данные в отчетах по электронной коммерции, лучше не использовать совместно с priceSEND
  20. priceSEND(0) - указываем больше 0 если точно знаем ценность данной цели и хотим видеть данные в отчетах по электронной коммерции, лучше не использовать совместно с priceTIME

Популярные примеры jQuery селекторов и регулярных выражений JavaScript для цели SEND

Примеры jQuery селекторов
  • "form,#form,.form" – выбрать все теги FORM, все теги с ID #form, все теги с классом .form
  • "FORM:not(#uptocall-form, #uptocall-form-email, #search, .search, #subscribe, .subscribe, #smartfilter, .smartfilter, #login, .login)" – выбрать все теги FORM кроме #uptocall-form, #uptocall-form-email и т.д.
  • "FORM:has(.seoup, .feedback)" – выбрать только теги FORM с классом .seoup, .feedback. Аналог "FORM.seoup, FORM.feedback"
  • "#myinput\\[3\\]" – выбрать элемент у которого ID с квадратными скобками "myinput[3]"
  • "FORM[action=\\/\\#wpcf7-f4349]" - выбрать FORM у которой атрибут action="/#wpcf7-f4349"

Примеры регулярных выражений JS:

  •  /12a45/ - строка содержит «12a45» в любом месте
  • /^12a45/ - строка начинается с «12a45»
  • /12a45$/ - строка заканчивается на «12a45»
  • /^12a45$/ - строка строго «12a45»
  • /^\[null,{"ok":1}]$/ - строка строго «[null,{"ok":1}]»
  • /^45678$|^12a45$/ - перечисление вариантов поиска символом «|»
  • /input_phone=.{5,}&input_email/ - строка имеет «input_phone=» и «input_email» между которыми 5 и более символов, это по логике означает заполненное поле input_phone
  • /order((?!edit).)*\/$/ - для страницы «site.ru/order/» работает, а для «site.ru/order/edit/» не работает
  • /order.*thank/ - для страницы «site.ru/order/» не работает, а для «site.ru/order/thank» работает
Проверяйте работоспособность регулярных выражений - https://regex101.com

Тестируем цели и исправляем ошибки

1. После установки открываем сайт и смотрим лог консоли, если надпись "Установлены цели TIME и SEND" появилась, то скорее всего цели работают.
2. Скрипт может не работать, если не подключена библиотека jQuery
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
3. В Яндекс.Метрика есть специальный тег, с которым открываешь страницу и смотришь логи отчета и Метрика отобразит свои действия по конверсиям
site.ru?_ym_debug=1
Подсказка: кстати так можно определить достигаемые цели от сервисов обратного звонка и онлайн-консультантов. Выполняете заявку, пишите сообщение и смотрите какая цель отобразилась, данное имя можете добавить в счетчик и буде собирать по данной цели конверсии и статистику.
4. Если скрипт установили, а счетчики не поставили, цели работать не будут.
5. Желательно скрипт ставить после вызова счетчиков, если цель универсального скрипта сработает раньше, чем загрузиться счётчик то будет ошибка.
6. Если JavaScript отключен в браузере, скрипт работать не будет. Крайне редкий случай.
7. Если счетчики слежения блокируют антивирусы, то скрипт так же работать не будет.

Все корректно, а целей в отчете нет?

В Яндекс.Метрика обычно требуется 15-40 минут, чтобы она отобразила достижение цели в своих отчетах
В Яндекс.Директ обычно требуется 1-2 дня, чтобы из отчета «Все цели» появились уже имена конкретных целей SEND и TIME. Яндекс.Директ предварительно надо связать с Яндекс.Метрика.
В Google Analytics в режиме реального времени может отобразить цель, задержка 3-15 секунд
В Google AdWords обычно требуется 2-3 для показа целей. Google AdWords предварительно надо связать с Google Analytics

Полезно прочесть


Полезно сделать

Рейтинг:
(3.75 из 5 - 5 голосов)
Сохранить страницу себе: