Start » Blog » Analytics
08.08.2026

Generische Ereignisse per Datenschicht oder DOM definieren - Vorteile, Nachteile und Tipps

Sobald eine Website mehr als nur Seitenaufrufe und automatisch erfasste Ereignisse vermessen will, muss ein Konzept her, wie diese zusätzlichen Ereignisse entstehen sollen. Individuelle Setups über Trigger im Tag Manager können dabei sehr unterschiedlich ausfallen und mal mehr, mal weniger robust sein. Zahlreiche Klick-Trigger mit komplexen CSS Selektoren etc. auf der einen Seite, generische "alles via dataLayer" - Events auf der anderen sind die beiden Extreme. Und vor allem der Weg über den dataLayer beinhaltet u. U. Ereignisse, die "per Wildcard" vom Setup im GTM aufgenommen und 1:1 an Google Analytics & Co. weitergegeben werden. Das ist praktisch und theoretisch "sparsam" im Tagging. Die Kosten können diesen Vorteil leider schnell auffressen. Dieser Beitrag beschreibt ein paar typische Ansätze zur Umsetzung, welche Probleme dabei auftreten und wie man einen gesunden Mittelweg finden kann.

"Generische Ereignisse" - was ist damit gemeint?

So generisch wie die Bezeichnung selbst ist, braucht sie vermutlich ein Minimum an Erklärung: "Genersich" ist hier im Sinne der Informatik gemeint und beschreibt ein Tagging Setup, bei dem eine Vielzahl an Events über den gleichen Weg erstellt und verarbeitet werden. Ein einfaches Beispiel:

  • Alle Ereignisse werden mit einem stets gemeinsamen Ereignisnamen wie z. B. ui_event in die Datenschicht geschrieben. Dabei existiert entweder ein kontrolliertes und überschaubares Set an allgemeinverwendbaren Eigenschaften, die verwendet werden, um mehr Infos zum Ereignis - und den Ereignisnamen (für Google Analytics oder andere Dienste) zu kommunizieren... oder es gibt individuelle Eigenschaften je Ereignistyp. Klick Ereignisse haben dann z. B. link_url, link_text etc., Formularereignisse Properties wie form_id, form_element, form_step o. Ä.
  • Im Tag Manager existiert ein Trigger, der auf diesen stets gleichen Event-Schlüssel reagiert. Damit wird ein einziges Tag je Dienst (wie Google Analytics) gefeuert, über das der Ereignisname und alle Eigenschaften aus dem dataLayer per Variablen entnommen und dem Ereignis hinzugefügt werden. Das können Ereignisparameter oder Nutzereigenschaften sein.

Mit einem solchen Setup können sämtliche Interaktionen und gewünschte Messpunkte komplett über den dataLayer definiert werden. Der Tag Manager ist hier nur noch bedingt in einer kontrollierenden Rolle tätig, sondern übernimmt die Daten (meistens) ungeprüft aus dem dataLayer und sendet diese, wenn das Tag entsprechende Zustimmung hat (oder nicht benötigt).

Am Ruder sitzt in diesem Fall - wieder - "die IT". Meint: Anpassungen im Tagging sind Aufgabe der Website, nicht des Tag Managers. Damit gibt es nur noch wenig Unterschiede zu einer direkten Implementierung des Taggings ohne Tag Manager. Wir brauchen ein Ereignis? Dann schreiben wir es in den dataLayer und lassen es entstehen. Das hat u. U. Konsequenzen.

Varianten der dataLayer Option

Auch ohne Nutzung des dataLayers als direkte Quelle von Ereignissen können ähnliche Ergebnisse erzielt werden, wenn z. B. passende data-Attribute direkt im DOM der Seiten verwendet werden. Der Google Tag Manager bietet direkten Zugriff auf diese Attribute und mit wenig JavaScript und ein paar Variablen kann das gleiche Ergebnis erzielt werden. Attribute können steuern, welche Akton (zum Beispiel Klick vs. Sichtbarkeit) das Ereignis auslösen soll, wie es benannt ist und welche Eigenschaften es haben sollte... also der gesamte Kontext des Events; ebenso wie bei Nutzung des dataLayers.

