Markus Baersch

Analytics · Beratung · Lösungen

Start » Blog » Analytics

12.08.2023

Der Landingpage-Bericht in GA4 zeigt - ebenso wie beim Vorgänger - mitunter eine nennenswerte Anzahl an Sitzungen, die offenkundig ohne eine Landingpage begonnen haben. Der Wert ist in diesem Fall (not set). Und wie bei Universal ist der Grund offenbar ähnlich: Es geht um Sitzungen, die lt. Google Hilfe keinen Seitenaufruf (page_view) beinhalten, sondern nur andere Events. Aber: Warum passiert das eigentlich? Wie kommen Sitzungen ohne Landingpage zustande, obschon bei einer üblichen Implementierung sowohl Seitenaufruf als auch Enhanced Measurement Ereignisse vom "Konfigurationstag" bzw. dem ggf. direkt implementierten gtag.js Trackingcode übernommen werden? Und was hat es mit "Zombie-Sessions" auf sich?

Zombie Sessions in GA4 durch tote Browser-Reiter

Der Weg zu Antworten auf diese Fragen führt über Besonderheiten, die das Tracking für GA4 von der Vorgehensweise vieler anderer Tool unterscheidet.

Warum GA4 Tracking "anders" ist

Wer sich ein wenig mehr mit der Funktionsweise der Datenerhebung mittels gtag.js im Browser befasst, wird schnell einige Eigenheiten feststellen. Darunter diese beiden Aspekte:

  1. Der Browser bestimmt, ob eine Sitzung anfängt oder bereits beendet ist (andere Tools entscheiden dies i. d. R. auf der Empfängerseite). Dazu werden Cookies verwendet
  2. Statt der reinen Messung der Zeit zwischen zwei Events wird "Engagement" bei GA4 anders erhoben. Der Browser muss aktiv und im Vordergrund sein und es müssen Zeichen von "Nutzung" vorhanden sein wie Bewegungen der Maus, Interaktionen mit der Seite, Scrolling etc. Die ermittelte Zeit der Aktivität wird (wenn nennenswert) als Parameter eines "user_engagement" Events an GA4 gesendet, bevor die Seite verlassen wird, z. B. durch Navigation auf eine andere Seite über einen internen Link innerhalb einer Sitzung

Soweit, so gut. Das Zusammenspiel dieser beiden Besonderheiten aber begünstigt (leider) das Auftreten von Sitzungen, die keine Landingpage Dimension haben.

"Keine Seitenaufrufe" - stimmt das wirklich?

Prinzipiell spricht nichts dagegen, dass es Sessions gibt, die keine Seitenaufrufe beinhalten... bzw. zumindest solche, die nicht damit anfangen. Entgegen der üblichen Aussage, dass eine (not set) Landingpage nur dann zu sehen ist, wenn die ganze Sitzung frei von page_view Ereignissen ist, scheint es mir bei Analyse der Daten in GA4 nicht zwingend so auszusehen. Vielmehr mag es auch eingeschlafene Sessions geben, die (vermutlich) bereits einen internen Referrer aufweisen, aber nichts außer einem Seitenaufruf senden. Auch diese fallen dann in die Kategorie von Sitzungen, die keine Landingpage haben und eigentlich auch nicht gestartet wurden; ähnlich wie man es von Universal Analytics kennt. Solche Sitzungen scheinen aber danach keine Ereignisse mehr zu beinhalten. Anders kann ich diese Ansicht hier nicht erklären / deuten:

Pageviews ohne LP in GA4

Wenn hingegen in einer Sitzung auf der Landingpage kein Seitenaufruf vermessen wird, sondern per Navigation auf eine zweite Seite gewechselt wird, ist es offenbar irrelevant, ob auf der Einstiegsseite Ereignisse stattgefunden haben oder nicht. Ich habe beide Fälle getestet: Einstieg war in beiden Fällen die Startseite. Ein Link auf eine zweite Seite wurde mit einem Parameter "test=xxxx" versehen, um diese Aufrufe wiederzuerkennen. In beiden Fällen ist eine Sitzung entstanden, deren Landingpage (was falsch ist) der zweiten Seite entspricht... obschon im Testfall mit Events auf der Einstiegsseite durchaus sowohl die URL bekannt, als auch ein Sitzungsstart-Marker im Event zu finden war. Im Ergebnis bleibt die zweite Seite die offenkundige Einstiegsseite, wenn man auf die Daten beider Aufrufe der Test-URLs schaut - aber eben nicht "(not set)":

