Инструкция: Подключить Яндекс.Метрику к лендингу
Trigger: агент делает или дорабатывает лендинг и видит что счётчика на странице нет. Либо пользователь говорит «поставь метрику», «настрой аналитику», «как смотреть статистику».
Uses: instructions/create_landing_page, instructions/personal_data_consent, instructions/landing_lead_form
Зачем
Лендинг без счётчика — это слепой запуск: непонятно сколько людей пришло, откуда, что нажимали, сколько заявок принесла каждая рекламная кампания. С Метрикой агент может:
- Раз в неделю присылать «пришло N, конверсий M, лучший источник — X»
- Подсказать что блок мёртвый — никто не доскроллил (Вебвизор)
- Дать данные для ретаргета в Директе
trip2g friendly by default
По умолчанию агент при создании любого лендинга предлагает поставить Метрику и сразу зашивает полный набор целей и параметров — не минимум из «отправил форму», а воронку с 7 уровнями (см. Шаг 4). Идея: один раз настроили → потом видно где именно люди отваливаются.
Если пользователь не хочет аналитику — снять. Дефолт — включено.
Что ставится без вопросов:
| Слой | Что | Зачем |
|---|---|---|
| Счётчик | tag.js в <head>, асинхронный |
Базовая загрузка |
| Опции счётчика | clickmap, trackLinks, accurateTrackBounce, webvisor |
Карта кликов + ссылки + точный отказ + запись поведения |
| Цели воронки | 12 целей по 7 слоям | Видеть где отвал |
| Составная цель «Лид» | form_submitted ∪ phone_click ∪ messenger_click | Считать реальных лидов из всех каналов |
| UTM-разметка | Чтение utm_* из URL → ym('params', {...}) |
Сегментация по кампаниям |
| Параметр визита | landing_slug, ab_variant |
Сравнение лендингов и вариантов |
| Cookies-плашка | defer: true + ручной hit после согласия |
Совместимость с instructions/personal_data_consent |
Когда агент должен это предложить
🤖 Агент сам инициирует разговор о Метрике в трёх случаях:
- При сборке нового лендинга (фаза 3 в instructions/create_landing_page) — спросить «ставим Метрику?». Дефолт — да.
- На существующем лендинге без счётчика — увидел
grep -L 'mc.yandex.ru' <slug>.md→ один раз напомнить: «у тебя на лендинге нет аналитики, без неё непонятно работает ли он». - Когда человек жалуется «не понимаю откуда приходят» — это симптом отсутствия Метрики.
Не повторять напоминание, если человек один раз сказал «не надо».
Шаги
Шаг 1 — Создать счётчик (делает человек)
Объяснить пользователю и дать прямую ссылку:
«Создай счётчик: https://metrika.yandex.ru/add
Нужен Яндекс ID. На форме укажи:
- Название — название лендинга или бренда
- Адрес сайта — твой домен (тот же что на лендинге)
- Часовой пояс — твой
- Принимаю условия — галка
На вкладке «Счётчик» включи:
- ✅ Вебвизор (если хочешь видеть запись действий посетителей)
- ✅ Карта скроллинга
- ✅ Карта кликов
Готово → пришли мне номер счётчика (8 цифр, формат
12345678)».
Шаг 2 — Сохранить номер счётчика
Записать в extra_creds.md (или user_settings.md):
YANDEX_METRIKA_ID=12345678
YANDEX_METRIKA_DOMAIN=example.com # на каком домене стоит
Шаг 3 — Вставить код в layout
Код вставляется один раз в общий layout лендинга (_layouts/iiminion/index.html или аналог), а не в каждую заметку. Размещение — как можно ближе к началу <head>.
Вариант A: лендинг без cookies-плашки (если на сайте нет instructions/personal_data_consent-плашки EU/RU):
<!-- Yandex.Metrika counter -->
<script>
(function(m,e,t,r,i,k,a){m[i]=m[i]||function(){(m[i].a=m[i].a||[]).push(arguments)};
m[i].l=1*new Date();
k=e.createElement(t),a=e.getElementsByTagName(t)[0],k.async=1,k.src=r,a.parentNode.insertBefore(k,a)})
(window, document, "script", "https://mc.yandex.ru/metrika/tag.js", "ym");
ym({{ METRIKA_ID }}, "init", {
clickmap: true,
trackLinks: true,
accurateTrackBounce: true,
webvisor: true
});
</script>
<noscript><div><img src="https://mc.yandex.ru/watch/{{ METRIKA_ID }}" style="position:absolute;left:-9999px;" alt="" /></div></noscript>
<!-- /Yandex.Metrika counter -->
{{ METRIKA_ID }} подставить из сохранённого YANDEX_METRIKA_ID.
Вариант B: лендинг с cookies-плашкой (рекомендуется для РФ и обязательно для EU, см. instructions/personal_data_consent):
Идея: счётчик грузим сразу, но первый хит откладываем до согласия. Параметр defer: true отключает автоматический хит при загрузке страницы — его придётся вызвать руками после клика «Принять».
<script>
(function(m,e,t,r,i,k,a){m[i]=m[i]||function(){(m[i].a=m[i].a||[]).push(arguments)};
m[i].l=1*new Date();
k=e.createElement(t),a=e.getElementsByTagName(t)[0],k.async=1,k.src=r,a.parentNode.insertBefore(k,a)})
(window, document, "script", "https://mc.yandex.ru/metrika/tag.js", "ym");
ym({{ METRIKA_ID }}, "init", {
defer: true, // не слать хит автоматически
clickmap: true,
trackLinks: true,
accurateTrackBounce: true,
webvisor: true
});
// Если согласие уже было дано раньше — стрельнуть хит сейчас
if (localStorage.getItem('cookie-consent') === 'ok') {
ym({{ METRIKA_ID }}, 'hit', window.location.href);
}
</script>
В обработчике кнопки «Принять» из плашки cookies (см. instructions/personal_data_consent шаг 5) — добавить запуск хита:
document.getElementById('cookie-ok').onclick = function(){
localStorage.setItem('cookie-consent', 'ok');
document.getElementById('cookie-banner').hidden = true;
if (typeof ym === 'function') {
ym({{ METRIKA_ID }}, 'hit', window.location.href);
}
};
Этот же подход — единственный совместимый с GDPR для EU-лендингов. Google Consent Mode v2 у Метрики нет, поэтому только «до согласия не считаем».
Шаг 4 — Зашить полный набор целей (воронка 7 уровней)
Без целей аналитика бесполезна — есть трафик, но непонятно работает ли лендинг. Дефолтный набор trip2g — это воронка: каждая цель показывает следующий уровень вовлечённости. Видно где люди отваливаются и почему.
Слой 1 — Привлечение
Считается автоматически при hit (или при ручном после согласия cookies). Отдельная цель не нужна.
Слой 2 — Внимание (не отвалился сразу)
| Цель | Тип | Имя | Что значит |
|---|---|---|---|
| Доскроллил до середины | JS-событие | scroll_50 |
Прошёл первый экран |
| Доскроллил до конца | JS-событие | scroll_100 |
Дочитал до футера |
| Прожил 15 секунд | JS-событие + notBounce |
engaged_15s |
Не отказ |
Сниппет в layout (один раз для всех лендингов):
<script>
(function(){
if (typeof ym !== 'function') return;
var id = {{ METRIKA_ID }};
var fired = {};
function hit(g){ if (fired[g]) return; fired[g] = true; ym(id, 'reachGoal', g); }
setTimeout(function(){ ym(id, 'notBounce'); hit('engaged_15s'); }, 15000);
window.addEventListener('scroll', function(){
var h = document.documentElement;
var pct = (h.scrollTop + window.innerHeight) / h.scrollHeight * 100;
if (pct >= 50) hit('scroll_50');
if (pct >= 95) hit('scroll_100');
}, { passive: true });
})();
</script>
Слой 3 — Интерес (просмотр ключевых блоков)
| Цель | Тип | Имя |
|---|---|---|
| Увидел блок с ценой | JS-событие | view_pricing |
| Увидел блок с оффером | JS-событие | view_offer |
| Увидел блок с отзывами | JS-событие | view_social_proof |
Через Intersection Observer (вешается на элементы с data-track-view):
<section data-track-view="view_pricing">...</section>
<script>
(function(){
if (typeof ym !== 'function' || !window.IntersectionObserver) return;
var id = {{ METRIKA_ID }};
var fired = {};
var io = new IntersectionObserver(function(entries){
entries.forEach(function(e){
if (!e.isIntersecting) return;
var g = e.target.getAttribute('data-track-view');
if (g && !fired[g]) { fired[g] = true; ym(id, 'reachGoal', g); }
});
}, { threshold: 0.5 });
document.querySelectorAll('[data-track-view]').forEach(function(el){ io.observe(el); });
})();
</script>
Слой 4 — Намерение (взаимодействие с CTA и формой)
| Цель | Тип | Имя | Params |
|---|---|---|---|
| Клик по CTA | JS-событие | cta_click |
{ source: 'hero' | 'pricing' | 'footer' } |
| Фокус в форме | JS-событие | form_focus |
— |
<a href="#contact"
onclick="ym({{ METRIKA_ID }}, 'reachGoal', 'cta_click', { source: 'hero' })">
Оставить заявку
</a>
<script>
document.addEventListener('focusin', function(e){
if (e.target.closest('form') && !window.__formFocusFired) {
window.__formFocusFired = true;
ym({{ METRIKA_ID }}, 'reachGoal', 'form_focus');
}
});
</script>
Слой 5 — Альтернативный контакт (минуя форму)
Многие лиды уходят в Telegram/WhatsApp/звонок — без этих целей они «невидимы».
| Цель | Тип | Имя |
|---|---|---|
| Клик по телефону | JS-событие | phone_click |
| Клик по email | JS-событие | email_click |
| Клик по Telegram | JS-событие | telegram_click |
| Клик по WhatsApp | JS-событие | whatsapp_click |
Универсальный обработчик в layout:
<script>
document.addEventListener('click', function(e){
var a = e.target.closest('a'); if (!a || typeof ym !== 'function') return;
var id = {{ METRIKA_ID }};
var href = a.getAttribute('href') || '';
if (href.startsWith('tel:')) ym(id, 'reachGoal', 'phone_click');
else if (href.startsWith('mailto:')) ym(id, 'reachGoal', 'email_click');
else if (/t\.me\/|telegram\.me\//.test(href)) ym(id, 'reachGoal', 'telegram_click');
else if (/wa\.me\/|whatsapp\.com\//.test(href)) ym(id, 'reachGoal', 'whatsapp_click');
});
</script>
Слой 6 — Конверсия
| Цель | Тип | Имя | Params |
|---|---|---|---|
| Форма отправлена | JS-событие | form_submitted |
{ has_phone, has_message, message_length } |
| Дошёл до thanks | Посещение URL | thanks_visit |
URL /thanks |
В обработчике submit формы (см. instructions/landing_lead_form шаг 3) после успешного ответа GraphQL:
if (typeof ym === 'function') {
ym({{ METRIKA_ID }}, 'reachGoal', 'form_submitted', {
has_phone: !!fields.phone,
has_message: !!fields.message,
message_length: (fields.message || '').length
});
}
window.location.href = spec.success_url || '/thanks';
thanks_visit — резервная цель на случай если JS не сработает. Создаётся в кабинете как «Посещение URL» c условием URL содержит /thanks.
Слой 7 — Составная цель «Лид»
Объединяет все каналы получения контакта: форма + клик по телефону + клик по мессенджеру. Это и есть «настоящее» количество лидов.
В кабинете → «Цели» → «Добавить» → тип «Составная цель» → один шаг с условием:
form_submittedИЛИphone_clickИЛИtelegram_clickИЛИwhatsapp_click
Имя: lead. Эту цель потом таскать в Директ для оптимизации кампаний.
Сводка: что создать в кабинете
Прямая ссылка на цели: https://metrika.yandex.ru/list? → твой счётчик → «Цели» → «Добавить цель».
Все JS-цели создаются типом «JavaScript-событие» с именем идентификатора. Названия в кабинете должны совпадать с теми, что в коде.
JS-события: scroll_50, scroll_100, engaged_15s,
view_pricing, view_offer, view_social_proof,
cta_click, form_focus,
phone_click, email_click, telegram_click, whatsapp_click,
form_submitted
Посещение URL: thanks_visit (URL содержит /thanks)
Составная: lead (form_submitted ИЛИ *_click)
Шаг 4.1 — UTM и параметры визита (для сегментации)
Без этого все источники сваливаются в одну кучу. С этим — в отчётах видно «из Telegram-канала пришло 40, конвертили 5; из Директа 120, конвертили 3».
В layout, после инициализации Метрики:
<script>
(function(){
if (typeof ym !== 'function') return;
var p = new URLSearchParams(location.search);
var params = {
landing_slug: '{{ SLUG }}' // имя лендинга
};
['utm_source','utm_medium','utm_campaign','utm_term','utm_content'].forEach(function(k){
var v = p.get(k); if (v) params[k] = v;
});
// A/B-вариант если используется
var ab = document.documentElement.getAttribute('data-ab');
if (ab) params.ab_variant = ab;
ym({{ METRIKA_ID }}, 'params', params);
})();
</script>
{{ SLUG }} подставить slug лендинга — будет видно если на счётчике несколько лендингов.
После этого в отчёте «Параметры визитов» можно строить срезы: «конверсии по utm_source», «отказы по landing_slug», «CR по ab_variant».
Шаг 5 — Проверить что счётчик и цели работают
- Открыть лендинг в incognito-вкладке с параметром
?utm_source=test - Если есть cookies-плашка — нажать «Принять»
- Прокрутить страницу до конца, подождать 15 секунд
- Кликнуть по любой CTA-кнопке (но вернуться назад)
- Открыть форму, поставить курсор в первое поле, заполнить и отправить
- В кабинете Метрики → отчёт «По времени» → визит появляется за ~30 секунд
- Отчёт «Конверсии» → должны быть:
engaged_15s,scroll_50,scroll_100,cta_click,form_focus,form_submitted,lead - Отчёт «Параметры визитов» → видны
utm_source: test,landing_slug: <slug>
Если визит не пришёл за 2 минуты:
grep -E 'METRIKA_ID|XXXXXX' <layout>— убедись что подстановка сработала- Консоль браузера → нет ли CSP-ошибок (
script-srcдолжен пускатьmc.yandex.ru) - Если
defer: true—ym(..., 'hit', ...)точно вызывается после согласия - Если цели не сработали — имена в кабинете посимвольно совпадают с кодом
Шаг 6 — Поставить себе крон на еженедельный отчёт (опционально)
/cron create "Раз в неделю принеси сводку по Метрике лендинга <slug>:
сколько визитов, конверсий form_submitted, лучший источник трафика, отказы.
Используй Metrika API token из extra_creds.md (если есть) или попроси
человека прислать скрин из кабинета."
--schedule "0 10 * * mon"
API Метрики требует отдельный OAuth-токен — если пользователь даст, агент сможет тянуть отчёты сам. Без токена — крон просто напомнит человеку открыть кабинет.
Проверка результата
- На лендинге в head есть код Метрики,
{{ METRIKA_ID }}подставлен - В кабинете Метрики появляются визиты (incognito-тест)
- Цель
form_submittedсрабатывает при отправке формы - Если есть плашка cookies — счётчик не шлёт хит до согласия
Когда остановиться
- Счётчик создан, ID сохранён в
extra_creds.md - Код в layout, хит идёт (с учётом плашки если она есть)
- Все 13 JS-целей +
thanks_visit+ составнаяleadсозданы в кабинете - Имена в коде и в кабинете совпадают посимвольно
- Параметры визита (
landing_slug,utm_*) приходят в отчёт - Человек видит данные в кабинете
Типичные ошибки
{{ METRIKA_ID }}остался в HTML — счётчик не работает. Проверитьgrep -E 'METRIKA_ID|XXXXXX' <layout>перед sync.- Код вставлен в
<body>, а не в<head>— работает, но первые секунды визитов могут потеряться. Переставить. defer: trueбез ручногоhit— счётчик загружен, но визиты не считаются. Добавитьym(..., 'hit', ...)после согласия.- Цель в коде есть, в кабинете не создана —
reachGoalуходит впустую, в отчётах ноль. Создать цель с тем же именем. - Webvisor включён, а в политике конфиденциальности про запись действий ни слова — нарушение. Дописать строку в
legal/personal_data_consentпро запись поведения. - Один счётчик на несколько разных лендингов — отчёты смешиваются. Лучше один счётчик на один продукт; разделять источники через UTM, а не через счётчики.
- Поставили счётчик, не настроили ни одной цели — есть трафик, нет конверсий, лендинг непонятно работает или нет. Минимум
form_submittedобязателен.
Кейсы
Кейс 1: новый лендинг, метрики у пользователя ещё не было
→ Шаг 1 (создать) → Шаг 2 (сохранить ID) → Шаг 3 вариант A или B → Шаг 4 (цель form_submitted) → Шаг 5 (проверить).
Кейс 2: лендинг уже сделан, счётчика нет
→ Напомнить про метрику → если согласен, дальше как кейс 1 со Шага 1.
Кейс 3: метрика стоит, но целей нет
→ Сразу Шаг 4 (зашить полный набор) → Шаг 5 (проверить).
Кейс 4: EU-аудитория
→ Обязательно вариант B (Шаг 3) + плашка cookies из instructions/personal_data_consent с равноценными кнопками «Принять» / «Отклонить». На «Отклонить» — хит не запускать никогда.
Кейс 5: пользователь говорит «слишком много целей, оставь минимум»
→ Сократить до: form_submitted, cta_click, phone_click, telegram_click, составная lead. Это нижняя граница чтобы увидеть конверсии и каналы. Меньше — слепо.
Связано: instructions/create_landing_page, instructions/landing_lead_form, instructions/personal_data_consent, insights/how_to_check_yourself
Источник: официальная документация Яндекс.Метрики — https://yandex.ru/support/metrica/quick-start.html, https://yandex.ru/support/metrica/code/counter-initialize.html, https://yandex.ru/support/metrica/general/goals.html