Ein Beispiel, das dieses System besonders gut unterstützt und aus diesen Attributen fertige Events entstehen lässt und entweder selbst versendet oder über den dataLayer wiederum einem Tag Manager zur Verfügung stellen kann, ist der hier im Blog schon mehrfach angesprochene "walker.js", der Data Capturing Komponente von walkerOS. Das Prinzip kann dazu verwendet werden, ebenfalls Ereignisse über den o. a. generischen Weg zu den Empfängern zu transportieren, auch wenn das nicht wirklich der Zweck dieses Systems ist.

Beispiele für generische dataLayer Pushes

Anhand der folgenden dataLayer Ereignisse soll das Prinzip verdeutlicht werden. In einem theoretischen Szenario werden diese in der hier gezeigten Reihenfolge ausgelöst, indem eine Frage in einem FAQ geöffnet, ein CTA Element (ohne zu reagieren) gesehen und dann auf der Seite ein externer Link geklickt wird. Zuerst der Klick im FAQ-Accordion, um die Anteort einzublenden:

window.dataLayer.push({
  event: "ui_event",
  ui_event_name: "accordion_click",
  accordion_type: "FAQ",
  accordion_reference: "Q: How much is the fish?",
  click_id: "acc-s5",
  click_classes: "faq-q accordion acc_closed",
  click_text: "Q: How much is the fish?",
  component: "accv2"
})

Bei der Sichtung der Antwort wird ein CTA Element eingeblendet, das ebenfalls vermessen werden soll:

window.dataLayer.push({
  event: "ui_event",
  ui_event_name: "cta_visible",
  cta_type: "Button",
  cta_text: "Learn more",
  cta_target: "Article|How generic events stack up",
  cta_target_url: "https://www.example.com/blog/how-generic-events-stack-up/",
  cta_position: "intext50",
})

Abschließend wird die Seite verlassen, indem ein externer Link geklickt wird:

window.dataLayer.push({
  event: "ui_event",
  ui_event_name: "external_link_click",
  click_classes: "extLnk",
  click_text: "Blogpost",
  click_url: "https://some-random-doma.in/blog/foo/",
})

Um alle drei Ereignisse mit einem gemeinsamen Trigger für das Benutzerdefinierte Ereignis ui-event und einem einzigen Tag an Google Analytics zu senden, sähe dieses in etwa so aus:

Generisches GA4 Tag für Ereignisse per dataLayer

In diesem Tag werden alle möglichen Eigenschaften, die das Tag besitzt, manuell als Ereignisparameter gleichen Namens gesetzt, indem die entsprechenden Werte per Datenschichtvariable für die gleichnamigen Keys aus dem Push genutzt werden. Der Name des Ereignisses selbst kommt auf gleichem Weg zustande. Die Datenschicht kontrolliert auf diese Weise sowohl den Namen als auch alle Parameter. Das muss hier einzeln geschehen, weil es (leider) keine Möglichkeit gibt, ein Array aus Key/Value-Paaren direkt als Ereignisparameter zu mappen, ohne dabei auf das Standard GA4 Tag zu verzichten (dazu gleich mehr).

Schaut man sich die ausgehenden Requests an, sieht auf den ersten Blick zunächst alles gut aus: Die Events verlassen den Browser, alle haben den korrekten Ereignisnamen und die Parameter scheinen anwesend.

Vom generisches GA4 Tag gesendete Ereignisse im Tracking Auditor

Betrachtet man allerdings die Details - z. B. wie hier im Tracking Auditor -, ist bei den Parametern doch einiges im Argen, wenn man normale Datenschicht-Variablen verwendet hat, um auf die Werte zuzugreifen. Die Anzahl der Parameter, die die Karten z. B. als "EP x14" - Pill beim external_link_click anzeigen, sind ein erster Indikator. Das accordion_click Ereignis ist als erstes gesendet worden, also lauern hier noch keine Überraschungen. Aber:

Das cta_visible Ereignis besitzt nun ebenso die Eigenschaften des Accordion-Events, denn diese stehen nach wie vor in der Datenschicht und werden daher erneut zugeordnet.