Ergebnisse der Test-Sessions

(Künstlich) wiedererwachtes Engagement

Üblicher (und ärgerlicher) ist aber ohnehin der Fall einer eingeschlafenen Session, die mit einem user_engagement, add_to_cart oder ähnlichen (z. B. E-Commerce) Events nach einer längeren Pause neu beginnt. Die Wiederaufnahme der Aktivität / Nutzung der Site führt dann zu einer neuen Sitzung eines bestehenden Clients.

Pageviews ohne LP in GA4

Aber: Sollte diese Session nicht trotzdem eine Landingpage haben? Ich finde schon (siehe unten). BTW: Wenn Du - z. B. aus Deinen BigQuery Daten - andere Ergebnisse hast, lass es mich wissen!

Wer sehen will, was in einer solchen Sitzung ohne Landingpage passiert, kann dies z. B. im Bericht zu Events erfahren, in dem ein Filter angewendet wird, der nur Ereignisse zeigt, die aus Sessions ohne Landingpage stammen. In der (von mir bevorzugten) englischen GA4 Oberfläche würde das so aussehen "Landing page + query string does not contain /"

Filter Definition in GA4

Wer mehr als nur ein paar click, user_engagement und session_start Events findet, kann zumindest davon ausgehen, dass es nicht nur Sitzungen gibt, die eigentlich überhaupt keinen Zweck erfüllen. Dennoch werden unnötige Sitzungen in jedem Fall dabei sein. Im Extremfall kann es so oder ähnlich aussehen (nur vermutlich mit größeren Zahlen als in meiner Test-Property):

Filter Events von LP freien Sessions

Wie sich hier zeigt, sind alle Sitzungen ohne eine Landingpage durch user_engagement Ereignisse entstanden, die gtag.js aus dem Browser einer bereits verstorbenen Sitzung hinterher sendet. Das session_start Ereignis hingegen ist kein separates Event, sondern entsteht nur durch entsprechende "Sitzungsstart-Marker", die einem anderen Event mitgegeben werden; ebenso wie ggf. hier zu findende first_visit Ereignisse, die dann entstehen, wenn nicht nur ein Sitzungsstart-Marker gesendet wurde, sondern gtag.js zudem keine bestehende Client ID in einem Cookie finden konnte und daher eine neue ID erzeugt hat. Sitzungen, die nur aus Events wie den o. g. bestehen, mag ich daher als "Zombie-Sessions" bezeichnen, denn es sind Auswirkungen von bereits "verstorbenen" Sitzungen.

"Zombie-Sessions"

Solche Sitzungen beginnen und enden zugleich i. d. R. mit einem Event, das eigentlich zu einer vorherigen Sitzung gehören. Neben einem Klick, der von der Site wegführt, sind es wie oben beschrieben vor allen Dingen Mess-Ereignisse für eine gemessene Engagement-Dauer auf der aktuellen Seite (gleich der letzten Seite der vorherigen Session). Diese entstehen in heutigen Browsern vor allem dann, wenn ein Tab (oder ggf. auch der Browser selbst) geschlossen wird. Was freilich nicht unüblich ist, denn wenn mehrere Reiter gleichzeitig offen sind und "bearbeitet" werden, kommt i. d. R. irgendwann der Zeitpunkt, zu dem ein Reiter - oder der ganze Browser - geschlossen wird.

Ist seit dem letzten Event der vorherigen Sitzung mehr Zeit vergangen, als in GA4 als Timeout für eine Sitzung definiert ist (Standard sind 30 Minuten), bringt das "Ausreißer-Ereignis" der alten Sitzung einen Marker mit, der eine neue Sitzung beginnt. Zumindest wenn der jeweilige Browser das Event wirklich noch versendet: Es gibt beim Schließen von Tab vs. Browser offenkundig durchaus Unterschiede, ob das "onunload" Event der jeweiligen Seiten noch ausgeführt wird (und ob dadurch noch Requests versendet werden dürfen oder nicht). Das Problem ist aber nicht auf einzelne Browser, Plattformen oder Geräte begrenzt. Sowohl Desktop-Browser als auch Mobilgeräte sind i. d. R. als Quelle solcher Sessions auszumachen; Safari, Chrome, Edge... egal.

