- Co to jest scroll depth i po co to mierzyć
- Definicje i podstawowe metryki
- Dlaczego to ma znaczenie
- Standardy i konwencje raportowania
- Przygotowanie: narzędzia, zakres i architektura pomiaru
- Wybór narzędzia i architektury
- Plan progów i nazewnictwa
- Zgody i prywatność
- Wydajność i jakość danych
- Implementacja w Google Tag Manager + GA4 krok po kroku
- Krok 1: Podstawy w GA4 i GTM
- Krok 2: Włącz zmienne przewijania
- Krok 3: Utwórz wyzwalacz Scroll Depth
- Krok 4: Tag zdarzenia GA4
- Krok 5: Ograniczenie do jednorazowego wysłania progu
- Krok 6: Definicje niestandardowe w GA4
- Krok 7: Testy i weryfikacja
- Implementacja bez GTM: czysty JavaScript
- Algorytm procentu przewinięcia
- Przykładowy kod z throttlingiem
- Metoda IntersectionObserver i znaczniki progów
- Wysyłka do GA4 bez gtag – Measurement Protocol
- Jakość danych, analiza i rozwiązywanie problemów
- Typowe pułapki techniczne
- Projektowanie progów: 25/50/75/90/100 czy inne?
- Łączenie z konwersjami i segmentacją
- Walidacja i sanity-check
- Wielokrotne przewinięcia i kierunek
- Makiety raportów i nazewnictwo
- WordPress i gotowe wtyczki
- Fallback i odporność
- Utrzymanie i wersjonowanie
- Alternatywy i rozszerzenia
- Uwagi końcowe o dokładności
Pomiar faktycznego zaangażowania użytkownika nie kończy się na odsłonie strony. To, jak głęboko ktoś przewija treść, mówi wiele o jakości contentu, układzie strony i barierach w odbiorze. Dzięki metryce scroll depth możemy zbudować realne hipoteki optymalizacyjne: co skrócić, co przenieść wyżej, kiedy zaproponować CTA. Poniżej znajdziesz kompletną instrukcję – od wyboru narzędzi, przez konfigurację w GTM/GA4, po kod w JavaScript i dobre praktyki, które zapewnią rzetelne dane.
Co to jest scroll depth i po co to mierzyć
Definicje i podstawowe metryki
Scroll depth (głębokość przewijania) to odsetek wysokości dokumentu, który użytkownik obejrzał w pionie. W praktyce mierzymy najczęściej progi: 25%, 50%, 75%, 90% oraz 100%. Dla jasności: 100% nie oznacza, że ktoś „przeczytał” wszystko, tylko że dotarł do końca treści, a przynajmniej do dolnej granicy kontenera dokumentu.
Możliwe są też alternatywy:
- piksele absolutne (np. 1500 px przewinięte),
- sekcje/akapit (np. wejście w „Opinie” lub „FAQ”),
- warunki złożone (np. osiągnięcie 50% + minimalnie 10 sekund na stronie).
Dlaczego to ma znaczenie
Głębokość przewijania to sygnał realnego zaangażowania i „konsumpcji” treści:
- Ocena jakości contentu i układu: czy lead i nagłówki wystarczająco „niosą” dalej?
- Optymalizacja rozmieszczenia CTA: czy przyciski nie są za nisko?
- Wsparcie decyzji SEO: dopasowanie długości i struktury tekstów do intencji użytkownika.
- Lejek konwersji: korelacja między głębokością a kliknięciami/konwersjami.
Standardy i konwencje raportowania
Najczęściej raportuje się ułamki procentowe (25/50/75/90/100). „90%” bywa praktycznym zamiennikiem „prawie koniec”, bo stopki, bannery lub dynamiczne komponenty potrafią przesuwać realny „koniec” strony. Pamiętaj, że GA4 domyślnie ma zdarzenie „scroll” w ramach Rozszerzonego Pomiaru, ale tylko dla 90%. Jeśli potrzebujesz innych progów, wdrożysz je niestandardowo.
Przygotowanie: narzędzia, zakres i architektura pomiaru
Wybór narzędzia i architektury
Najbardziej elastyczny zestaw to GTM + GA4. GTM udostępnia gotowy wyzwalacz przewijania i zmienne, a GA4 – raportowanie i łączenie z innymi sygnałami. Alternatywy: Matomo, Plausible czy własna baza przez Measurement Protocol. Kluczowe, by zachować spójne nazwy zdarzeń i parametrów oraz kontrolę nad miejscem, w którym dane powstają (klient vs. serwer).
Plan progów i nazewnictwa
Zanim rozpoczniesz implementację, zdecyduj:
- Progi: 25/50/75/90/100 (zalecane) czy inne?
- Nazwa zdarzenia: np. scroll_depth (snake_case).
- Parametry: percent_scrolled (liczba), direction (down/up), content_id (opcjonalnie).
- Zakres stron: wszystkie, czy tylko blog/landing?
Zapisz te decyzje w krótkiej specyfikacji – ułatwi to utrzymanie i audyt.
Zgody i prywatność
Pamiętaj o RODO i zgodach. W GTM stosuj Consent Mode (analytics_storage). Zdarzenia zdarzenia przewijania to dane behawioralne, więc powinny respektować stan zgody. Jeżeli używasz CMP, skonfiguruj reguły „Fire only if consent = granted”.
Wydajność i jakość danych
Nie wywołuj zdarzeń przy każdym pikselu przewinięcia. Wysyłaj tylko przy osiąganiu progów i tylko raz na sesję strony (per próg). Zadbaj o wydajność: stosuj throttling/debouncing i lekką logikę warunkową. Ustal, jak obsłużysz dynamiczne wysokości (lazy-load, infinite scroll, akordeony).
Implementacja w Google Tag Manager + GA4 krok po kroku
Krok 1: Podstawy w GA4 i GTM
- Zainstaluj GTM na stronie (kontener web). Zweryfikuj w Podglądzie (Preview).
- W GTM dodaj tag „GA4 Configuration” z Measurement ID (G-XXXX). Włączodpowiednie ustawienia zgód.
- W GA4 włącz Rozszerzony Pomiar (opcjonalnie). Pamiętaj: domyślne „scroll” to 90% i nie zastąpi własnych progów.
Krok 2: Włącz zmienne przewijania
W GTM wejdź w Variables > Configure i zaznacz:
- Scroll Depth Threshold,
- Scroll Depth Units,
- Scroll Direction.
Te zmienne udostępni wyzwalacz przewijania.
Krok 3: Utwórz wyzwalacz Scroll Depth
- Trigger type: Scroll Depth.
- Vertical Scroll Depths: 25, 50, 75, 90, 100 (wartości oddzielone przecinkami).
- Enable this trigger on: All Pages (lub wg warunków, np. Page Path matches RegEx: ^/(blog|case-studies)/ ).
- Throttling: GTM sam wywoła zdarzenie dopiero na progu – to bezpieczne.
Wyzwalacz emituje event gtm.scrollDepth z wartościami w zmiennych.
Krok 4: Tag zdarzenia GA4
Dodaj tag typu „GA4 Event”:
- Event Name: scroll_depth.
- Event Parameters:
- percent_scrolled = {{Scroll Depth Threshold}}
- scroll_units = {{Scroll Depth Units}}
- direction = {{Scroll Direction}}
- page_location = {{Page URL}} (opcjonalnie, GA4 i tak go doda)
- Trigger: utworzony Scroll Depth.
Aby uniknąć duplikatów, nie dodawaj innych wyzwalaczy do tego taga. Jeśli wysyłasz do kilku strumieni, skonfiguruj „Send to server container” lub dodatkowe tagi GA4 z tą samą regułą.
Krok 5: Ograniczenie do jednorazowego wysłania progu
GTM z natury wywoła każdy próg tylko raz na „życie” strony, ale w SPA warto dodać filtr:
- Utwórz 5 zmiennych typu 1st Party Cookie lub Session Storage (np. sd_25, sd_50…).
- Dodaj warunek do taga: Fire gdy sd_{{threshold}} ≠ 1.
- Ustaw tag Custom HTML (po odpaleniu eventu) do zapisania sd_{{threshold}} = 1 w sessionStorage.
To zabezpiecza przed ponownymi strzałami po zmianie routingu lub komponentów.
Krok 6: Definicje niestandardowe w GA4
Aby raportować procenty w Explorations:
- GA4 > Admin > Custom definitions > Create custom dimension.
- Event scope, Name: Percent Scrolled, Event parameter: percent_scrolled.
- Analogicznie dla „direction”, jeśli potrzebujesz segmentacji po kierunku.
Po kilku godzinach parametry zaczną się pojawiać w raportach i w Eksploracjach.
Krok 7: Testy i weryfikacja
- GTM Preview: przewijaj stronę i obserwuj gtm.scrollDepth. Sprawdzaj, czy wartości 25/50/75/90/100 są trafione.
- GA4 DebugView: widoczne powinny być eventy scroll_depth z parametrami.
- Realtime > Events: upewnij się, że multiple odsłony nie duplikują zdarzeń.
W razie problemów sprawdź, czy któraś warstwa CSS (np. overflow w kontenerze) nie przechwytuje scrolla – wyzwalacz bazuje na dokumencie, nie na wewnętrznym skrolowanym divie.
Implementacja bez GTM: czysty JavaScript
Algorytm procentu przewinięcia
Podstawowy wzór: percent = round( (scrollTop / (scrollHeight – clientHeight)) * 100 ). Należy używać document.documentElement dla nowoczesnych przeglądarek. Uważaj na „overscroll bounce” w iOS – wartości mogą wyjść poza [0,100]. Warto zatem clampować wynik do 0–100 i emitować zdarzenia dopiero, gdy przekroczymy próg i nie został on jeszcze wysłany.
Przykładowy kod z throttlingiem
// Pseudokod JavaScript (umieść w tagu w sekcji HEAD lub ładowany asynchronicznie)
const sent = new Set();
const thresholds = [25,50,75,90,100];
let ticking = false;
function getPercent(){
const el = document.documentElement;
const scrollTop = (window.pageYOffset || el.scrollTop || 0);
const scrollHeight = el.scrollHeight;
const clientHeight = el.clientHeight;
const denom = Math.max(scrollHeight – clientHeight, 1);
const raw = Math.round((scrollTop / denom) * 100);
return Math.min(100, Math.max(0, raw));
}
function send(percent){
if (sent.has(percent)) return;
sent.add(percent);
window.dataLayerPYS = window.dataLayerPYS || [];
window.dataLayer.push({
event: 'scroll_depth’,
percent_scrolled: percent,
direction: 'down’
});
if (window.gtag) {
gtag(’event’,’scroll_depth’,{percent_scrolled: percent});
}
}
function onScroll(){
if (!ticking) {
ticking = true;
requestAnimationFrame(() => {
const p = getPercent();
thresholds.forEach(t => { if (p >= t) send(t); });
ticking = false;
});
}
}
window.addEventListener(’scroll’, onScroll, {passive:true});
window.addEventListener(’load’, onScroll);
Ten przykład wysyła zdarzenia do dataLayer i (jeśli dostępny) bezpośrednio do GA4 przez gtag(). Zadbaj, by nazwy eventów/parametrów pokrywały się z definicjami w raportach. W SPA opróżniaj Set() po zmianie trasy, jeśli traktujesz każdą trasę jak „nową stronę”.
Metoda IntersectionObserver i znaczniki progów
W złożonych layoutach (parallax, wewnętrzne skrolowane kontenery) rozważ IntersectionObserver. Tworzysz markery w dokumencie na wysokości progów i nasłuchujesz ich przecięcia z viewportem.
// Pseudokod tworzenia markerów i obserwacji
const el = document.documentElement;
const thresholds = [25,50,75,90,100];
const markers = [];
function placeMarkers(){
const h = el.scrollHeight – el.clientHeight;
markers.forEach(m => m.remove());
markers.length = 0;
thresholds.forEach(t => {
const m = document.createElement(’div’);
m.style.position=’absolute’;
m.style.top = Math.round(h * (t/100)) + 'px’;
m.style.width=’1px’; m.style.height=’1px’; m.style.pointerEvents=’none’;
m.dataset.threshold = t;
document.body.appendChild(m);
markers.push(m);
});
}
const sent = new Set();
const io = new IntersectionObserver(entries => {
entries.forEach(e => {
if (e.isIntersecting) {
const t = Number(e.target.dataset.threshold);
if (!sent.has(t)) { sent.add(t); gtag(’event’,’scroll_depth’,{percent_scrolled:t}); }
}
});
},{root:null, threshold:0});
placeMarkers(); markers.forEach(m => io.observe(m));
window.addEventListener(’resize’, debounce(placeMarkers, 300));
Ta metoda minimalizuje przeliczenia i dobrze radzi sobie z dynamicznym DOM (po dopracowaniu logiki aktualizacji). Pamiętaj, że absolutnie pozycjonowane markery powinny być potomkami dokumentu, który faktycznie się przewija.
Wysyłka do GA4 bez gtag – Measurement Protocol
Jeśli nie możesz użyć gtag() (np. środowisko niestandardowe), wyślij zdarzenie do GA4 Measurement Protocol (wymaga api_secret):
- Endpoint: https://www.google-analytics.com/mp/collect?measurement_id=G-XXXX&api_secret=YYYY
- Body JSON zawiera client_id i events[].
Pamiętaj o zgodach i o tym, że MP nie zasila raportu Realtime, jeśli nie dostarczysz poprawnego client_id i session_id.
Jakość danych, analiza i rozwiązywanie problemów
Typowe pułapki techniczne
- Różne wysokości dokumentu: lazy-load obrazów/komponentów zmienia scrollHeight; rozważ ponowną kalkulację progów po „content loaded”/„resize”.
- Kontenery z overflow: auto: w takim układzie zdarzenia dokumentu nie odzwierciedlają przewijania kontenera. Mierz przewinięcie konkretnego elementu (target = kontener) i wysyłaj osobne zdarzenia.
- Sticky header/footer: zawyżają lub zaniżają osiągalność 100%; praktycznie lepszy próg 90%.
- iOS overscroll/bounce: clampuj wynik do 0–100, stosuj requestAnimationFrame zamiast intensywnych handlerów.
- SPA: po zmianie trasy resetuj zestaw wysłanych progów i ponownie inicjalizuj obserwacje; w GTM użyj History Change Trigger.
Projektowanie progów: 25/50/75/90/100 czy inne?
Domyślne progi są dobre na start. Z czasem dopasuj je do długości treści: dla krótkich stron (do 2–3 ekranów) wystarczy 50/90/100; dla bardzo długich – dodaj 10/30/60/80. Ważniejsza niż liczba progów jest ich stabilność w czasie, aby móc porównywać serie.
Łączenie z konwersjami i segmentacją
W GA4 zbuduj Eksplorację typu Funnel lub Free Form:
- Segment użytkowników z percent_scrolled >= 75 i porównaj współczynnik konwersji z segmentem < 25.
- Oceń wpływ głębokości na kliknięcia w CTA umieszczone niżej.
- Wyznacz „sweet spot” długości – gdzie krzywa spadku zaangażowania jest najbardziej stroma.
Aby parametry były dostępne, pamiętaj o definicjach niestandardowych. Dla bardziej zaawansowanej analizy wyeksportuj zdarzenia do BigQuery.
Walidacja i sanity-check
- Rozkład: 25% powinno mieć więcej trafień niż 50%, a 50% więcej niż 75% itd. Jeśli jest odwrotnie – błąd implementacji.
- Różnice urządzeń: mobile zwykle osiąga niższe progi; jeśli jest identycznie jak desktop, sprawdź czy viewport jest mierzony poprawnie.
- Sesje 100% bez czasu: mogą wskazywać na auto-scrolling lub anchor link po wejściu – rozważ rozdzielenie zdarzenia „anchor_jump”.
Wielokrotne przewinięcia i kierunek
Dodanie parametru direction (down/up) pozwala odróżnić „pierwszy zjazd” od „przeglądania w górę”. Często interesuje nas tylko „down” – jeśli tak, filtruj zdarzenia w tagu lub w raporcie. Dla jakości danych nie wysyłaj up, jeśli próg down już został osiągnięty.
Makiety raportów i nazewnictwo
Spójne nazewnictwo przyspiesza pracę analityków:
- Nazwa eventu: scroll_depth (nie używaj spacji).
- Parametry: percent_scrolled (liczba), direction (string), content_group.
- Wymiary niestandardowe: jasne, opisowe nazwy (np. Depth Percent).
Dzięki temu Twoja analityka będzie jednolita w wielu projektach i narzędziach.
WordPress i gotowe wtyczki
W WordPress najprościej użyć GTM (wtyczki: GTM4WP) i skonfigurować wyzwalacz przewijania. Jeśli korzystasz z wtyczek „scroll depth”, sprawdź:
- czy wysyłają progi tylko raz,
- jakie nazwy eventów/parametrów stosują,
- czy działają poprawnie w lazy-load (np. Jetpack, optymalizatory obrazów).
Konsekwencja w nazewnictwie ułatwia łączenie danych między stronami.
Fallback i odporność
Warto przewidzieć scenariusze ograniczeń:
- Brak JS lub zablokowane skrypty – brak zdarzeń, zaplanuj minimalne KPI niezależne od JS.
- Adblock – korzystaj z własnego hostingu plików i serwera Tagowania (Server-Side), jeśli to kluczowe dane.
- Degradacja – jeśli nie zainicjuje się GTM/gtag, buforuj zdarzenia i wyślij po inicjalizacji (kolejka w local/sessionStorage).
Utrzymanie i wersjonowanie
Zmiany w konfiguracji trzymaj w changelogu kontenera GTM i w repozytorium (eksport JSON). Twórz środowiska (Dev/QA/Prod) i testuj na realnych długich stronach. Audytuj raz na kwartał, czy progi i nazewnictwo nie rozjechały się z praktyką zespołu contentowego.
Alternatywy i rozszerzenia
Poza procentami, możesz mierzyć wejścia sekcji:
- Dodaj data-attributes do nagłówków (data-section=”faq”) i wyślij event przy ich wejściu w viewport.
- Mierz widoczność kluczowych modułów (np. rekomendacje, formularz) przez IntersectionObserver.
- Połącz głębokość przewijania z odtwarzaniem wideo (czas vs. procent) dla pełniejszego obrazu atencji.
Takie podejście daje precyzyjniejszy kontekst niż same progi.
Uwagi końcowe o dokładności
Pamiętaj, że „głębokość przewijania” nie równa się „przeczytano”. Aby zbliżyć się do realnej atencji, połącz progi z minimalnym czasem spędzonym na stronie (np. engaged_time_msec) albo z aktywnością myszki/klawiatury. W GA4 możesz użyć metryki engaged sessions, ale najlepiej dodać własną logikę „aktywnych 10 s” przed uznaniem progu za „wartościowy”.
Podsumowując operacyjnie: wybierz stabilne progi, zaplanuj nazwy zdarzeń i parametrów, wdroż w GTM i GA4 lub przez JS, dopilnuj zgodności z RODO, a następnie regularnie weryfikuj rozkład i wpływ na konwersje. Konsekwentne mierzenie i iteracyjne poprawki szybko przełożą się na lepsze decyzje produktowe i biznesowe – bez zgadywania.