Parameter der Ereignisse werden gemischt

Das mag vielleicht nicht stören, solange bei Auswertungen von CTA Einblendungen nicht auf "Akkordion Eigenschaften" geschaut wird, aber so oder so sind die Daten falsch. In GA4 und daher ggf. zusätzlich in BigQuery. Oder anderen Empfängern, die mit den gleichen Daten auf ähnliche Weise gefüttert werden.

Der external_link_click hat folgrrichtig das gleiche Problem. Besonders ärgerlich hier: Der geklickte Link selbst hatte keine ID. Stattdessen wird hier daher ebenso die ID des Accordion Links verwendet. Spätestens jetzt kommt es zu verwirrenden Ergebnissen, wenn man ausgehende Klicks anhand der Link IDs untersuchen will.

Vermischte Parameter sorgen für eine falsche Klick ID bei einem Klick-Ereignis

Ein solches Konstrukt ist daher vor allem anderen ziemlich fehleranfällig, wenn es um die Auswertung der Daten geht. Dennoch sieht man solche Konstruktionen in vielen GTM Containern.

Typische Herausforderungen und Lösungen

Ein weitere Problem sind die zahlreichen Parameter, die hier verwendet werden sollen. Spätestens bei weiteren Ereignistypen, die ebenfalls alle ihre eigenen Parameternamen mitbringen, wird das Ganze sehr unübersichtlich. Solange die Registrierung von Dimensionen in GA4 das zulässt - oder noch mehr bei Nutzung von BigQuery - könnten hier sonst immer weitere Parameter hinzukommen und mit vorhandenen Standard-Parametern wie den Eigenschaften eines Links / Klicks gemischt werden.

Die erste sinnvolle Maßnahme zur Reduktion ist daher die Verwendung von allgemeineren Bezeichnungen, die je nach Kontext unterschiedliche Werte enthalten. Statt eines cta_type, accordion_type, form_type, link_type und weiteren Dimensionen, die alle eigentlich die gleiche Aufgabe haben, ist ein gemeinsamer "element_type" sinnvoll zur Reduktion der Komplexität und Anzahl der erforderlichen Variablen zur Unterhaltung des generischen Event-Tags.

Data-Attribute im Vorteil?

Spätestens bei Verwendung von data-Attributen statt der Datenschicht ist das vermutlich schon aus Faulheit der bessere Weg. Zudem haben data-Attribute, die man explizit aus dem DOM und der Umgebung des Elements entnimmt, das vermessen wird, nicht das oben gezeigte Problem von Parameterwerten, die in der Datenschicht von einem Ereignis zum nächsten überdauern. Dabei wird z. B. bei einem Link per Attribut data-gtm-event-name ein Ereignisname vorgegeben. Mit weiteren Attributen können Trigger (Klick vs. Visibility) oder Parameter (entweder einzeln oder als Liste) definiert und im Tag Manager ausgelesen werden. Ein Beispiel:

<a href="/foo/" class="nvlnk" data-gtm-event-name="navigation_click" data-gtm-event-category="Main Menu">Ankertext</a>

Um nun ein Attribut wie den Namen auszulesen, reicht der Standardumfang des Tag Managers. Eine "Auto Event Variable" kann Attribute lesen.

Data Attribute auslesen und nutzen

Damit lässt sich ein Trigger erzeugen, der immer dann feuert, wenn ein solcher Name belegt ist (ggf. kombiniert mit weiteren Attributen) und die Information in das Tag als Ereignisnamen befördern. Auf gleichem Weg lassen sich individuelle Parameter auslesen und verwenden. Je nach Gestaltung des DOM kann das Auslesen erfordern, dass man sich in einer JS Variable vom aktuell geklickten Element auf- oder abwärts auf die Suche nach einem data-Attribut machen muss, aber es ist lösbar, ohne dass ein Ereignis mit "Altwerten" belastet wird.

Will man also dem obigen Problem von veralteten Werten im dataLayer begegnen, statt mit data-Attributen zu arbeiten, muss eine Lösung her, die die verwendeten Parameterwerte auf den aktuellen Push in den dataLayer reduziert.