Hier sieht man ein Beispiel einer Test-Session im DebugView, die aus 19 Events inkl. Conversions besteht und anschließend aus Besuchersicht schlichtweg "beendet" war, weil das Kontaktformular abgesendet wurde. Nach mehr als 30 Minuten Inaktivität (z. B. Arbeiten in einem anderen Tab) werden alle noch offenen und inaktiven Tabs geschlossen. Dabei sendet Chrome noch beim "Entladen" der Seite schnell das Engagement-Event raus und als Ergebnis entsteht eine (ungewollte) neue Session:

Neue Session im DebugView

Da der Reiter gerade erst geschlossen wurde, ist es unwahrscheinlich, dass hier nun weitere Aktivität gemessen wird - die Sitzung besteht daher nur aus diesem einen "echten" Event, ddem angeblich vorher eine ganze Menge an Aktivität vorausgegangen ist (die gemessene Engagement Time), aber dennoch den Start der Sitzung markiert. Oder kurz: Reiner Unfug 🙁

Muss das so sein?

Natürlich nicht. Erstens hat jedes Event bei GA4 eine page_location, in der die URL der Seite steckt, auf der das Event ausgelöst wurde. Also ist stets klar, auf welcher Seite das Ereignis stattgefunden hat. Daraus könnte eine "Landingpage" für die neu entstandene Sitzung bedient werden. Schlussendlich sollen alle Events in GA4 mehr oder weniger gleichwertig sein und ein Seitenaufruf ist - anders als es bei Universal Analytics war - ein Event wie jedes andere.

Zweitens - und meines Erachtens viel wichtiger - sollte sich gtag.js bei all der Verantwortung, die durch die Verwaltung von Sessions und den Versand von Engagement-Events im Browser liegt, mehr Mühe geben, diesen Zustand zu vermeiden. Es wäre einfach, auf den Versand eines user_engagement zu unterbinden, wenn man doch selbst einfach bestimmen kann, ob die dazu gehörende Sitzung überhaupt noch lebt! Ein user_engagement Event zu senden und zugleich mit einem Session-Start-Marker zu versehen, so dass eine neue Sitzung entsteht, ist schlichtweg Unsinn, denn es gehört ja per Definition zur schon abgelaufenen Sitzung.

Daher sollte zumindest dieses Event im Browser selbst unterbunden werden. Solange das nicht passiert, bleibt als Lösung für sauberere Daten (leider) nur die Kontrolle an einem eigenen Endpunkt (siehe unten).

Optionen für client-Side GTM

Bei allen selbst gesendeten Events, die auf Timern, Sichtbarkeit oder Besucheraktionen deutlich nach einem Ladevorgang stattfinden können, ist ein Unterbinden von Events nach Ablauf einer Session eine gute Option, wenn Daten wie diese hier verhindert werden sollen.

Blockierende Trigger

Wer dazu z. B. blockierende Trigger auf Basis der seit dem letzten Event vergangenen Zeit umsetzen möchte, kann die Zeit in Sekunden, die seit dem letzten Ereignis vergangen ist, auf Basis des "GA4-Datenstrom-Sitzungs-Cookies" ermitteln. Dieses Cookie trägt den Namen _ga_xxxxx, wobei xxxxx für die Measurement ID steht des Datenstroms steht, dessen Sitzung darüber kontrolliert wird. Im Wert dieses Cookies stecken unter anderem die Session ID, die Session Nummer und auch der Zeitstempel des letzten Events. Mit dem folgenden Code kann der Zeitstempel ausgelesen und die verstrichene Zeit in Sekunden in einer Benutzerdefinierten JavaScript-Variable im Tag Manager ermittelt werden:

function(){
  var c = {{GA4 Session Cookie}};
  if (!c) return 0;
  var ts = c.split(".")[5];
  if (!ts) return 0;
  return Math.round(Math.round(Date.now() / 1000) - ts);
}

Dabei wird davon ausgegangen, dass es eine First-Party-Cookie Variable namens "GA4 Session Cookie" gibt, die den Wert des o. a. Cookies beinhaltet. Wer lieber mit Variablen-Templates arbeitet (oder es muss, weil die eigene CSP keine Ausführung von JS Variablen erlaubt), findet ein entsprechendes Template auf GitHub. Das Template ist allerdings (noch) nicht Teil der Gallery, also muss es einstweilen manuell importiert werden.

Die Arbeit mag sich durchaus lohnen, wenn man eine nennenswerte Anzahl an Zombie-Sessions findet. Die folgende Abbildung zeigt dazu exemplarisch eine Vielfalt an möglichen Ereignissen, die eine solche Session erzeugen können und demonstriert, dass faktisch jeder Browser betroffen ist.

Events von LP freien Sessions - teils selbst gemacht

Allerdings sollte man hier nicht einfach "alles" ausschließen, denn wie oben gezeigt ist eine Wiederaufnahme einer Session nicht bei jedem Event gleich "ärgerlich" und es gibt valide Gründe, warum eine eingeschlafene Sitzung einen Nachfolger haben kann. Wie man in der obigen Abbildung sehen kann, können es auch ("engagementbasierte") Zielgruppen-Trigger-Ereignisse sein, die dank erreichtem Schwellwert nach Ende der eingeschlafenen Sitzung als Teil einer Zombie-Session vorkommen (Danke an Adrian Grigore für den Hinweis auf LinkedIn!). Hier sind es "engaged_user" Ereignisse. Ob die durch dieses Event markierten Cookies wirklich auf die Liste gehören, nur weil nach Stunden ein Tab geschlossen wurde?

Das Problem ist auch in der Konfiguration des Datenstreams zu beeinflussen. Oder besser: zu minimieren:

Anpassung der Session-Dauer

Die Einstellungen zum Datenstream erlauben es, den Session-Timeout von 30 Minuten anzuheben bis auf knapp 8 Stunden. Das ist freilich nicht die "Lösung für alles". Aber wenn auf der eigenen Website längere Pausen zwischen einzelnen Schritten (wie bei komplexen Formularen etc.) nicht unüblich sind, müssen die 30 Minuten nicht der beste Wert sein. Analysen der schon bestehenden Daten helfen, einen geeigneten Wert zu finden.

Lösungen am eigenen Endpunkt

Dummerweise ist das Zurückhalten solcher Events am eigenen Endpunkt oder Proxy (ohne Patching von gtag.js oder der Funktion, die zum Versand des Events verwendet wird) aktuell die einzige Lösung, die mir einfällt, wenn man auch die Engagement Ereignisse in den Griff bekommen will. Dazu kann man z. B. in einem server-side GTM durch entsprechende Trigger dafür sorgen, dass user_engagement, scroll oder ggf. auch ein click mit einem externen Link als Ziel und einem Sitzungsstart-Marker blockiert werden. Verzichtet man auf Enhanced Measurement und nimmt sämtliche Events z. B. im Tag Manager selbst in die Hand, kann man dieses Problem auch client-seitig in gewissem Umfang kontrollieren... aber die Messung des Engagements ist ausschließlich eine Angelegenheit von gtag.js und damit auch voll in der Verantwortung von Google. Leider.

Zudem kann es schädlich für die Datenqualität ausfallen, wenn man wiederaufgenommenen Sessions bei zu vielen Events den Sitzungsstart-Marker vorenthält, weil das entsprechende Event am Server hängen geblieben ist. Komplette serverseitige Sitzungskontrolle als Ersatz ist wiederum keine triviale Alternative (aber machbar).

Hast Du eine andere Idee? Dann lass uns diskutieren - per Mail, auf LinkedIn oder DM auf Twitter X.

Hat Dir der Beitrag geholfen?

Dann freue ich mich, wenn Du ihn mit anderen teilst! Wenn Du magst, gib einen aus ;)

© 2001 - 2024 Markus Baersch