Jak mierzyć scroll depth

dowiedz się

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.

< Powrót

Zapisz się do newslettera


Zadzwoń Napisz