Handling von Datenschicht-Parameterwerten

Ein denkbarer Ansatz ist es, die Parameter als Array mittels einer benutzerdefinierten JavaScript Variable selbst "kuratiert" und passend zum aktuellen Eventnamen zusammenzustellen und nur die Parameter zu nutzen, die zum Event passen. Dadurch werden nicht nur die Werte bestimmt, sondern ein gewisses "Schema" durchgesetzt, das zu den dataLayer Pushes passt und mit dem Umfang der Ereignisse abgestimmt ist. Diese kann man dann entweder in einem Benutzerdefinierten HTML Tag selbst per gtag() absetzen oder auf ein alternatives Template wie z. B. "GA4 Unified Tag for Webview (Web & App) | Commands Tag" zurückgreifen.

Das erfordert allerdings eine Abstimmung des Schemas mit jedem neuen Event (statt nur Hinzufügen neuer Parameter-Keys, wenn diese erstmals verwendet werden) und der Verzicht auf das eingebaute GA4 Tag zu Gunsten von HTML oder einem eher schwergewichtigen Template, nur weil dort ein Array genutzt werden kann, statt einzelner Parameter, ist kein guter Deal. Daher sind andere Lösungen zu bevorzugen.

Um nur Werte aus dem dataLayer zu erhalten, die mit dem derzeitigen Push entstanden sind und alle anderen zu ignorieren, gibt es ebenfalls ein Custom Template: den "Data Layer Picker" von Simo Ahava. Er erlaubt den Zugriff auf das komplette aktuelle Objekt, das gepushed wurde - oder einzelne Keys daraus.

Data Layer Picker zum Zugriff auf Eigenschaften des aktuellen Pushes

Auf diese Weise statt mit Standard-Datenschicht-Variablen ausgelesen, erhält das generische Event nur die Eigenschaften, die gesendet werden sollen. Veraltete Werte aus vorherigen Ereignissen werden ignoriert. Einen Haken hat die Sache allerdings: Damit der Zugriff funktioniert, muss die Variable den ganzen dataLayer lesen und den passenden Push "heraussuchen" und daraus die geforderte Eigenschaft entnehmen. Das kann eine sehr große Menge an Daten und Ereignissen sein. Das bedeutet nicht, dass man dadurch einen Performanceverlust im Browser spüren muss, aber die Belastung ist real und in einer Single Page Application häufen sich die Daten schnell an. E-Commerce Ereignisse wie view_item_list & Co. beim Stöbern in einem Shop können der Variable eine Menge zu tun geben, wenn 20 Eigenschaften aus dem dataLayer geholt werden müssen - nacheinander.

Ein viel einfacherer Weg beginnt bereits da, wo die Events in die Datenschicht gelangen. Der Ansatz hierbei erfordert zwei Änderungen an der Art und Weise, wie solche Events dort abgelegt werden und beide sind inspiriert vom E-Commerce-Tracking für GA4:

  • Alle Ereignisparameter wandern aus dem "Root" des Objekts in einen gemeinsamen Schlüssel wie ui_event_properties und werden dort als Keys und Values gehalten
  • Der Schlüssel wird vor jedem neuen Push mit einem Reset versehen, so dass keine Werte aus vorherigen Ereignissen dort überleben können.

Im E-Commerce ist dieser gemeinsame Schlüssel das ecommerce Objekt, welches im Idealfall durch einen ecommerce: null Push zurückgesetzt wird, bevor das neue Event entsteht und einen neuen "ecommerce Zweig" mitbringt. Das mittlere Event aus der obigen Beispielsequenz würde dann so aussehen:

window.dataLayer.push({ui_event_properties: null});
window.dataLayer.push({
  event: "ui_event",
  ui_event_name: "cta_visible",
  ui_event_properties: { 
    cta_type: "Button",
    cta_text: "Learn more",
    cta_target: "Article|How generic events stack up",
    cta_target_url: "https://www.example.com/blog/how-generic-events-stack-up/",
    cta_position: "intext50"
  }
})

