Das Formular ist raus, die Bestätigungsmail liegt im Postfach, und im Tag Manager: Stille. Kein Ereignis, kein Tag, keine Conversion. Wer jetzt wahllos an Trigger-Einstellungen dreht, verliert schnell einen halben Tag. Denn das Problem sitzt fast nie im GTM. Es sitzt im JavaScript der Seite.
Diese Seite gehört zur Fehler-Serie: geprüft wird in der Reihenfolge der Häufigkeit. Und die führt fast immer zum Formular-Trigger auf WordPress.
Zwei Minuten Grundcheck, bevor du gräbst
Öffne den Vorschaumodus und lade die Seite neu. Drei Ereignisse müssen immer in der linken Spalte stehen: Container Loaded, DOM Ready, Window Loaded. Fehlen sie, hat irgendein Skript den dataLayer neu zugewiesen statt zu pushen (meist ein kopiertes window.dataLayer = [...]). Damit sind alle automatischen Trigger tot, obwohl der Container brav lädt.
Stehen die drei da, schau beim Absenden auf die Liste. Kein Ereignis: Die Seite verschluckt es. Ereignis da, Trigger springt nicht an: Bedingungen prüfen, „enthält“ gegen „ist gleich“, Groß- und Kleinschreibung. Trigger springt an, Tag schweigt: Ausnahme.
Der Klassiker: Formular-Trigger auf WordPress
Warum sterben ausgerechnet Formular-Trigger so oft? Weil GTM anders lauscht, als die meisten denken: nicht mit einem Listener an jedem Element, sondern mit einem einzigen ganz oben am Dokument. Das ist sparsam und erfasst auch nachgeladene Elemente. Die Bedingung dabei: Das Submit-Ereignis entsteht unten am Formular und muss durch alle Elternelemente nach oben durchgereicht werden, bis es dort ankommt. Bubbling heißt das im Browser.
Und genau da grätschen Formular-Plugins rein. Viele validieren per JavaScript und stoppen das Ereignis danach: mal per stopPropagation, mal mit dem jQuery-Klassiker return false, der preventDefault und stopPropagation in einem Befehl vereint. Das Ereignis stirbt auf halber Höhe, GTM hört nichts. Variante zwei sind Ajax-Formulare: Sie senden beim Buttonklick per Skript, ein echtes Submit-Ereignis entsteht nie.
Daher das typische Bild: Formular funktioniert, Mail kommt an, Trigger schweigt. Das Formular hatte nie ein Problem. Nur die Nachricht nach oben wurde gekappt.
Der Capture-Workaround: Pflaster, kein Fix
Ereignisse laufen zweimal durch die Seite: von oben nach unten (Capture-Phase), dann wieder hinauf (Bubbling). Gestoppt wird fast immer nur der Rückweg. Ein Capture-Listener sieht das Ereignis auf dem Hinweg, bevor das Plugin es abwürgt. Im GTM nutzt der Trigger „Alle Elemente“ diese Phase (eigene Listener: drittes Argument true).
Warum trotzdem nur Pflaster? Du misst den Versuch, nicht den Erfolg: Auch das Submit mit leerem Pflichtfeld läuft durch die Capture-Phase. Beim Ajax-Formular hilft Capture gar nicht, es gibt ja kein Ereignis. Und „Alle Elemente“ kann nicht auf Tags warten; leitet die Seite sofort weiter, ist der Request weg.
Der Königsweg: ein eigenes dataLayer-Event
Die dauerhafte Lösung: Das Plugin oder der Entwickler meldet den Erfolg selbst, eine Zeile im Erfolgs-Callback, erst wenn die Sendung wirklich durch ist: dataLayer.push({event: "formular_gesendet"}). Im GTM ein Custom-Event-Trigger darauf, fertig.
Warum Königsweg? Du misst den Erfolg statt des Versuchs, und das Event hängt nicht am Markup, es übersteht jedes Redesign. Viele Formular-Plugins bringen dafür längst eine Einstellung oder einen Hook mit (oft keine Viertelstunde Arbeit). Ja, du musst dafür einmal mit dem Entwickler oder der Plugin-Doku reden. Das ist der ganze Preis.
Zwei Regeln dabei: immer pushen, nie neu zuweisen, sonst bricht der Container still. Und immer mit event-Schlüssel, denn nur der löst Trigger aus. Wie ein Container von Anfang an auf solchen Events aufbaut, steht in der Anleitung Google Tag Manager einrichten.
Zwei stille Killer: Ausnahmen und Selektoren
Springt der Trigger in der Vorschau an und der Tag feuert trotzdem nicht, lies den Ausnahmen-Block des Tags. Eine Ausnahme gewinnt immer gegen den auslösenden Trigger, und sie meldet sich nirgends. Gern übersehen: eine alte Blockier-Ausnahme auf einen Seitenpfad, der seit dem Relaunch anders heißt.
Der zweite Killer: Trigger an CSS-Selektoren und Klassennamen. „Klick auf .btn-primary“ funktioniert genau bis zum nächsten Theme-Update. Dann heißt der Button anders, der Trigger ist tot, und nichts wird rot. Solche Trigger haben ein Verfallsdatum, es steht nur nirgends drauf. Auch hier ist die Antwort das dataLayer-Event von oben.
„Gefeuert“ heißt nur: GTM hat es versucht
Der letzte Stolperstein ist die Vorschau selbst. „Tag fired“ heißt: Der Container hat den Tag ausgeführt. Ob der Request die Seite je verlassen hat, zeigt nur der Netzwerk-Tab der Entwicklertools: Filter auf „collect“ oder den Endpunkt deines Zielsystems, absenden, Request suchen. Fehlt er, war meist ein Blocker schneller oder eine Weiterleitung dazwischen.
Merk dir die drei Wahrheiten: Vorschau (was im Container ankommt), Netzwerk-Tab (was rausgeht), Echtzeit-Ansicht des Zielsystems. Ein Fall ist zu, wenn alle drei dasselbe sagen. Nicht vorher.
Die Diagnose als Wenn/Dann-Liste
Zum Mitnehmen die Prüfreihenfolge am Stück, beim ersten Treffer aussteigen:
Wenn nicht mal Container Loaded, DOM Ready und Window Loaded auftauchen, dann wurde der dataLayer neu zugewiesen. Snippet suchen, auf push umbauen.
Wenn beim Absenden kein Formular-Ereignis erscheint, dann stoppt das Plugin das Bubbling oder sendet per Ajax. Fix: dataLayer-Push im Erfolgs-Callback.
Wenn das Ereignis da ist, der Trigger aber nicht anspringt, dann passen die Bedingungen nicht. Werte aus der Vorschau kopieren statt abtippen.
Wenn der Trigger anspringt und der Tag stumm bleibt, dann blockt eine Ausnahme. Ausnahmen-Block des Tags lesen.
Wenn der Tag „gefeuert“ meldet und nichts ankommt, dann prüf den Netzwerk-Tab. Kein Request: Blocker oder Weiterleitung.
Wenn der Trigger nach einem Theme-Update starb, dann hing er an Klassennamen. Auf ein dataLayer-Event umbauen.
Meistens endet die Suche beim zweiten Punkt, dem Formular-Plugin. Die Liste ist unspektakulär. Aber sie ersetzt Stochern durch Diagnose, und das ist der halbe Fix.