Data Layer — це JavaScript-об’єкт, котрий працює як проміжна ланка між сайтом і системами аналітики на кшталт Google Analytics. Найчастіше його сприймають виключно в контексті електронної комерції: відстеження покупок, додавання товарів у кошик, переходів між категоріями. І це працює відмінно. Проте обмежуватися таким підходом — те саме, що користуватися смартфоном лише для дзвінків.
У статті я розгляну п’ять нестандартних способів використання dataLayer, що допоможуть зібрати дані, яких не видно у стандартній аналітиці, та перетворити їх на інсайти для покращення UX, конверсії та роботи ресурсу.
- Фіксація помилок JavaScript у браузері
- Відстеження взаємодії з інтерактивними картами
- Відстеження поведінки при валідації форм
- Копіювання тексту
- Відстеження «мертвих кліків»
- Як передати дані з DataLayer в GA4
Фіксація помилок JavaScript у браузері
«Чому конверсія на мобільних пристроях нижча ніж на десктопі?» — питання, котре мучить багатьох власників eCommerce-проєктів.
А відповідь часто криється в JavaScript-помилках, що блокують критичну функціональність, але непомітні для стандартної аналітики.
Google Analytics та інші системи збирають дані про відвідування, кліки, конверсії. Але вони не бачать, коли виникає збій JavaScript і порушує функціональність. Користувач натискає «Додати в кошик», нічого не відбувається, він йде до конкурентів — а ви навіть не знаєте, що сталося.
Є два основних способи для налаштування виявлення JS-помилок через dataLayer.
Спосіб 1. За допомогою обробника JavaScript — window.onerror
Глобальний обробник проблем в логіці для JavaScript. Коли на сторінці виникає JavaScript-помилка, браузер автоматично викликає цю функцію.
Спосіб підходить для простого відстеження збоїв у коді сайту — коли перестає працювати кнопка «Купити зараз», ламається калькулятор доставки або не працює слайдер на головній сторінці.
Ось базовий код, який автоматично відстежуватиме всі JavaScript-помилки на сторінці:
window.onerror = function(errorMessage, url, lineNumber, columnNumber, errorObject) {
dataLayer.push({
'event': 'javascript_error',
'error_message': errorMessage,
'error_url': url,
'error_line': lineNumber,
'error_column': columnNumber,
'page_url': window.location.href
});
return false; // дозволяє браузеру також обробити помилку
};Мінус: не ловить помилки завантаження ресурсів (картинок, скриптів, стилів), а підключення кількох обробників потребує додаткового коду.
Спосіб 2. За допомогою обробника JavaScript — window.addEventListener('error')
Більш гнучкий підхід, що дає можливість відстежувати різні типи помилок.
Спосіб буде корисний, коли потрібен комплексний моніторинг — відстежувати не тільки поламаний код, а й проблеми з завантаженням картинок товарів, CSS-файлів або JavaScript-бібліотек:
window.addEventListener('error', function(event) {
// Перевіряємо, що це помилка завантаження ресурсу
if (event.target !== window) {
dataLayer.push({
'event': 'resource_error',
'error_type': 'resource_loading',
'resource_url': event.target.src || event.target.href,
'resource_type': event.target.tagName,
'page_url': window.location.href
});
} else {
// Це JavaScript помилка
dataLayer.push({
'event': 'javascript_error',
'error_message': event.message,
'error_url': event.filename,
'error_line': event.lineno,
'error_column': event.colno,
'page_url': window.location.href
});
}
});Якщо сайт використовує сучасний JavaScript з async/await (наприклад, для завантаження даних з API без перезавантаження сторінки), варто окремо відстежувати помилки в асинхронних операціях.
Простими словами: коли сайт завантажує дані «у фоні» (наприклад, підтягує ціни товарів без оновлення сторінки), помилки в цих процесах можуть зламати функціональність, але ви про них не дізнаєтесь зі звичайних логів.
Щоб фіксувати такі необроблені -помилки, додайте код:
window.addEventListener('unhandledrejection', function(event) {
dataLayer.push({
'event': 'promise_error',
'error_message': event.reason.message || 'Promise rejected',
'page_url': window.location.href
});
});Також на більшості сайтів завантажуються сторонні скрипти — реклама Google Ads, віджети соціальних мереж, чати підтримки. Збої в цих скриптах не пов’язані з вашим кодом і можуть перевантажити аналітику сотнями непотрібних записів. Щоб відстежувати тільки помилки вашого ресурсу, додайте фільтрацію:
window.addEventListener('error', function(event) {
// Ігноруємо помилки зі сторонніх доменів
if (event.filename && !event.filename.includes(window.location.hostname)) {
return;
}
// Ваш код відстеження...
});Описані підходи особливо важливі для:
великих eCommerce-платформ — проблеми в процесі оформлення замовлення можуть призводити до щоденних втрат у тисячі доларів;
SaaS-проєктів — JavaScript-баги блокують ключову функціональність і знижують задоволеність користувачів;
сайтів, що мають багато інтерактивних елементів — слайдери, калькулятори, фільтри, що залежать від JavaScript.
Фіксація у Google Analytics дає можливість швидко ідентифікувати:
сторінки, де найчастіше виникають збої;
найбільш проблемні браузери або пристрої;
як саме це впливає на конверсію.
Відстеження взаємодії з інтерактивними картами
«Відвідувачі активно використовують карту на головній сторінці, але конверсія все одно низька. Що вони там роблять?» — питання, знайоме всім, хто працює з нерухомістю, готелями або локальними послугами.
Карти — це потужний інструмент взаємодії з користувачами. Вони показують, що саме цікавить відвідувача: який район він збільшує на карті, на які маркери натискає, яку інформацію переглядає. Усе це — цінні сигнали про наміри та потреби, котрі можна використовувати для персоналізації й підвищення конверсії.
Карти допомагають:
На майданчиках з продажу нерухомості зрозуміти, які райони найбільш популярні, в яких зонах найчастіше збільшують масштаб.
На платформах бронювання готелів — котрі локації переглядають найчастіше, наскільки далеко від центру готові розглядати помешкання.
Якщо на сайті з продажу нерухомості вже інтегрована Google Maps, можна додати відстеження до неї. Код для виявлення основних взаємодій:
// Ініціалізуємо карту з обробниками подій
function initMap() {
const map = new google.maps.Map(document.getElementById('map'), {
zoom: 10,
center: {lat: 50.4501, lng: 30.5234} // Київ
});
// Відстежуємо зміни масштабу
map.addListener('zoom_changed', function() {
dataLayer.push({
'event': 'map_zoom_change',
'zoom_level': map.getZoom(),
'map_center_lat': map.getCenter().lat(),
'map_center_lng': map.getCenter().lng(),
'page_url': window.location.href
});
});
// Відстежуємо перетягування карти
map.addListener('dragend', function() {
const bounds = map.getBounds();
dataLayer.push({
'event': 'map_pan',
'map_center_lat': map.getCenter().lat(),
'map_center_lng': map.getCenter().lng(),
'viewport_ne_lat': bounds.getNorthEast().lat(),
'viewport_ne_lng': bounds.getNorthEast().lng(),
'viewport_sw_lat': bounds.getSouthWest().lat(),
'viewport_sw_lng': bounds.getSouthWest().lng()
});
});
// Додаємо маркери квартир з відстеженням кліків
apartments.forEach(function(apartment) {
const marker = new google.maps.Marker({
position: {lat: apartment.lat, lng: apartment.lng},
map: map,
title: apartment.title
});
marker.addListener('click', function() {
dataLayer.push({
'event': 'map_marker_click',
'property_id': apartment.id,
'property_type': apartment.type, // 'apartment', 'house', 'commercial'
'property_price': parseFloat(apartment.price),
'property_district': apartment.district,
'marker_lat': apartment.lat,
'marker_lng': apartment.lng
});
});
});
}Що означають події:
map_zoom_change — спрацьовує, коли відвідувач змінює масштаб карти — кнопками +/-, колесом миші або жестами на мобільному. Показує, наскільки детально людина хоче розглянути локацію. Часте збільшення масштабу в певному районі сигналізує про високий інтерес до цієї зони.
map_pan — спрацьовує після того, як відвідувач перетягнув карту в інше місце. Допомагає зрозуміти, які географічні зони цікавлять користувачів. Viewport bounds (межі видимої області) показують, яку частину карти бачить юзер на екрані.
map_marker_click — активується при натисканні на маркер конкретного об’єкта (квартири, будинку, комерційної нерухомості). Це прямий сигнал інтересу до конкретної пропозиції.
Для платформ бронювання готелів логіка схожа, але з акцентом на рейтинг, ціну та відстань до центру міста. Для початку потрібен масив з даними про готелі — зазвичай інформація надходить з бази даних або API. Нижче наведено приклад структури такого масиву:
// Приклад структури даних готелів
// Замініть назви полів на ті, що використовуються у вашій базі даних
const hotels = [
{
id: 'hotel_123', // id готелю
name: 'Готель "Київський"', // назва готелю
rating: 4.5, // рейтинг готелю
pricePerNight: 2500, // ціна за ніч в грн
distanceToCenter: 1.2, // відстань до центру в км
lat: 50.4501, // координати широти
lng: 30.5234, // координати довготи
},
{
id: 'hotel_456',
name: 'Готель "Дніпро"',
rating: 4.8,
pricePerNight: 3200,
distanceToCenter: 0.5,
lat: 50.4547,
lng: 30.5238,
}
// ... інші готелі
];Тепер створіть функцію для відстеження взаємодій та додайте обробники подій:
function trackHotelMapInteraction(hotelData, interactionType) {
dataLayer.push({
'event': 'hotel_map_interaction',
'interaction_type': interactionType, // 'marker_click', 'info_window_open', 'price_filter'
'hotel_id': hotelData.id,
'hotel_name': hotelData.name,
'hotel_rating': parseFloat(hotelData.rating),
'hotel_price_per_night': parseFloat(hotelData.pricePerNight),
'distance_to_center': parseFloat(hotelData.distanceToCenter), // в км
'location_lat': hotelData.lat,
'location_lng': hotelData.lng,
});
}
// Відстеження кліків по готелях з різними характеристиками
marker.addListener('click', function() {
trackHotelMapInteraction(hotelData, 'marker_click');
});Значення типів взаємодій:
marker_click — натискання безпосередньо на маркер готелю на карті. Показує початковий інтерес до конкретного об’єкта. Дає змогу відстежувати всю інформацію про готель, щоб зрозуміти, які характеристики (ціна, рейтинг, локація) найбільше привертають увагу.
info_window_open — відкриття інформаційного вікна (popup) з деталями про готель. Це сильніший сигнал інтересу порівняно з простим кліком по маркеру — користувач хоче дізнатися більше.
price_filter — застосування фільтра за ціною безпосередньо на карті (якщо така функція передбачена). Дає розуміння, у який ціновий сегмент спрямований попит і які діапазони цікавлять аудиторію найбільше.
Окрім базових взаємодій, корисно відстежувати час, котрий відвідувач проводить на карті:
// Відстеження часу взаємодії з картою
let mapEngagementStart = null;
// Фіксуємо початок взаємодії при русі курсора по карті
map.addListener('mousemove', function() {
if (!mapEngagementStart) {
mapEngagementStart = Date.now();
}
});
// Фіксуємо кінець взаємодії, коли курсор покидає карту
map.addListener('mouseout', function() {
if (mapEngagementStart) {
const timeSpent = Math.round((Date.now() - mapEngagementStart) / 1000);
// Відстежуємо тільки якщо користувач провів на карті хоча б 2 секунди
if (timeSpent >= 2) {
dataLayer.push({
'event': 'map_engagement',
'engagement_duration': timeSpent, // секунди
'page_url': window.location.href
});
}
mapEngagementStart = null;
}
});Що означають ці події:
mousemove — спрацьовує при русі курсора по карті. Використовується для фіксації початку активної взаємодії з картою.
mouseout — спрацьовує, коли курсор покидає область карти. Фіксує завершення взаємодії та показує загальний час, який користувач провів на карті. Варто відстежувати тільки взаємодії від 2 секунд, щоб відфільтрувати випадкові наведення курсора.
Відстеження поведінки при валідації форм
Зазвичай ми бачимо тільки кінцевий результат: користувач або відправив форму, або ні. Але що відбувається на всьому шляху? Скільки було спроб відправлення? На якому полі виникло тертя? Чи з’являлися взагалі повідомлення про помилки валідації?
Саме ці «темні зони» поведінки приховують відповіді на запитання, чому просідає конверсія. І саме їх dataLayer допомагає зробити видимими.
Припустимо, є проста контактна форма з полями email та телефон. Потрібно відстежувати всі спроби відправки — успішні і невдалі — щоб зрозуміти, на яких саме полях найчастіше виникають помилки.
Ось базовий приклад для контактної форми. Код спрацьовує при кожній спробі відправки, навіть якщо форма не пройшла валідацію:
// Лічильник спроб для кожної форми
let formAttempts = {};
function trackFormValidation(formId, validationResult, errorFields = [], errorTypes = []) {
// Збільшуємо лічильник спроб
if (!formAttempts[formId]) {
formAttempts[formId] = 0;
}
formAttempts[formId]++;
dataLayer.push({
'event': 'form_validation_attempt',
'form_id': formId,
'form_name': document.getElementById(formId).getAttribute('name') || formId,
'validation_success': validationResult,
'error_fields': errorFields,
'error_types': errorTypes, // типи помилок: required, format, length
'attempt_number': formAttempts[formId],
'page_url': window.location.href
});
}
// Приклад використання при відправці форми
document.getElementById('contact-form').addEventListener('submit', function(e) {
let errors = [];
let errorTypes = [];
let isValid = true;
// Перевіряємо email
const email = this.querySelector('[name="email"]').value;
if (!email) {
errors.push('email');
errorTypes.push('required');
isValid = false;
} else if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) {
errors.push('email');
errorTypes.push('format');
isValid = false;
}
// Перевіряємо телефон
const phone = this.querySelector('[name="phone"]').value;
if (!phone) {
errors.push('phone');
errorTypes.push('required');
isValid = false;
} else if (!/^[\d\+\-\s\(\)]{10,}$/.test(phone)) {
errors.push('phone');
errorTypes.push('format');
isValid = false;
}
// Відстежуємо спробу валідації
trackFormValidation('contact-form', isValid, errors, errorTypes);
if (!isValid) {
e.preventDefault(); // Зупиняємо відправку
}
});Для форм замовлення можна відстежувати додаткові параметри — етап оформлення, суму замовлення, спосіб доставки:
// Лічильники для кожного кроку checkout
let checkoutAttempts = {};
function trackCheckoutValidation(step, validationData) {
// Унікальний ключ для кожного кроку
const stepKey = `checkout_${step}`;
if (!checkoutAttempts[stepKey]) {
checkoutAttempts[stepKey] = 0;
}
checkoutAttempts[stepKey]++;
dataLayer.push({
'event': 'checkout_validation',
'checkout_step': step, // 'shipping', 'payment', 'review'
'validation_success': validationData.isValid,
'error_fields': validationData.errorFields,
'error_types': validationData.errorTypes,
'attempt_number': checkoutAttempts[stepKey],
'order_value': parseFloat(validationData.orderValue),
'payment_method': validationData.paymentMethod || 'unknown'
});
}Щоб адаптувати цей код під конкретний проєкт, об’єкт validationData має містити повний набір даних про стан форми та замовлення. Структура виглядає так:
const validationData = {
isValid: true, // true/false -- чи пройшла форма валідацію
errorFields: ['address', 'city'], // масив назв полів з помилками
errorTypes: ['required', 'format'], // масив типів помилок (required, format, length)
orderValue: '2500.00', // сума замовлення (рядок або число)
paymentMethod: 'card' // спосіб оплати: 'card', 'cash', 'paypal' тощо
};Щоб інтегрувати рішення в реальний checkout-процес:
Визначте кроки checkout — наприклад, shipping (доставка), payment (оплата), review (перевірка).
Зберіть дані про замовлення — сума зазвичай вже є на сторінці у прихованому полі або змінній JavaScript.
Замініть назви полів — errorFields має містити реальні назви полів з вашої форми (наприклад, 'billing_address', 'card_number').
Викликайте функцію на кожному етапі відправки, передавши відповідний step та validationData.
Важливий нюанс для багатосторінкових форм: після перезавантаження сторінки лічильник спроб відправки скидається.
Щоб зберегти дані між оновленнями, використовуйте sessionStorage:
// Зберігаємо лічильники в sessionStorage
function getAttemptCount(formId) {
const stored = sessionStorage.getItem(`form_attempts_${formId}`);
return stored ? parseInt(stored) : 0;
}
function incrementAttemptCount(formId) {
const currentCount = getAttemptCount(formId) + 1;
sessionStorage.setItem(`form_attempts_${formId}`, currentCount.toString());
return currentCount;
}Копіювання тексту (copy-to-clipboard)
«Промокод показується 10 000 разів на місяць, а використовується всього 500. Його копіюють чи просто ігнорують?» — класична загадка для eCommerce- та маркетингових команд.
Копіювання тексту — одна з найбільш недооцінених взаємодій. Воно завжди дає сигнал про намір:
копіюють промокод — збираються зробити покупку;
копіюють email або телефон — хочуть зв’язатися з вами поза сайтом;
копіюють фрагмент статті — зберігають або діляться контентом.
За замовчуванням ці мікроконверсії непомітні, але вони можуть розповісти багато цікавого про поведінку користувачів та ефективність контенту.
Як відстежити всі копіювання на сторінці
Браузер надає подію copy, котра спрацьовує кожного разу, коли відвідувач копіює текст. Можна відстежувати всі копіювання на сторінці або тільки в конкретних зонах.
Ось код для загального відстеження копіювання на всій сторінці:
document.addEventListener('copy', function(e) {
// Отримуємо скопійований текст
const copiedText = window.getSelection().toString();
// Відстежуємо тільки осмислений текст (більше 3 символів)
if (copiedText.length > 3) {
dataLayer.push({
'event': 'content_copy',
'copied_text': copiedText.substring(0, 100), // перші 100 символів
'copied_length': copiedText.length,
'page_url': window.location.href,
'page_title': document.title
});
}
});Як відстежити окремі важливі елементи
Набагато корисніше відстежувати копіювання конкретних важливих елементів — промокодів, контактів, фрагментів статей, щоб зрозуміти, що саме цікавить користувачів.
Уявімо, що є eCommerce-сайт із промокодами, розміщеними в різних місцях — на банері головної сторінки, в поп-апі при виході, на сторінці оформлення замовлення. Завдання — зрозуміти, звідки найчастіше копіюють промокоди, які типи знижок їх найбільше цікавлять та чи впливає факт копіювання на завершення покупки.
Код для відстеження:
// Відстеження копіювання промокодів
document.querySelectorAll('.promo-code').forEach(function(promoElement) {
promoElement.addEventListener('copy', function(e) {
const promoCode = this.textContent.trim();
dataLayer.push({
'event': 'promo_code_copy',
'promo_code': promoCode,
'promo_location': this.getAttribute('data-location') || 'unknown', // banner, popup, checkout
'promo_discount': this.getAttribute('data-discount') || 'unknown', // 10%, 15%, 20%
'page_url': window.location.href
});
});
});Якщо відвідувачі активно копіюють промокоди, але не використовують їх — можливо, процес оформлення замовлення занадто складний.
Як відстежувати копіювання контактної інформації
Для цього додайте код:
// Відстеження копіювання email та телефонів
document.querySelectorAll('[data-contact-type]').forEach(function(contactElement) {
contactElement.addEventListener('copy', function(e) {
const contactType = this.getAttribute('data-contact-type'); // email, phone, address
const contactValue = this.textContent.trim();
dataLayer.push({
'event': 'contact_copy',
'contact_type': contactType,
'contact_value': contactValue,
'contact_location': this.closest('section')?.id || 'unknown', // header, footer, contact-page
'page_url': window.location.href
});
});
});Якщо копіюють контакти замість того, щоб скористатися формою — це може свідчити про два проблемні сценарії:
форма працює некоректно;
форма викликає недовіру, і користувач обирає безпечніший для себе спосіб зв’язку.
Як відстежувати копіювання з блоків коду
Якщо ваш сайт містить технічну документацію, туторіали або навчальні матеріали з прикладами коду — важливо знати, які саме фрагменти копіюють найчастіше.
Це допоможе:
визначити найпопулярніші приклади, щоб розширити документацію в цих темах;
виявити складні секції — якщо код копіюють багато, але на сторінці високий показник відмов, можливо, приклад незрозумілий;
виявити, типи фрагментів коду, котрі цікавлять вашу аудиторію.
Це можна визначити за допомогою наступного коду:
// Відстеження копіювання з блоків коду
document.querySelectorAll('pre code').forEach(function(codeBlock, index) {
codeBlock.addEventListener('copy', function(e) {
const copiedCode = window.getSelection().toString();
const language = this.className.match(/language-(\w+)/)?.[1] || 'unknown';
dataLayer.push({
'event': 'code_snippet_copy',
'code_language': language,
'code_length': copiedCode.length,
'code_block_index': index,
'article_title': document.title,
'page_url': window.location.href
});
});
});Відстеження «мертвих кліків» (rage clicks)
«Чому кнопка “Купити” отримує 5000 кліків, а в кошик додається тільки 1000 товарів?» — питання, що може коштувати бізнесу десятки тисяч доларів втраченого доходу.
Уявімо ситуацію: людина знайшла потрібний товар, готова купити, натискає «Додати в кошик» — і нічого. Вона тисне знову. І ще раз. Три, чотири, п’ять разів. Роздратування зростає, користувач залишає сайт і переходить до конкурентів. Бізнес втрачає продаж, навіть не здогадуючись про проблему.
Rage clicks або кліки люті — це серії швидких повторних кліків по одному елементу, коли він не реагує, повільно завантажується, працює не так, як очікується, або взагалі зламаний. Стандартна аналітика цього не помічає: вона бачить лише кількість кліків, але не їхній контекст.
Принцип виявлення простий: коли по одному елементу виконано 3+ кліки за короткий проміжок (1–2 секунди), це сигнал фрустрації. Важливо зафіксувати селектор елемента, кількість кліків і часовий інтервал.
Ось базовий код для виявлення rage clicks:
// Зберігаємо дані про кліки
let clickTracking = {};
document.addEventListener('click', function(e) {
const element = e.target;
const elementPath = getElementPath(element);
const currentTime = Date.now();
// Ініціалізуємо дані для елемента, якщо їх ще немає
if (!clickTracking[elementPath]) {
clickTracking[elementPath] = {
clicks: [],
element: element
};
}
// Додаємо час кліку
clickTracking[elementPath].clicks.push(currentTime);
// Залишаємо тільки кліки за останні 2 секунди
clickTracking[elementPath].clicks = clickTracking[elementPath].clicks.filter(
time => currentTime - time < 2000
);
// Якщо 3+ кліки за 2 секунди -- це rage click
if (clickTracking[elementPath].clicks.length >= 3) {
dataLayer.push({
'event': 'rage_click',
'element_type': element.tagName.toLowerCase(),
'element_id': element.id || 'no_id',
'element_class': element.className || 'no_class',
'element_text': element.textContent?.substring(0, 50) || '',
'element_path': elementPath,
'click_count': clickTracking[elementPath].clicks.length,
'page_url': window.location.href,
'viewport_width': window.innerWidth,
'viewport_height': window.innerHeight
});
// Скидаємо лічильник, щоб уникнути дублювання подій
clickTracking[elementPath].clicks = [];
}
});
// Функція для отримання унікального шляху до елемента
function getElementPath(element) {
const path = [];
let current = element;
while (current && current.tagName) {
let selector = current.tagName.toLowerCase();
if (current.id) {
selector += '#' + current.id;
path.unshift(selector);
break;
} else if (current.className) {
selector += '.' + current.className.split(' ').join('.');
}
path.unshift(selector);
current = current.parentElement;
}
return path.join(' > ');
}Для більш точного моніторингу можна відстежувати тільки важливі елементи — кнопки покупки, форми, фільтри, навігацію. Це зменшить шум в аналітиці і дозволяє сфокусуватися саме на критичних проблемах, котрі впливають на конверсію.
Уявімо eCommerce-сайт, де особливо важливі кнопки «Додати в кошик» та «Оформити замовлення». Нижче — приклад, як відстежувати rage clicks саме на таких елементах:
// Відстеження rage clicks на критичних кнопках
const criticalButtons = document.querySelectorAll('.add-to-cart, .checkout-button, .apply-filter');
let buttonClicks = new Map();
criticalButtons.forEach(button => {
button.addEventListener('click', function(e) {
const buttonId = this.getAttribute('data-product-id') || this.id || 'unknown';
const currentTime = Date.now();
if (!buttonClicks.has(buttonId)) {
buttonClicks.set(buttonId, []);
}
const clicks = buttonClicks.get(buttonId);
clicks.push(currentTime);
// Залишаємо тільки кліки за останні 1.5 секунди
const recentClicks = clicks.filter(time => currentTime - time < 1500);
buttonClicks.set(buttonId, recentClicks);
// 3+ кліки за 1.5 секунди
if (recentClicks.length >= 3) {
dataLayer.push({
'event': 'rage_click_critical',
'button_type': this.classList.contains('add-to-cart') ? 'add_to_cart' : 'checkout',
'product_id': this.getAttribute('data-product-id') || null,
'button_text': this.textContent.trim(),
'click_count': recentClicks.length,
'page_url': window.location.href,
'user_agent': navigator.userAgent
});
// Скидаємо
buttonClicks.set(buttonId, []);
}
});
});Окрім фіксації кліків люті, корисно збирати контекст, щоб точніше визначити причину проблеми. Наприклад, елемент може бути перекритий іншим блоком, знаходитися поза межами viewport або JavaScript не встиг завантажитися.
Наведений код допомагає з'ясувати причину rage clicks — він перевіряє видимість кнопки, її позицію на екрані та інші технічні характеристики:
function analyzeElement(element) {
const rect = element.getBoundingClientRect();
const computedStyle = window.getComputedStyle(element);
return {
'is_visible': computedStyle.display !== 'none' && computedStyle.visibility !== 'hidden',
'is_in_viewport': rect.top >= 0 && rect.bottom <= window.innerHeight,
'has_pointer_events': computedStyle.pointerEvents !== 'none',
'z_index': computedStyle.zIndex,
'element_width': rect.width,
'element_height': rect.height
};
}
// Використання при rage click
if (recentClicks.length >= 3) {
const diagnostics = analyzeElement(this);
dataLayer.push({
'event': 'rage_click_critical',
'button_type': this.classList.contains('add-to-cart') ? 'add_to_cart' : 'checkout',
'click_count': recentClicks.length,
...diagnostics, // додаємо діагностичні дані
'page_url': window.location.href
});
}Головне — не ігнорувати ці сигнали. Якщо бачите rage clicks на важливих елементах, це пріоритет номер один для виправлення.
Як передати дані з Data Layer в GA4
Щоб дані потрапили в Google Analytics або інші системи аналітики, потрібен посередник — Google Tag Manager (GTM). Він «слухає» події в dataLayer і передає їх у вибрані інструменти.
Процес виглядає так:
Розберу на конкретному прикладі з rage clicks.
Крок 1. Створюємо змінні в GTM
Спочатку потрібно створити змінні (Variables), котрі витягуватимуть дані з dataLayer.
Перейдіть в GTM. Оберіть меню Variables і натисніть New.
Оберіть тип змінної — Data Layer Variable.
Створіть змінні для кожного параметра:
Назва змінної: DL - Rage Click - Element Type
Data Layer Variable Name: element_type
Назва змінної: DL - Rage Click - Element ID
Data Layer Variable Name: element_id
Назва змінної: DL - Rage Click - Click Count
Data Layer Variable Name: click_countПрефікс DL допомагає швидко знайти змінні dataLayer серед інших.
Крок 2. Створюємо тригер
Тепер потрібен тригер, що спрацьовуватиме, коли в dataLayer з’являється подія rage_click.
В пункті Triggers натисніть New.
Оберіть тип тригера — Custom Event.
В полі Event name зазначте rage_click (точно як у коді).
Збережіть налаштування.
Крок 3. Створюємо тег для GA4
Створіть тег для відправки даних в Google Analytics.
Перейдіть в розділ Tags і натисніть New.
Оберіть тип тега — Google Analytics: GA4 Event.
Впишіть Measurement ID з GA4 або оберіть ваш GA4 Config.
В полі Event Name задайте rage_click.
В поле Event Parameters додайте параметри:
Parameter Name: element_type
Value: {{DL - Rage Click - Element Type}}
Parameter Name: element_id
Value: {{DL - Rage Click - Element ID}}
Parameter Name: click_count
Value: {{DL - Rage Click - Click Count}}
Parameter Name: page_path
Value: {{Page Path}}Перейдіть в пункт Triggering та оберіть створений тригер rage_click. Збережіть налаштування.
Крок 4. Тестуємо
Перед публікацією обов’язково протестуйте коректність роботи. Для цього:
Увімкніть режим попереднього перегляду. У GTM натисніть Preview і відкрийте сайт у режимі дебагу. Праворуч з’явиться панель GTM Debug.
Створіть подію. Зробіть декілька швидких кліків по будь-якому елементу на сторінці імітуючи rage click.
Перевірте дані в Debug View. У вікні GTM Preview має з’явитися подія rage_click. Розгорніть її та переконайтесь, що всі змінні заповнені правильно:
- click_element — назва елемента;
- click_count — кількість кліків;
- page_url — URL сторінки.
Перевірте відправку в GA4. Впевніться, що тег спрацював без помилок. Це можна побачити у розділі Tags Fired в GTM Debug View.
Крок 5. Дивимось дані в GA4
Після публікації контейнера GTM події почнуть надходити в Google Analytics. Перевірити їх можна у кілька способів:
Reports → Realtime — для перевірки в реальному часі;
Reports → Events — список всіх подій, там з'явиться rage_click;
Explore → Free form — для детального аналізу з параметрами.
Є можливість створити кастомний звіт, щоб бачити:
елементи, що найчастіше викликають rage clicks;
сторінки, де це відбувається;
середню кількість кліків у кожному випадку;
залежність від типу пристрою або браузера.
Той самий підхід працює й для інших подій зі статті:
javascript_error — фіксація помилок JS;
form_validation_attempt — спроби відправлення форм;
map_marker_click — кліки по карті;
promo_code_copy — копіювання промокодів.
Для кожної події налаштуйте окремі змінні, тригер і тег. Спочатку це виглядає трудомістким, але після перших двох-трьох налаштувань процес стає майже автоматичним.
Висновок
Data Layer — це не лише інструмент для eCommerce. П’ять способів, розглянутих в статті, допоможуть вам:
Відстежувати JavaScript-помилки — виявляти технічні збої, котрі ламають функціональність сайту.
Відстежувати взаємодію з картами — зрозуміти географічні інтереси відвідувачів.
Фіксувати проблеми з валідацією форм — зрозуміти, чому користувачі не завершують оформлення замовлення.
Аналізувати копіювання контенту — побачити, які промокоди чи приклади коду найцікавіші для аудиторії.
Виявляти rage clicks — знайти елементи, що працюють некоректно і викликають роздратування.
Головне — кожна подія в dataLayer повинна відповідати на конкретне бізнес-питання: чому знижується конверсія? Які елементи працюють некоректно? Тільки тоді аналітика стає корисною, а не купою цифр у звітах.
Експериментуйте з цими прикладами, адаптуйте їх під свій проєкт — і ваша аналітика стане набагато глибшою.
Свіжі
Усе, що вам потрібно знати про природні посилання
Природні лінки не є за замовчуванням високоякісними та корисними, іноді вони можуть бути навіть шкідливими. Як і чому, розбираю у статті
Новини AI-пошуку: що змінилося за останні місяці
Дайджест головних оновлень AI і їхнього впливу на ринок
Посібник з Apple Ads на 2026 рік
Команда RadASO підготувала детальну інструкцію, як користуватися Apple Ads і покращити результати на платформі