Wenn man in diesem Fall auf eine der Eigenschaften - nun z. B. über ui_event_properties.cta_target statt wie vorher cta_target zugegriffen wird, ist nur dann ein Wert vorhanden, wenn im aktuellen Ereignis ein solcher spezifiziert wurde. Es erfordert keinerlei Custom Templates; der Job kann von einer normalen Datenschicht-Variable gemacht werden.

Wildwuchs und Kontrollverlust

Mit dieser Maßnahme allein ist das generische Event allerdings nicht dagegen immun, unnötig viele Parameter zu transportieren - dazu muss nach wie vor Disziplin bei der Bestückung des dataLayers herhalten (oder die Gestaltung von data-Attributen, wenn dieser Weg verwendet wird). Außerdem hat hier nach wie vor "die Website" die Kontrolle darüber, wie viele Ereignisse entstehen und wie viele Varianten es davon gibt.

Ein neuer Eventname ist auf diese Weise schnell erstellt und daher ist eine weitere Herausforderung der Umfang. Damit ist sowohl das Volumen der einzelnen Ereignisse gemeint, als auch deren Vielfalt. Statt in bestehenden Ereignissen nach passenden Kandidaten zu suchen, entstehen daher in der Praxis schnell verschiedene Varianten des gleichen Ereignisses. Auf der Startseite heißt es "cta_click", im Blog "site_link_click" und auf der neuen Landingpage hat jemand einen "cta_link_click" verbaut. Irgendwo gibt es das Ganze dann noch mit einem "klick" statt "click"... und die Parametersätze zeigen ggf. ebenfalls Abweichungen.

Während neue Parameter zumindest im GTM "angemeldet" werden müssen, um vom generischen Tag übergeben zu werden, ist der Eventname - und damit zumindest die Vielfalt - erst dann zu kontrollieren, wenn man beim Trigger mit einer Whitelist arbeitet, statt jedes ui_event zu übergeben. Diese kann z. B. gezielt nur bekannte und gewünschte Ereignisse per ui_event_name abdecken und alle unbekannten ignorieren. Ob das in Form einzelner Trigger geschieht oder der eine allgemeine Trigger eine (umfangreiche) Regex-Zusatzbedigung erhält, ist dann nur noch Geschmackssache. Beides erlaubt es, ein gewisses Maß an Kontrolle zurück zu erhalten und zwingt neue Events in einen Prozess, der eine neue Fassung des Containers erfordert. Was in 99% der Fälle eine gute Sache ist und kein Hindernis, sobald mehrere Personen in Gestaltung des dataLayers und Tagging involviert sind.

Empfehlungen

Assets in einem Tag Manager zu sparen, ist primär eine gute Idee. Wenn es das eigene System hergibt, sinnvolle Ereignisse über DOM oder Datenschicht triggerbar zu gestalten und mit Eigenschaften zu versehen, kann das gerade bei eher umfangreichem Tagging ein echter Vorteil sein. Dass dadurch die Performance nicht zwingend steigt, muss in Betracht gezogen werden. Daher:

  • Eine Lösung, die über die Datenschicht funktioniert, sollte idealerweise mit dem demonstrierten Reset arbeiten, um saubere Daten ohne falsche Werte zu erzeugen.
  • Parameterlisten sollten reduziert und mit möglichst allgemeingültigen Dimensionsnamen arbeiten
  • Eine Whitelist beim Trigger kann dazu dienen, neue Events durch einen Prozess zu schicken, statt unkontrolliert durch den Tag Manager in die Zielsysteme laufen zu können

Unter diesen Bedingungen bin ich ein Fan von generischen Ereignissen. Leider erfordert dies allerdings oft eine Anpassung bereits bestehender Konzepte. Da diese ohnehin gern noch aus Universal Analytics Zeiten stammen, kann bei der Planung einer Neugestaltung auch gleich alles richtig gemacht werden. Diesmal jedenfalls 😉

War der Beitrag hilfreich?

Dann freue ich mich, wenn er mit anderen geteilt wird!

Ko-fi Einen Tee ausgeben ;)