{"id":28768,"date":"2026-11-04T18:06:25","date_gmt":"2026-11-04T17:06:25","guid":{"rendered":"https:\/\/www.lukaswojcik.com\/blog\/werkzeuge\/gtm-container-orphan-checker-unused-tags-triggers-variables\/"},"modified":"2026-11-04T19:17:22","modified_gmt":"2026-11-04T18:17:22","slug":"gtm-container-orphan-checker-unused-tags-triggers-variables","status":"publish","type":"page","link":"https:\/\/www.lukaswojcik.com\/blog\/de\/werkzeuge\/gtm-container-orphan-checker-unused-tags-triggers-variables\/","title":{"rendered":"GTM-Container aufr\u00e4umen: verwaiste Tags, Trigger und Variablen finden"},"content":{"rendered":"<div class=\"lw-go\" id=\"go-wurzel\" style=\"background: var(--bg-panel, #1e1e24); padding: 25px; border-radius: 8px; border: 1px solid var(--border, #2a2a35);\">\n<style>\n.lw-go label.go-feld { display: flex; flex-direction: column; gap: 6px; font-size: 0.84rem; color: var(--text-secondary, #a0a0b0); margin-bottom: 12px; }\n.lw-go textarea { width: 100%; box-sizing: border-box; padding: 9px 10px; background: var(--bg-body, #14141a); border: 1px solid var(--border, #2a2a35); color: var(--text-primary, #e8e8ee); border-radius: 6px; font-family: monospace; font-size: 0.84rem; min-height: 220px; resize: vertical; line-height: 1.45; }\n.lw-go .go-reihe { display: flex; flex-wrap: wrap; gap: 10px; align-items: center; margin: 4px 0 6px; }\n.lw-go button { padding: 9px 16px; border-radius: 6px; border: 1px solid var(--border, #2a2a35); background: var(--bg-body, #14141a); color: var(--text-primary, #e8e8ee); font-size: 0.92rem; cursor: pointer; }\n.lw-go button.go-haupt { background: var(--accent, #38bdf8); border-color: var(--accent, #38bdf8); color: var(--on-accent, #0a0e14); font-weight: 700; }\n.lw-go button:focus-visible, .lw-go input:focus-visible, .lw-go textarea:focus-visible, .lw-go summary:focus-visible { outline: 2px solid var(--accent, #38bdf8); outline-offset: 2px; }\n.lw-go .go-datei { font-size: 0.86rem; color: var(--text-secondary, #a0a0b0); max-width: 100%; }\n.lw-go .go-status { min-height: 1.3em; margin: 10px 0 0; font-size: 0.92rem; color: var(--text-secondary, #a0a0b0); }\n.lw-go .go-status.go-schlecht { color: var(--fail, #ff7b72); }\n.lw-go .go-h { font-weight: 700; color: var(--text-primary, #e8e8ee); font-size: 0.98rem; margin: 26px 0 8px; }\n.lw-go .go-tabelle { overflow-x: auto; }\n.lw-go table { border-collapse: collapse; width: 100%; font-size: 0.88rem; }\n.lw-go th, .lw-go td { text-align: left; padding: 6px 10px; border-bottom: 1px solid var(--border, #2a2a35); vertical-align: top; color: var(--text-primary, #e8e8ee); }\n.lw-go th { color: var(--text-secondary, #a0a0b0); font-weight: 600; font-size: 0.8rem; }\n.lw-go td.go-zahl, .lw-go th.go-zahl { text-align: right; font-variant-numeric: tabular-nums; }\n.lw-go .go-behaelter { margin: 0 0 8px; font-size: 0.9rem; color: var(--text-secondary, #a0a0b0); }\n.lw-go ul.go-liste { list-style: none; margin: 0; padding: 0; }\n.lw-go ul.go-liste > li { display: flex; gap: 10px; align-items: flex-start; padding: 10px 0; border-bottom: 1px solid var(--border, #2a2a35); font-size: 0.9rem; line-height: 1.5; color: var(--text-primary, #e8e8ee); }\n.lw-go .go-marke { flex: 0 0 auto; min-width: 74px; text-align: center; font-size: 0.74rem; font-weight: 700; padding: 2px 6px; border-radius: 4px; border: 1px solid currentColor; }\n.lw-go .go-fehler { color: var(--fail, #ff7b72); }\n.lw-go .go-warnung { color: var(--warn, #f0b429); }\n.lw-go .go-hinweis { color: var(--text-secondary, #a0a0b0); }\n.lw-go .go-gut { color: var(--pass, #3fb950); }\n.lw-go .go-inhalt { flex: 1 1 auto; min-width: 0; }\n.lw-go .go-titel { font-weight: 600; }\n.lw-go .go-hilfe { display: block; font-size: 0.84rem; color: var(--text-secondary, #a0a0b0); margin-top: 2px; line-height: 1.55; }\n.lw-go details { margin-top: 6px; }\n.lw-go summary { cursor: pointer; font-size: 0.84rem; color: var(--accent, #38bdf8); }\n.lw-go ul.go-elemente { list-style: none; margin: 6px 0 0; padding: 0; }\n.lw-go ul.go-elemente li { font-size: 0.84rem; padding: 3px 0; border: 0; display: block; word-break: break-word; }\n.lw-go .go-art { color: var(--text-secondary, #a0a0b0); font-size: 0.76rem; margin-right: 6px; }\n.lw-go .go-nr { font-family: monospace; color: var(--text-secondary, #a0a0b0); font-size: 0.78rem; }\n.lw-go .go-mehr { font-size: 0.82rem; color: var(--text-secondary, #a0a0b0); }\n.lw-go .go-klein { font-size: 0.84rem; color: var(--text-secondary, #a0a0b0); line-height: 1.55; margin: 0 0 6px; }\n.lw-go .go-klein a, .lw-go ul.go-links a { color: var(--accent, #38bdf8); }\n.lw-go ul.go-links { margin: 0 0 10px; padding-left: 1.2em; font-size: 0.86rem; line-height: 1.6; color: var(--text-secondary, #a0a0b0); }\n.lw-go .go-gruppe { margin: 0 0 18px; }\n.lw-go .go-gruppe-kopf { font-weight: 700; color: var(--text-primary, #e8e8ee); font-size: 0.92rem; margin: 0 0 4px; padding: 6px 0; border-bottom: 2px solid var(--accent, #38bdf8); }\n.lw-go .go-gruppe-kopf .go-anzahl { color: var(--text-secondary, #a0a0b0); font-weight: 400; }\n.lw-go table.go-loesch td { word-break: break-word; }\n.lw-go table.go-loesch td.go-n { font-weight: 600; width: 45%; }\n.lw-go table.go-loesch td.go-o { color: var(--text-secondary, #a0a0b0); width: 18%; }\n.lw-go table.go-loesch td.go-g { color: var(--text-secondary, #a0a0b0); font-size: 0.84rem; }\n.lw-go .go-nichts { font-size: 0.9rem; color: var(--pass, #3fb950); margin: 0 0 12px; }\n.lw-go details.go-ueberblick { margin-top: 22px; }\n.lw-go details.go-ueberblick summary { font-weight: 700; color: var(--text-primary, #e8e8ee); font-size: 0.95rem; }\n@media (max-width: 480px) {\n    .lw-go table.go-loesch td.go-o { display: none; }\n    .lw-go table.go-loesch th.go-o { display: none; }\n    .lw-go { padding: 16px !important; }\n    .lw-go .go-marke { min-width: 62px; }\n}\n<\/style>\n<p style=\"color: var(--text-secondary, #a0a0b0); margin-bottom: 18px;\">Ein Container w\u00e4chst durch Hinzuf\u00fcgen und selten durch Entfernen. Diese Pr\u00fcfung liest den Export eines Google-Tag-Manager-Containers im Browser und listet, was mit nichts mehr verbunden ist: Tags ohne funktionierenden Trigger, Trigger und Variablen, auf die nichts verweist, \u00fcbrig gebliebene Vorlagen und Ordner sowie Elemente, die nur von pausierten Tags gebraucht werden. Defekte Verweise (eine Trigger-ID oder eine {{Variable}}, die es nicht gibt) und doppelte IDs stehen ebenfalls in der Liste, weil gerade sie dazu f\u00fchren, dass ein Tag stillschweigend nichts sendet.<\/p>\n<p>    <label class=\"go-feld\">Container-Export (JSON einf\u00fcgen oder Datei ausw\u00e4hlen)<br \/>\n        <textarea id=\"go-json\" spellcheck=\"false\" autocomplete=\"off\" data-mp-mask placeholder=\"{&quot;exportFormatVersion&quot;: 2, &quot;containerVersion&quot;: {&hellip;}}\"><\/textarea><br \/>\n    <\/label><\/p>\n<p class=\"go-klein\">Im Tag Manager: Admin \u2192 Container exportieren, f\u00fcr eine Version oder den Arbeitsbereich. Das API-Format einer Containerversion funktioniert ebenfalls.<\/p>\n<div class=\"go-reihe\">\n        <input id=\"go-datei\" class=\"go-datei\" type=\"file\" accept=\".json,.txt,application\/json,text\/plain\">\n    <\/div>\n<div class=\"go-reihe\">\n        <button type=\"button\" id=\"go-los\" class=\"go-haupt\">Container pr\u00fcfen<\/button><br \/>\n        <button type=\"button\" id=\"go-beispiel\">Beispielcontainer<\/button><br \/>\n        <button type=\"button\" id=\"go-leeren\">Leeren<\/button>\n    <\/div>\n<p id=\"go-status\" class=\"go-status\" data-mp-mask aria-live=\"polite\">\n<div id=\"go-ergebnis\" data-mp-mask hidden>\n<p id=\"go-behaelter\" class=\"go-behaelter\" data-mp-mask>\n<div class=\"go-h\">L\u00f6schliste<\/div>\n<p class=\"go-klein\">Alles hier kann weg, gruppiert wie im Tag Manager. Am besten in dieser Reihenfolge l\u00f6schen: Tags, Trigger, Variablen, Vorlagen, Ordner \u2013 so verweist beim L\u00f6schen nichts mehr auf das Element. Eingebaute Variablen werden nicht gel\u00f6scht, sondern unter Variablen \u2192 Konfigurieren abgew\u00e4hlt. Eintr\u00e4ge mit \u201enur genutzt von \u2026\u201c werden frei, sobald die dort genannten Elemente weg sind.<\/p>\n<div id=\"go-loeschliste\" data-mp-mask><\/div>\n<div class=\"go-reihe\" id=\"go-export\" hidden>\n            <button type=\"button\" id=\"go-kopieren\">L\u00f6schliste kopieren<\/button><br \/>\n            <button type=\"button\" id=\"go-csv\">CSV herunterladen<\/button>\n        <\/div>\n<div id=\"go-weitere-block\">\n<div class=\"go-h\">Fehler und Hinweise<\/div>\n<p class=\"go-klein\">Das sind keine L\u00f6schkandidaten, sondern Fehler zum Beheben: Verweise ins Leere, doppelte IDs und \u00c4hnliches.<\/p>\n<ul id=\"go-befunde\" class=\"go-liste\" data-mp-mask><\/ul>\n<\/p><\/div>\n<details class=\"go-ueberblick\">\n<summary>\u00dcberblick<\/summary>\n<div class=\"go-tabelle\">\n<table>\n<thead>\n<tr>\n<th>Element<\/th>\n<th class=\"go-zahl\">Im Container<\/th>\n<th class=\"go-zahl\">Aufr\u00e4umkandidaten<\/th>\n<\/tr>\n<\/thead>\n<tbody id=\"go-zahlen\" data-mp-mask><\/tbody>\n<\/table>\n<\/div>\n<\/details><\/div>\n<div class=\"go-h\">Was gepr\u00fcft wird<\/div>\n<p class=\"go-klein\">Aufbau: das Exportformat (containerVersion mit Listen f\u00fcr Tags, Trigger, Variablen, Ordner, eingebaute Variablen, Vorlagen, Zonen, Clients und Transformationen), doppelte IDs und doppelte Namen.<\/p>\n<p class=\"go-klein\">Verweise: ausl\u00f6sende und blockierende Trigger, Mitglieder von Trigger-Gruppen, Setup- und Cleanup-Tags nach Namen, jede {{Variable}} in Parametern, Filtern und Einwilligungsfeldern, Typen eigener Vorlagen (cvt_\u2026) und Ordner-IDs. Namen werden exakt verglichen, mit Gro\u00df- und Kleinschreibung und Leerzeichen.<\/p>\n<p class=\"go-klein\">Verwaiste Elemente: Ein Tag ist aktiv, wenn er nicht pausiert ist und einen vorhandenen ausl\u00f6senden Trigger hat oder von einem aktiven Tag gestartet wird. Von aktiven Tags, Zonen, Clients und Transformationen aus werden Trigger, Variablen und Vorlagen verfolgt. Was nicht erreicht wird, ist entweder ungenutzt (nichts verweist darauf) oder nur von toten Elementen genutzt (nur pausierte oder nie feuernde Elemente verweisen darauf).<\/p>\n<p class=\"go-klein\">Reihenfolge: zuerst defekte Verweise, dann ungenutzte Elemente, dann Punkte, die einen Blick lohnen.<\/p>\n<div class=\"go-h\">Grenzen und Datenschutz<\/div>\n<p class=\"go-klein\">Die Pr\u00fcfung arbeitet mit Namen und IDs im Export. Nicht sichtbar sind ein Name, den ein Skript als blo\u00dfen Text zusammensetzt, ein Element, das ein anderer Arbeitsbereich noch nutzt, und ein Tag, der mit Absicht bleibt. Ein gelistetes Element ist ein Kandidat und kein Urteil: vor dem L\u00f6schen mit Versionsverlauf und Vorschau abgleichen. Server-Container werden genauso gelesen, Verweise von Clients und Transformationen z\u00e4hlen als aktiv.<\/p>\n<p class=\"go-klein\">Das Container-JSON wird im Browser gelesen und ausgewertet und nirgendwohin gesendet. Exporte enthalten Tag-IDs, Mess-IDs und manchmal Pixelcodes oder Schl\u00fcssel in benutzerdefiniertem HTML; deshalb wird hier nichts gespeichert oder \u00fcbertragen, und die Ergebnisbereiche sind von der Sitzungsaufzeichnung ausgenommen.<\/p>\n<div class=\"go-h\">Dazu<\/div>\n<p class=\"go-klein\">Weitere Werkzeuge f\u00fcr GTM-Container:<\/p>\n<ul class=\"go-links\">\n<li><a href=\"https:\/\/www.lukaswojcik.com\/blog\/de\/werkzeuge\/gtm-duplicates-analyser\/\">GTM-Duplikatanalyse<\/a> \u2013 findet Tags, Trigger und Variablen, die dasselbe doppelt tun.<\/li>\n<li><a href=\"https:\/\/www.lukaswojcik.com\/blog\/de\/werkzeuge\/gtm-naming-convention-auditer\/\">GTM-Namenskonventionen pr\u00fcfen<\/a> \u2013 gleicht Elementnamen mit einer vereinbarten Konvention ab.<\/li>\n<li><a href=\"https:\/\/www.lukaswojcik.com\/blog\/de\/werkzeuge\/gtm-container-history-deep-search-engine\/\">GTM-Containerverlauf und Tiefensuche<\/a> \u2013 findet die Version, in der ein Element angelegt, ge\u00e4ndert oder entfernt wurde.<\/li>\n<li><a href=\"https:\/\/www.lukaswojcik.com\/blog\/de\/werkzeuge\/gtm-datalayer-variable-path-flattener\/\">GTM DataLayer-Variablenpfade erzeugen<\/a> \u2013 macht aus einem verschachtelten dataLayer-Objekt die anzulegenden Variablenpfade.<\/li>\n<li><a href=\"https:\/\/www.lukaswojcik.com\/blog\/de\/werkzeuge\/text-code-diff\/\">Text- und Code-Vergleich<\/a> \u2013 vergleicht zwei Exporte, etwa vor und nach dem Aufr\u00e4umen.<\/li>\n<\/ul>\n<p class=\"go-klein\">Artikel zum Ordnunghalten im Container:<\/p>\n<ul class=\"go-links\">\n<li><a href=\"https:\/\/www.lukaswojcik.com\/blog\/de\/digital-analytics-de\/tutorials-de\/tutorial-eine-gtm-namenskonvention-festlegen-und-im-bestehenden-container-durchsetzen\/\">Tutorial: Eine GTM-Namenskonvention festlegen und im bestehenden Container durchsetzen<\/a> \u2013 an Namen sind verwaiste Elemente leicht zu erkennen.<\/li>\n<li><a href=\"https:\/\/www.lukaswojcik.com\/blog\/de\/web-entwicklung\/zwei-gtm-container-exporte-vergleichen-normalisieren-vor-dem-diff-und-was-ein-zeilenvergleich-nicht-zeigt\/\">Zwei GTM-Container-Exporte vergleichen<\/a> \u2013 so zeigt sich, dass das Aufr\u00e4umen nur entfernt hat, was es sollte.<\/li>\n<li><a href=\"https:\/\/www.lukaswojcik.com\/blog\/de\/digital-analytics-de\/tutorials-de\/tutorial-die-containerversion-finden-in-der-sich-ein-tag-geandert-hat\/\">Tutorial: Die Containerversion finden, in der sich ein Tag ge\u00e4ndert hat<\/a> \u2013 f\u00fcr den Fall, dass sich ein entferntes Element doch als n\u00f6tig erweist.<\/li>\n<li><a href=\"https:\/\/www.lukaswojcik.com\/blog\/de\/digital-marketing-de\/tutorials-de-digital-marketing-de\/tutorial-google-tag-manager-anderungen-mit-claude-code-vorbereiten-und-prufen\/\">Tutorial: Google-Tag-Manager-\u00c4nderungen mit Claude Code vorbereiten und pr\u00fcfen<\/a> \u2013 das Aufr\u00e4umen vor der Ver\u00f6ffentlichung gegenlesen.<\/li>\n<\/ul>\n<\/div>\n<p><script>\n(function () {\n    'use strict';<\/p>\n<p>    const T = {\"einleitung\":\"Ein Container w\u00e4chst durch Hinzuf\u00fcgen und selten durch Entfernen. Diese Pr\u00fcfung liest den Export eines Google-Tag-Manager-Containers im Browser und listet, was mit nichts mehr verbunden ist: Tags ohne funktionierenden Trigger, Trigger und Variablen, auf die nichts verweist, \u00fcbrig gebliebene Vorlagen und Ordner sowie Elemente, die nur von pausierten Tags gebraucht werden. Defekte Verweise (eine Trigger-ID oder eine {{Variable}}, die es nicht gibt) und doppelte IDs stehen ebenfalls in der Liste, weil gerade sie dazu f\u00fchren, dass ein Tag stillschweigend nichts sendet.\",\"f_json\":\"Container-Export (JSON einf\u00fcgen oder Datei ausw\u00e4hlen)\",\"f_hilfe\":\"Im Tag Manager: Admin \u2192 Container exportieren, f\u00fcr eine Version oder den Arbeitsbereich. Das API-Format einer Containerversion funktioniert ebenfalls.\",\"k_pruefen\":\"Container pr\u00fcfen\",\"k_beispiel\":\"Beispielcontainer\",\"k_leeren\":\"Leeren\",\"k_kopieren\":\"L\u00f6schliste kopieren\",\"k_csv\":\"CSV herunterladen\",\"h_ueberblick\":\"\u00dcberblick\",\"sp_art\":\"Element\",\"sp_gesamt\":\"Im Container\",\"sp_kandidaten\":\"Aufr\u00e4umkandidaten\",\"h_befunde\":\"Fehler und Hinweise\",\"h_regeln\":\"Was gepr\u00fcft wird\",\"regel_1\":\"Aufbau: das Exportformat (containerVersion mit Listen f\u00fcr Tags, Trigger, Variablen, Ordner, eingebaute Variablen, Vorlagen, Zonen, Clients und Transformationen), doppelte IDs und doppelte Namen.\",\"regel_2\":\"Verweise: ausl\u00f6sende und blockierende Trigger, Mitglieder von Trigger-Gruppen, Setup- und Cleanup-Tags nach Namen, jede {{Variable}} in Parametern, Filtern und Einwilligungsfeldern, Typen eigener Vorlagen (cvt_\u2026) und Ordner-IDs. Namen werden exakt verglichen, mit Gro\u00df- und Kleinschreibung und Leerzeichen.\",\"regel_3\":\"Verwaiste Elemente: Ein Tag ist aktiv, wenn er nicht pausiert ist und einen vorhandenen ausl\u00f6senden Trigger hat oder von einem aktiven Tag gestartet wird. Von aktiven Tags, Zonen, Clients und Transformationen aus werden Trigger, Variablen und Vorlagen verfolgt. Was nicht erreicht wird, ist entweder ungenutzt (nichts verweist darauf) oder nur von toten Elementen genutzt (nur pausierte oder nie feuernde Elemente verweisen darauf).\",\"regel_4\":\"Reihenfolge: zuerst defekte Verweise, dann ungenutzte Elemente, dann Punkte, die einen Blick lohnen.\",\"h_grenzen\":\"Grenzen und Datenschutz\",\"grenze\":\"Die Pr\u00fcfung arbeitet mit Namen und IDs im Export. Nicht sichtbar sind ein Name, den ein Skript als blo\u00dfen Text zusammensetzt, ein Element, das ein anderer Arbeitsbereich noch nutzt, und ein Tag, der mit Absicht bleibt. Ein gelistetes Element ist ein Kandidat und kein Urteil: vor dem L\u00f6schen mit Versionsverlauf und Vorschau abgleichen. Server-Container werden genauso gelesen, Verweise von Clients und Transformationen z\u00e4hlen als aktiv.\",\"datenschutz\":\"Das Container-JSON wird im Browser gelesen und ausgewertet und nirgendwohin gesendet. Exporte enthalten Tag-IDs, Mess-IDs und manchmal Pixelcodes oder Schl\u00fcssel in benutzerdefiniertem HTML; deshalb wird hier nichts gespeichert oder \u00fcbertragen, und die Ergebnisbereiche sind von der Sitzungsaufzeichnung ausgenommen.\",\"h_dazu\":\"Dazu\",\"dazu_werkzeuge\":\"Weitere Werkzeuge f\u00fcr GTM-Container:\",\"dazu_artikel\":\"Artikel zum Ordnunghalten im Container:\",\"w1_titel\":\"GTM-Duplikatanalyse\",\"w1_text\":\"findet Tags, Trigger und Variablen, die dasselbe doppelt tun.\",\"w2_titel\":\"GTM-Namenskonventionen pr\u00fcfen\",\"w2_text\":\"gleicht Elementnamen mit einer vereinbarten Konvention ab.\",\"w3_titel\":\"GTM-Containerverlauf und Tiefensuche\",\"w3_text\":\"findet die Version, in der ein Element angelegt, ge\u00e4ndert oder entfernt wurde.\",\"w4_titel\":\"GTM DataLayer-Variablenpfade erzeugen\",\"w4_text\":\"macht aus einem verschachtelten dataLayer-Objekt die anzulegenden Variablenpfade.\",\"w5_titel\":\"Text- und Code-Vergleich\",\"w5_text\":\"vergleicht zwei Exporte, etwa vor und nach dem Aufr\u00e4umen.\",\"a1_titel\":\"Tutorial: Eine GTM-Namenskonvention festlegen und im bestehenden Container durchsetzen\",\"a1_text\":\"an Namen sind verwaiste Elemente leicht zu erkennen.\",\"a2_titel\":\"Zwei GTM-Container-Exporte vergleichen\",\"a2_text\":\"so zeigt sich, dass das Aufr\u00e4umen nur entfernt hat, was es sollte.\",\"a3_titel\":\"Tutorial: Die Containerversion finden, in der sich ein Tag ge\u00e4ndert hat\",\"a3_text\":\"f\u00fcr den Fall, dass sich ein entferntes Element doch als n\u00f6tig erweist.\",\"a4_titel\":\"Tutorial: Google-Tag-Manager-\u00c4nderungen mit Claude Code vorbereiten und pr\u00fcfen\",\"a4_text\":\"das Aufr\u00e4umen vor der Ver\u00f6ffentlichung gegenlesen.\",\"tausendertrenner\":\".\",\"s_position\":\"(Zeile {zeile}, Spalte {spalte})\",\"s_json\":\"Das ist kein g\u00fcltiges JSON.\",\"s_kein_container\":\"Das JSON sieht nicht nach einem Tag-Manager-Container aus: Es gibt weder containerVersion noch eine Liste mit Tags, Triggern oder Variablen.\",\"s_leer\":\"Noch nichts zu pr\u00fcfen: zuerst einen Export einf\u00fcgen oder eine Datei ausw\u00e4hlen.\",\"s_zu_gross\":\"Die Datei ist gr\u00f6\u00dfer als 30 MB und wurde nicht gelesen.\",\"s_lesen\":\"Datei wird gelesen \u2026\",\"s_lesefehler\":\"Die Datei konnte nicht gelesen werden.\",\"s_ok\":\"{n} Elemente in {ms} ms gepr\u00fcft.\",\"s_beispiel\":\"Beispielcontainer geladen und gepr\u00fcft.\",\"s_kopiert\":\"Aufr\u00e4umliste kopiert.\",\"s_kopieren_fehl\":\"Der Browser hat das Kopieren blockiert. Der CSV-Download enth\u00e4lt dieselbe Liste.\",\"behaelter_mit_name\":\"Container {name} ({id}): {n} Elemente gelesen, {k} Aufr\u00e4umkandidaten, {f} defekte Verweise oder doppelte IDs.\",\"behaelter_ohne_name\":\"{n} Elemente gelesen, {k} Aufr\u00e4umkandidaten, {f} defekte Verweise oder doppelte IDs.\",\"zeige_elemente\":\"Elemente anzeigen\",\"ohne_namen\":\"(ohne Namen)\",\"weitere\":\"\u2026 und {n} weitere, alle stehen in der CSV.\",\"stufe_fehler\":\"Fehler\",\"stufe_warnung\":\"Ungenutzt\",\"stufe_hinweis\":\"Hinweis\",\"stufe_gut\":\"OK\",\"art_tag\":\"Tags\",\"art_trigger\":\"Trigger\",\"art_variable\":\"Variablen\",\"art_builtin\":\"Eingebaute Variablen (aktiviert)\",\"art_vorlage\":\"Eigene Vorlagen\",\"art_ordner\":\"Ordner\",\"art_zone\":\"Zonen\",\"art_client\":\"Clients\",\"art_transformation\":\"Transformationen\",\"art_tag_eins\":\"Tag\",\"art_trigger_eins\":\"Trigger\",\"art_variable_eins\":\"Variable\",\"art_builtin_eins\":\"Eingebaut\",\"art_vorlage_eins\":\"Vorlage\",\"art_ordner_eins\":\"Ordner\",\"art_zone_eins\":\"Zone\",\"art_client_eins\":\"Client\",\"art_transformation_eins\":\"Transformation\",\"d_pausiert\":\"pausiert\",\"d_id\":\"ID {x}\",\"d_ordner\":\"Ordner: {x}\",\"d_id_doppelt\":\"ID {x} kommt mehrfach vor\",\"d_name_doppelt\":\"{x} Elemente tragen diesen Namen\",\"d_fehlt_variable\":\"fehlt: {x}\",\"d_fehlt_trigger\":\"Trigger-ID {x} fehlt\",\"d_fehlt_tag\":\"Tag fehlt: {x}\",\"d_fehlt_vorlage\":\"Vorlage f\u00fcr {x} fehlt\",\"d_fehlt_ordner\":\"Ordner-ID {x} fehlt\",\"d_nur_von\":\"nur genutzt von: {x}\",\"csv_art\":\"Art\",\"csv_name\":\"Name\",\"csv_id\":\"ID\",\"csv_typ\":\"Typ\",\"csv_ordner\":\"Ordner\",\"csv_hinweis\":\"Hinweis\",\"b_id_doppelt\":\"Doppelte IDs\",\"b_id_doppelt_hilfe\":\"Zwei Elemente derselben Art teilen sich eine ID. Ein Verweis \u00fcber die ID kann sie nicht mehr unterscheiden. Meist stammt das aus von Hand bearbeitetem JSON oder wiederholten Importen.\",\"b_ref_trigger_fehlt\":\"Verweise auf Trigger, die es nicht gibt\",\"b_ref_trigger_fehlt_hilfe\":\"Ein Tag, eine Trigger-Gruppe oder eine Zone zeigt auf eine Trigger-ID, die nicht im Export steht, deshalb l\u00f6st nichts aus. Typisch nach dem L\u00f6schen eines Triggers, ohne die Tags zu \u00f6ffnen, die ihn nutzten, oder nach einem Teilimport.\",\"b_ref_variable_fehlt\":\"Verweise auf Variablen, die es nicht gibt\",\"b_ref_variable_fehlt_hilfe\":\"Eine {{Variable}} wird verwendet, aber weder eine Variable dieses Namens noch eine aktivierte eingebaute Variable existiert. Der Tag Manager l\u00f6st sie zu undefined auf. Der Name muss exakt passen, mit Gro\u00df- und Kleinschreibung und Leerzeichen.\",\"b_ref_builtin_aus\":\"Eingebaute Variablen verwendet, aber nicht aktiviert\",\"b_ref_builtin_aus_hilfe\":\"Der Name geh\u00f6rt zu einer eingebauten Variable, die in diesem Container nicht aktiviert ist. Unter Variablen \u2192 Konfigurieren aktiviert, hat sie einen Wert; bis dahin bleibt sie undefined.\",\"b_ref_vorlage_fehlt\":\"Eigene Vorlagen, die fehlen\",\"b_ref_vorlage_fehlt_hilfe\":\"Das Element hat einen Vorlagentyp (cvt_\u2026), dessen Vorlage nicht im Export steht. Ein Import des Containers ohne seine Vorlagen erzeugt das. Das Element funktioniert erst, wenn die Vorlage wieder da ist.\",\"b_ref_sequenz_fehlt\":\"Tag-Sequenz verweist auf einen fehlenden Tag\",\"b_ref_sequenz_fehlt_hilfe\":\"Ein Setup- oder Cleanup-Tag steht in der Sequenz eines Tags, aber es gibt keinen Tag dieses Namens. Die Sequenz kann nicht wie eingerichtet laufen.\",\"b_zyklus\":\"Variablen, die sich im Kreis aufeinander beziehen\",\"b_zyklus_hilfe\":\"Eine Variable nutzt eine zweite, die wieder die erste oder sich selbst nutzt. Der Tag Manager kann so eine Kette nicht aufl\u00f6sen, der Wert ist undefined.\",\"b_tag_ohne_ausloeser\":\"Tags, die nie feuern k\u00f6nnen\",\"b_tag_ohne_ausloeser_hilfe\":\"Es ist kein vorhandener ausl\u00f6sender Trigger zugewiesen, und kein aktiver Tag startet diesen als Setup- oder Cleanup-Tag. Er ist nicht pausiert, wirkt im Arbeitsbereich also aktiv und sendet trotzdem nichts.\",\"b_trigger_ungenutzt\":\"Trigger, die nichts verwendet\",\"b_trigger_ungenutzt_hilfe\":\"Kein Tag feuert auf diesen Trigger oder wird von ihm blockiert, und keine Trigger-Gruppe und keine Zone enth\u00e4lt ihn. Das Entfernen ist meist unproblematisch, eine fr\u00fchere Version enth\u00e4lt ihn noch.\",\"b_variable_ungenutzt\":\"Variablen, die nichts verwendet\",\"b_variable_ungenutzt_hilfe\":\"Kein Tag, Trigger, keine Variable, Zone und kein Client enth\u00e4lt den Verweis {{Name}}. Vor dem L\u00f6schen pr\u00fcfen: Ein Name, den ein Skript als blo\u00dfen Text zusammensetzt, wird nicht erkannt, und ein anderer Arbeitsbereich kann die Variable schon nutzen.\",\"b_name_doppelt_var\":\"Variablen mit gleichem Namen\",\"b_name_doppelt_var_hilfe\":\"Zwei Variablen tragen einen Namen, der Verweis {{Name}} ist damit mehrdeutig. Welche gewinnt, ist nichts, worauf sich verlassen werden sollte.\",\"b_ref_ordner_fehlt\":\"Ordnerzuordnung zeigt auf einen fehlenden Ordner\",\"b_ref_ordner_fehlt_hilfe\":\"Das Element nennt einen Ordner, der nicht im Export steht. F\u00fcr das Ausl\u00f6sen harmlos, aber das Element liegt in keinem Ordner.\",\"b_tag_pausiert\":\"Pausierte Tags\",\"b_tag_pausiert_hilfe\":\"Pausierte Tags feuern nicht. Trigger und Variablen, die nur sie nutzen, stehen gesondert in der Liste. Entweder den Tag entfernen oder festhalten, warum er bleibt.\",\"b_trigger_tot\":\"Trigger, die nur pausierte oder nie feuernde Tags nutzen\",\"b_trigger_tot_hilfe\":\"Die einzigen Verweise kommen von Tags, die nicht feuern. Der Trigger ist ungenutzt, sobald diese Tags entfernt sind.\",\"b_variable_tot\":\"Variablen, die nur pausierte oder tote Elemente nutzen\",\"b_variable_tot_hilfe\":\"Die einzigen Verweise kommen von Elementen, die nie laufen. Sie werden zusammen mit diesen Elementen ungenutzt.\",\"b_vorlage_ungenutzt\":\"Eigene Vorlagen, die nichts verwendet\",\"b_vorlage_ungenutzt_hilfe\":\"Kein Tag, keine Variable und kein Trigger ist aus der Vorlage gebaut. Vorlagen aus der Galerie lassen sich sp\u00e4ter wieder hinzuf\u00fcgen.\",\"b_vorlage_tot\":\"Vorlagen, die nur tote Elemente nutzen\",\"b_vorlage_tot_hilfe\":\"Nur pausierte oder nie feuernde Elemente sind aus der Vorlage gebaut.\",\"b_builtin_ungenutzt\":\"Aktivierte eingebaute Variablen, die nichts verwendet\",\"b_builtin_ungenutzt_hilfe\":\"Sie kosten zur Laufzeit nichts, doch die Liste im Editor und die Daten in der Vorschau werden l\u00e4nger. Manche sind mit Absicht aktiv, um beim Bau eines Triggers zur Hand zu sein.\",\"b_ordner_leer\":\"Leere Ordner\",\"b_ordner_leer_hilfe\":\"Weder Tag noch Trigger noch Variable liegt im Ordner.\",\"b_name_doppelt\":\"Tags oder Trigger mit gleichem Namen\",\"b_name_doppelt_hilfe\":\"Erlaubt, aber die Liste und die Tag-Sequenz nach Namen werden unklar.\",\"b_sauber\":\"Keine ungenutzten oder defekten Elemente gefunden.\",\"b_sauber_hilfe\":\"Jeder Tag kann feuern, und jeder Trigger, jede Variable, Vorlage und jeder Ordner wird von etwas Aktivem referenziert.\",\"h_loeschliste\":\"L\u00f6schliste\",\"loesch_hilfe\":\"Alles hier kann weg, gruppiert wie im Tag Manager. Am besten in dieser Reihenfolge l\u00f6schen: Tags, Trigger, Variablen, Vorlagen, Ordner \u2013 so verweist beim L\u00f6schen nichts mehr auf das Element. Eingebaute Variablen werden nicht gel\u00f6scht, sondern unter Variablen \u2192 Konfigurieren abgew\u00e4hlt. Eintr\u00e4ge mit \u201enur genutzt von \u2026\u201c werden frei, sobald die dort genannten Elemente weg sind.\",\"befunde_hilfe\":\"Das sind keine L\u00f6schkandidaten, sondern Fehler zum Beheben: Verweise ins Leere, doppelte IDs und \u00c4hnliches.\",\"sp_name\":\"Name\",\"sp_ordner\":\"Ordner\",\"sp_grund\":\"Grund\",\"loesch_tag\":\"Tags\",\"loesch_trigger\":\"Trigger\",\"loesch_variable\":\"Variablen\",\"loesch_vorlage\":\"Vorlagen\",\"loesch_ordner\":\"Ordner\",\"loesch_builtin\":\"Eingebaute Variablen \u2013 abw\u00e4hlen\",\"loesch_nichts\":\"Nichts zu l\u00f6schen: Jeder Tag, Trigger, jede Variable, Vorlage und jeder Ordner wird verwendet.\",\"g_tag_ohne_ausloeser\":\"kein Trigger, feuert nie\",\"g_tag_pausiert\":\"pausiert\",\"g_tag_nur_von\":\"nur gestartet von: {x}\",\"g_trigger_ungenutzt\":\"kein Tag verwendet ihn\",\"g_trigger_tot\":\"nur genutzt von: {x}\",\"g_variable_ungenutzt\":\"nirgends verwendet\",\"g_variable_tot\":\"nur genutzt von: {x}\",\"g_vorlage_ungenutzt\":\"kein Tag und keine Variable nutzt sie\",\"g_vorlage_tot\":\"nur genutzt von: {x}\",\"g_builtin_ungenutzt\":\"nirgends verwendet\",\"g_ordner_leer\":\"leer\",\"g_ordner_wird_leer\":\"leer, sobald die Eintr\u00e4ge oben gel\u00f6scht sind\",\"hinweis_teilexport\":\"Viele verwendete Variablen fehlen in dieser Datei. Das sieht nach einem Teilexport aus (Container exportieren mit nur ausgew\u00e4hlten Elementen). F\u00fcr eine L\u00f6schliste den ganzen Arbeitsbereich oder die ganze Version exportieren.\",\"hinweis_ohne_id\":\"Einige Tags, Trigger oder Variablen haben keine ID. Exporte aus dem Tag Manager tragen immer IDs, die Datei ist also vermutlich von Hand oder mit einem anderen Werkzeug erstellt, und Verweise \u00fcber IDs lassen sich nicht verl\u00e4sslich pr\u00fcfen.\",\"csv_aktion\":\"Aktion\",\"csv_loeschen\":\"L\u00f6schen\",\"csv_deaktivieren\":\"Abw\u00e4hlen\",\"w1_href\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/de\\\/werkzeuge\\\/gtm-duplicates-analyser\\\/\",\"w2_href\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/de\\\/werkzeuge\\\/gtm-naming-convention-auditer\\\/\",\"w3_href\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/de\\\/werkzeuge\\\/gtm-container-history-deep-search-engine\\\/\",\"w4_href\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/de\\\/werkzeuge\\\/gtm-datalayer-variable-path-flattener\\\/\",\"w5_href\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/de\\\/werkzeuge\\\/text-code-diff\\\/\"};<\/p>\n<p>    \/\/ KERN-ANFANG\n    var MAX_BYTES = 31457280;      \/\/ 30 MB\n    var MAX_ZEILEN = 400;          \/\/ Elemente je Befund in der Liste<\/p>\n<p>    var ARTEN = ['tag', 'trigger', 'variable', 'builtin', 'vorlage', 'ordner', 'zone', 'client', 'transformation'];\n    \/\/ Arten, die im Container als Liste stehen: Schluessel im Export, Id-Feld\n    var LISTEN = [\n        { art: 'tag', liste: 'tag', id: 'tagId' },\n        { art: 'trigger', liste: 'trigger', id: 'triggerId' },\n        { art: 'variable', liste: 'variable', id: 'variableId' },\n        { art: 'builtin', liste: 'builtInVariable', id: '' },\n        { art: 'vorlage', liste: 'customTemplate', id: 'templateId' },\n        { art: 'ordner', liste: 'folder', id: 'folderId' },\n        { art: 'zone', liste: 'zone', id: 'zoneId' },\n        { art: 'client', liste: 'client', id: 'clientId' },\n        { art: 'transformation', liste: 'transformation', id: 'transformationId' }\n    ];\n    \/\/ Eingebaute Variablen: Typ im Export -> Name in der Oberflaeche (nur sichere Zuordnungen)\n    var BUILTIN_NAMEN = {\n        CLICK_ELEMENT: 'Click Element', CLICK_CLASSES: 'Click Classes', CLICK_ID: 'Click ID', CLICK_TARGET: 'Click Target', CLICK_URL: 'Click URL',\n        CLICK_TEXT: 'Click Text', ERROR_MESSAGE: 'Error Message', ERROR_URL: 'Error URL', ERROR_LINE: 'Error Line', DEBUG_MODE: 'Debug Mode',\n        FORM_ELEMENT: 'Form Element', FORM_CLASSES: 'Form Classes', FORM_ID: 'Form ID', FORM_TARGET: 'Form Target', FORM_URL: 'Form URL', FORM_TEXT: 'Form Text',\n        HISTORY_SOURCE: 'History Source', NEW_HISTORY_FRAGMENT: 'New History Fragment', OLD_HISTORY_FRAGMENT: 'Old History Fragment',\n        NEW_HISTORY_STATE: 'New History State', OLD_HISTORY_STATE: 'Old History State', PAGE_URL: 'Page URL', PAGE_HOSTNAME: 'Page Hostname',\n        PAGE_PATH: 'Page Path', REFERRER: 'Referrer', SCROLL_DEPTH_THRESHOLD: 'Scroll Depth Threshold', SCROLL_DEPTH_UNITS: 'Scroll Depth Units',\n        SCROLL_DEPTH_DIRECTION: 'Scroll Direction', CONTAINER_ID: 'Container ID', CONTAINER_VERSION: 'Container Version', ENVIRONMENT_NAME: 'Environment Name',\n        EVENT: 'Event', HTML_ID: 'HTML ID', RANDOM_NUMBER: 'Random Number', VIDEO_CURRENT_TIME: 'Video Current Time', VIDEO_DURATION: 'Video Duration',\n        VIDEO_PERCENT: 'Video Percent', VIDEO_PROVIDER: 'Video Provider', VIDEO_STATUS: 'Video Status', VIDEO_TITLE: 'Video Title', VIDEO_URL: 'Video URL',\n        VIDEO_VISIBLE: 'Video Visible'\n    };\n    \/\/ Eingebaute Trigger: feste IDs, die im Export nie als Trigger erscheinen\n    var BUILTIN_TRIGGER = { '2147479553': 'All Pages', '2147479572': 'Consent Initialization - All Pages', '2147479573': 'Initialization - All Pages',\n        '2147479574': 'built-in (server container)' };\n    var BUILTIN_BEKANNT = {};\n    Object.keys(BUILTIN_NAMEN).forEach(function (k) { BUILTIN_BEKANNT[BUILTIN_NAMEN[k]] = true; });<\/p>\n<p>    \/\/ Schluessel, die nie nach Verweisen durchsucht werden (Namen, Notizen, Kennungen)\n    var SPERRE = { name: 1, notes: 1, fingerprint: 1, tagManagerUrl: 1, path: 1, accountId: 1, containerId: 1, containerVersionId: 1, workspaceId: 1,\n        tagId: 1, triggerId: 1, variableId: 1, folderId: 1, templateId: 1, zoneId: 1, clientId: 1, transformationId: 1, parentFolderId: 1,\n        firingTriggerId: 1, blockingTriggerId: 1, customEvaluationTriggerId: 1, setupTag: 1, teardownTag: 1 };<\/p>\n<p>    var ORDNUNG = ['id_doppelt', 'ref_trigger_fehlt', 'ref_variable_fehlt', 'ref_builtin_aus', 'ref_vorlage_fehlt', 'ref_sequenz_fehlt', 'zyklus',\n        'tag_ohne_ausloeser', 'trigger_ungenutzt', 'variable_ungenutzt', 'name_doppelt_var',\n        'ref_ordner_fehlt', 'tag_pausiert', 'trigger_tot', 'variable_tot', 'vorlage_ungenutzt', 'vorlage_tot', 'builtin_ungenutzt', 'ordner_leer', 'name_doppelt'];\n    var STUFE = { id_doppelt: 'fehler', ref_trigger_fehlt: 'fehler', ref_variable_fehlt: 'fehler', ref_builtin_aus: 'fehler', ref_vorlage_fehlt: 'fehler',\n        ref_sequenz_fehlt: 'fehler', zyklus: 'fehler', tag_ohne_ausloeser: 'warnung', trigger_ungenutzt: 'warnung', variable_ungenutzt: 'warnung',\n        name_doppelt_var: 'warnung', ref_ordner_fehlt: 'hinweis', tag_pausiert: 'hinweis', trigger_tot: 'hinweis', variable_tot: 'hinweis',\n        vorlage_ungenutzt: 'hinweis', vorlage_tot: 'hinweis', builtin_ungenutzt: 'hinweis', ordner_leer: 'hinweis', name_doppelt: 'hinweis' };\n    \/\/ Befunde, deren Elemente als Aufraeumkandidaten zaehlen\n    var KANDIDAT = { tag_ohne_ausloeser: 1, tag_pausiert: 1, trigger_ungenutzt: 1, trigger_tot: 1, variable_ungenutzt: 1, variable_tot: 1,\n        vorlage_ungenutzt: 1, vorlage_tot: 1, builtin_ungenutzt: 1, ordner_leer: 1 };<\/p>\n<p>    function s(x) { return x === undefined || x === null ? '' : String(x); }\n    function fmt(vorlage, werte) {\n        return String(vorlage).replace(\/\\{(\\w+)\\}\/g, function (alles, k) { return Object.prototype.hasOwnProperty.call(werte, k) ? werte[k] : alles; });\n    }\n    function zahl(n) { return String(n).replace(\/\\B(?=(\\d{3})+(?!\\d))\/g, T.tausendertrenner || ','); }<\/p>\n<p>    \/\/ --- Verweise aus einem Element einsammeln --------------------------------\n    function sammeln(x, r, tiefe) {\n        if (tiefe > 40 || x === null || x === undefined) { return; }\n        if (typeof x === 'string') {\n            var re = \/\\{\\{([^{}]+?)\\}\\}\/g, m;\n            while ((m = re.exec(x)) !== null) { r.vars.push(m[1]); }\n            return;\n        }\n        if (Array.isArray(x)) { for (var i = 0; i < x.length; i++) { sammeln(x[i], r, tiefe + 1); } return; }\n        if (typeof x !== 'object') { return; }\n        if (x.type === 'TRIGGER_REFERENCE' &#038;&#038; x.value !== undefined) { r.trig.push(s(x.value)); }\n        if (x.type === 'TAG_REFERENCE' &#038;&#038; x.value !== undefined) { r.tags.push(s(x.value)); }\n        for (var k in x) {\n            if (!Object.prototype.hasOwnProperty.call(x, k) || SPERRE[k] === 1) { continue; }\n            sammeln(x[k], r, tiefe + 1);\n        }\n    }\n    function verweise(roh, art) {\n        var r = { vars: [], trig: [], fire: [], tags: [], seq: [], tmpl: '' };\n        if (art === 'vorlage' || art === 'ordner') { return r; }\n        sammeln(roh, r, 0);\n        ['firingTriggerId', 'blockingTriggerId', 'customEvaluationTriggerId'].forEach(function (k) {\n            var a = roh[k];\n            if (!a &#038;&#038; roh.boundary &#038;&#038; k === 'customEvaluationTriggerId') { a = roh.boundary.customEvaluationTriggerId; }\n            if (a !== undefined &#038;&#038; a !== null &#038;&#038; !Array.isArray(a)) { a = [a]; }\n            (a || []).forEach(function (id) { r.trig.push(s(id)); if (k === 'firingTriggerId') { r.fire.push(s(id)); } });\n        });\n        ['setupTag', 'teardownTag'].forEach(function (k) {\n            (Array.isArray(roh[k]) ? roh[k] : []).forEach(function (t) { if (t &#038;&#038; t.tagName !== undefined) { r.seq.push(s(t.tagName)); } });\n        });\n        \/\/ Vorlagentyp: cvt_<Container-ID>_<templateId> fuer eigene, cvt_<Galerie-ID> fuer Galerievorlagen\n        if (\/^cvt_.\/.test(s(roh.type))) { r.tmpl = s(roh.type).slice(4); }\n        return r;\n    }<\/p>\n<p>    \/\/ --- Container finden ------------------------------------------------------\n    function holeContainer(wurzel) {\n        if (!wurzel || typeof wurzel !== 'object' || Array.isArray(wurzel)) { return null; }\n        if (wurzel.containerVersion && typeof wurzel.containerVersion === 'object' && !Array.isArray(wurzel.containerVersion)) { return wurzel.containerVersion; }\n        for (var i = 0; i < LISTEN.length; i++) { if (Array.isArray(wurzel[LISTEN[i].liste])) { return wurzel; } }\n        return null;\n    }\n\n    \/\/ --- Analyse ----------------------------------------------------------------\n    function analysiere(cv) {\n        var el = [], idKarte = {}, nameKarte = { tag: {}, variable: {} }, builtinKarte = {}, galerieKarte = {};\n        ARTEN.forEach(function (a) { idKarte[a] = {}; });\n        var fund = {};\n        function melde(key, e, info) {\n            if (!fund[key]) { fund[key] = []; }\n            fund[key].push({ e: e, info: info || null });\n        }\n\n        \/\/ 1. Elemente anlegen\n        LISTEN.forEach(function (L) {\n            var liste = Array.isArray(cv[L.liste]) ? cv[L.liste] : [];\n            liste.forEach(function (roh) {\n                if (!roh || typeof roh !== 'object') { return; }\n                var e = { n: el.length, art: L.art, roh: roh, id: L.id ? s(roh[L.id]) : '', name: s(roh.name), typ: s(roh.type), ordner: s(roh.parentFolderId),\n                    ein: [], aus: [], pausiert: roh.paused === true };\n                if (L.art === 'builtin') { if (!e.name) { e.name = BUILTIN_NAMEN[e.typ] || e.typ; } }\n                e.ref = verweise(roh, L.art);\n                el.push(e);\n                if (e.id !== '') { (idKarte[L.art][e.id] = idKarte[L.art][e.id] || []).push(e); }\n                if (L.art === 'tag' || L.art === 'variable') { (nameKarte[L.art][e.name] = nameKarte[L.art][e.name] || []).push(e); }\n                if (L.art === 'builtin') { builtinKarte[e.name] = e; }\n                if (L.art === 'vorlage' &#038;&#038; roh.galleryReference &#038;&#038; roh.galleryReference.galleryTemplateId) {\n                    (galerieKarte[s(roh.galleryReference.galleryTemplateId)] = galerieKarte[s(roh.galleryReference.galleryTemplateId)] || []).push(e);\n                }\n            });\n        });\n\n        \/\/ 2. Doppelte Kennungen und Namen\n        ARTEN.forEach(function (a) {\n            Object.keys(idKarte[a]).forEach(function (id) {\n                if (idKarte[a][id].length > 1) { idKarte[a][id].forEach(function (e) { melde('id_doppelt', e, { k: 'd_id_doppelt', x: id }); }); }\n            });\n        });\n        ['tag', 'trigger'].forEach(function (a) {\n            var karte = {};\n            el.forEach(function (e) { if (e.art === a && e.name !== '') { (karte[e.name] = karte[e.name] || []).push(e); } });\n            Object.keys(karte).forEach(function (nm) { if (karte[nm].length > 1) { karte[nm].forEach(function (e) { melde('name_doppelt', e, { k: 'd_name_doppelt', x: String(karte[nm].length) }); }); } });\n        });\n        Object.keys(nameKarte.variable).forEach(function (nm) {\n            var l = nameKarte.variable[nm];\n            if (l.length > 1 && nm !== '') { l.forEach(function (e) { melde('name_doppelt_var', e, { k: 'd_name_doppelt', x: String(l.length) }); }); }\n        });<\/p>\n<p>        \/\/ 3. Kanten aufbauen, defekte Verweise melden\n        var hatOrdner = Array.isArray(cv.folder);\n        function kante(von, ziel, art) {\n            if (ziel === von) { return; }\n            von.aus.push({ t: ziel, k: art });\n            ziel.ein.push({ s: von, k: art });\n        }\n        el.forEach(function (e) {\n            var r = e.ref, seen;\n            \/\/ Variablen\n            seen = {};\n            r.vars.forEach(function (nm) {\n                if (seen[nm]) { return; }\n                seen[nm] = true;\n                var ziele = (nameKarte.variable[nm] || []).slice();\n                if (builtinKarte[nm]) { ziele.push(builtinKarte[nm]); }\n                \/\/ {{_event}} ist der feste Verweis auf die eingebaute Variable \"Event\" und braucht keine eigene Variable\n                if (nm === '_event') { if (builtinKarte.Event) { ziele.push(builtinKarte.Event); } else { return; } }\n                if (!ziele.length) {\n                    melde(BUILTIN_BEKANNT[nm] ? 'ref_builtin_aus' : 'ref_variable_fehlt', e, { k: 'd_fehlt_variable', x: nm });\n                } else { ziele.forEach(function (z) { kante(e, z, 'v'); }); }\n            });\n            \/\/ Ausloeser\n            seen = {};\n            r.trig.forEach(function (id) {\n                if (seen[id]) { return; }\n                seen[id] = true;\n                var ziele = idKarte.trigger[id];\n                if (!ziele && BUILTIN_TRIGGER[id]) { return; }   \/\/ eingebauter Trigger, steht nie im Export\n                if (!ziele) { melde('ref_trigger_fehlt', e, { k: 'd_fehlt_trigger', x: id }); } else { ziele.forEach(function (z) { kante(e, z, 't'); }); }\n            });\n            \/\/ Tag-Verweise (Parameter) und Reihenfolge\n            seen = {};\n            r.tags.forEach(function (nm) {\n                if (seen[nm]) { return; }\n                seen[nm] = true;\n                (nameKarte.tag[nm] || idKarte.tag[nm] || []).forEach(function (z) { kante(e, z, 'r'); });\n            });\n            seen = {};\n            r.seq.forEach(function (nm) {\n                if (seen[nm]) { return; }\n                seen[nm] = true;\n                var ziele = nameKarte.tag[nm];\n                if (!ziele) { melde('ref_sequenz_fehlt', e, { k: 'd_fehlt_tag', x: nm }); } else { ziele.forEach(function (z) { kante(e, z, 'q'); }); }\n            });\n            \/\/ Vorlage\n            if (r.tmpl) {\n                var mv = \/_(\\d+)$\/.exec(r.tmpl);\n                var vt = (mv && idKarte.vorlage[mv[1]]) || galerieKarte[r.tmpl];\n                if (!vt) { melde('ref_vorlage_fehlt', e, { k: 'd_fehlt_vorlage', x: e.typ }); } else { vt.forEach(function (z) { kante(e, z, 'p'); }); }\n            }\n            \/\/ Ordner\n            if (hatOrdner && e.ordner !== '' && e.ordner !== '0' && !idKarte.ordner[e.ordner] && e.art !== 'ordner') {\n                melde('ref_ordner_fehlt', e, { k: 'd_fehlt_ordner', x: e.ordner });\n            }\n        });<\/p>\n<p>        \/\/ 4. Zyklen unter Variablen\n        var farbe = {}, inZyklus = {};\n        function tiefensuche(e, pfad) {\n            farbe[e.n] = 1; pfad.push(e);\n            e.aus.forEach(function (ka) {\n                var z = ka.t;\n                if (ka.k !== 'v' || z.art !== 'variable') { return; }\n                if (farbe[z.n] === 1) {\n                    for (var i = pfad.length - 1; i >= 0; i--) { inZyklus[pfad[i].n] = true; if (pfad[i] === z) { break; } }\n                } else if (!farbe[z.n]) { tiefensuche(z, pfad); }\n            });\n            pfad.pop(); farbe[e.n] = 2;\n        }\n        el.forEach(function (e) { if (e.art === 'variable' && !farbe[e.n]) { tiefensuche(e, []); } });\n        el.forEach(function (e) {\n            if (e.art !== 'variable') { return; }\n            if (inZyklus[e.n]) { melde('zyklus', e, null); return; }\n            e.aus.forEach(function (ka) { if (ka.k === 'v' && ka.t === e) { melde('zyklus', e, null); } });\n        });\n        \/\/ Selbstverweis: kante() legt keine Kante auf sich selbst an, daher gesondert\n        el.forEach(function (e) {\n            if (e.art === 'variable' && e.ref.vars.indexOf(e.name) !== -1 && !inZyklus[e.n]) {\n                var schon = (fund.zyklus || []).some(function (f) { return f.e === e; });\n                if (!schon) { melde('zyklus', e, null); }\n            }\n        });<\/p>\n<p>        \/\/ 5. Tags: wann feuern sie wirklich?\n        var live = {};\n        function vorhandeneAusloeser(e) { var n = 0; e.ref.fire.forEach(function (id) { if (idKarte.trigger[id] || BUILTIN_TRIGGER[id]) { n++; } }); return n; }\n        var geaendert = true;\n        while (geaendert) {\n            geaendert = false;\n            el.forEach(function (e) {\n                if (e.art !== 'tag' || live[e.n] || e.pausiert) { return; }\n                var ok = vorhandeneAusloeser(e) > 0;\n                if (!ok) {\n                    ok = e.ein.some(function (ka) { return ka.s.art === 'tag' && live[ka.s.n] && (ka.k === 'q' || ka.k === 'r'); });\n                }\n                if (ok) { live[e.n] = true; geaendert = true; }\n            });\n        }<\/p>\n<p>        \/\/ 6. Von lebenden Wurzeln aus verfolgen\n        var erreicht = {}, stapel = [];\n        el.forEach(function (e) {\n            if ((e.art === 'tag' && live[e.n]) || e.art === 'zone' || e.art === 'client' || e.art === 'transformation') { erreicht[e.n] = true; stapel.push(e); }\n        });\n        while (stapel.length) {\n            var a = stapel.pop();\n            a.aus.forEach(function (ka) {\n                if (ka.t.art === 'tag' || erreicht[ka.t.n]) { return; }\n                erreicht[ka.t.n] = true; stapel.push(ka.t);\n            });\n        }<\/p>\n<p>        \/\/ 7. Aufraeumkandidaten einordnen\n        function referrer(e) {\n            var namen = [], gesehen = {};\n            e.ein.forEach(function (ka) {\n                var nm = ka.s.name || ka.s.id;\n                if (!gesehen[ka.s.n]) { gesehen[ka.s.n] = true; namen.push(nm + (ka.s.pausiert ? ' (' + T.d_pausiert + ')' : '')); }\n            });\n            var rest = namen.length > 3 ? ' +' + (namen.length - 3) : '';\n            return namen.slice(0, 3).join(', ') + rest;\n        }\n        var benutzteOrdner = {};\n        el.forEach(function (e) { if (e.ordner !== '' && e.art !== 'ordner') { benutzteOrdner[e.ordner] = true; } });\n        el.forEach(function (e) {\n            if (e.art === 'tag') {\n                if (e.pausiert) { melde('tag_pausiert', e, null); }\n                else if (!live[e.n]) { melde('tag_ohne_ausloeser', e, e.ein.length ? { k: 'd_nur_von', x: referrer(e) } : null); }\n            } else if (e.art === 'trigger' || e.art === 'variable' || e.art === 'vorlage' || e.art === 'builtin') {\n                if (erreicht[e.n]) { return; }\n                var wohin = e.art === 'builtin' ? 'variable' : e.art;\n                if (e.ein.length === 0) {\n                    melde(e.art === 'builtin' ? 'builtin_ungenutzt' : wohin + '_ungenutzt', e, null);\n                } else {\n                    melde(wohin + '_tot', e, { k: 'd_nur_von', x: referrer(e) });\n                }\n            }\n        });\n        \/\/ Ordner zuletzt: leer, oder leer, sobald alle Elemente darin von der Loeschliste weg sind\n        var weg = {};\n        Object.keys(fund).forEach(function (key) { if (KANDIDAT[key]) { fund[key].forEach(function (f) { weg[f.e.n] = true; }); } });\n        var bleibt = {};\n        el.forEach(function (e) { if (e.ordner !== '' && e.art !== 'ordner' && !weg[e.n]) { bleibt[e.ordner] = true; } });\n        el.forEach(function (e) {\n            if (e.art !== 'ordner') { return; }\n            if (!benutzteOrdner[e.id]) { melde('ordner_leer', e, null); }\n            else if (!bleibt[e.id]) { melde('ordner_leer', e, { k: 'g_ordner_wird_leer', x: '' }); }\n        });<\/p>\n<p>        \/\/ 8. Ergebnis zusammenstellen\n        var befunde = [];\n        ORDNUNG.forEach(function (key) {\n            if (fund[key] && fund[key].length) { befunde.push({ key: key, stufe: STUFE[key], eintraege: fund[key] }); }\n        });\n        var kand = {}, zaehl = {};\n        ARTEN.forEach(function (a) { zaehl[a] = { gesamt: 0, kandidaten: 0 }; });\n        el.forEach(function (e) { zaehl[e.art].gesamt++; });\n        befunde.forEach(function (b) {\n            if (!KANDIDAT[b.key]) { return; }\n            b.eintraege.forEach(function (f) {\n                if (!kand[f.e.n]) { kand[f.e.n] = true; zaehl[f.e.art].kandidaten++; }\n            });\n        });\n        var fehler = 0, kandidaten = 0;\n        befunde.forEach(function (b) { if (b.stufe === 'fehler') { fehler += b.eintraege.length; } });\n        Object.keys(kand).forEach(function () { kandidaten++; });\n        var ordnerName = {};\n        el.forEach(function (e) { if (e.art === 'ordner') { ordnerName[e.id] = e.name; } });\n        var cont = (cv.container && typeof cv.container === 'object') ? cv.container : {};\n        \/\/ Teilexport: der Tag Manager kann auch nur ausgewaehlte Elemente exportieren, dann fehlen viele Variablen\n        var fehlendeNamen = {};\n        (fund.ref_variable_fehlt || []).forEach(function (f) { fehlendeNamen[f.info.x] = true; });\n        var nFehlend = Object.keys(fehlendeNamen).length;\n        var teilexport = nFehlend >= 10 && nFehlend > zaehl.variable.gesamt * 0.5;\n        \/\/ Elemente ohne ID kommen in Exporten aus dem Tag Manager nicht vor (Datei von Hand oder per Werkzeug erzeugt)\n        var ohneId = el.some(function (e) { return (e.art === 'tag' || e.art === 'trigger' || e.art === 'variable') && e.id === ''; });\n        return { befunde: befunde, zahlen: zaehl, kandidaten: kandidaten, fehler: fehler, elemente: el.length, ordnerName: ordnerName, teilexport: teilexport, ohneId: ohneId,\n            container: { name: s(cont.name), oeffentlich: s(cont.publicId) } };\n    }<\/p>\n<p>    \/\/ --- Text lesen ----------------------------------------------------------------\n    function textLesen(text) {\n        var t = String(text);\n        if (t.charCodeAt(0) === 0xFEFF) { t = t.slice(1); }\n        var wurzel;\n        try { wurzel = JSON.parse(t); }\n        catch (fehler) {\n            var pos = \/position (\\d+)\/.exec(String(fehler && fehler.message));\n            var info = '';\n            if (pos) {\n                var p = parseInt(pos[1], 10), zeile = 1, letzter = -1, idx = -1;\n                while ((idx = t.indexOf('\\n', idx + 1)) !== -1 && idx < p) { zeile++; letzter = idx; }\n                info = fmt(T.s_position, { zeile: zeile, spalte: p - letzter });\n            }\n            return { fehler: 'json', info: info };\n        }\n        var cv = holeContainer(wurzel);\n        if (!cv) { return { fehler: 'container' }; }\n        return { cv: cv };\n    }\n\n    \/\/ --- Ausgabe -----------------------------------------------------------------------\n    function el_(id) { return document.getElementById(id); }\n    function knoten(tag, klasse, text) {\n        var n = document.createElement(tag);\n        if (klasse) { n.className = klasse; }\n        if (text !== undefined) { n.textContent = text; }\n        return n;\n    }\n    function status(text, schlecht) {\n        var n = el_('go-status');\n        if (!n) { return; }\n        n.textContent = text;\n        n.className = 'go-status' + (schlecht ? ' go-schlecht' : '');\n    }\n    function detailText(info, ordnerName, e) {\n        var teile = [];\n        if (e.id !== '') { teile.push(fmt(T.d_id, { x: e.id })); }\n        if (e.typ) { teile.push(e.typ); }\n        if (e.ordner !== '' &#038;&#038; ordnerName[e.ordner]) { teile.push(fmt(T.d_ordner, { x: ordnerName[e.ordner] })); }\n        if (info) { teile.push(fmt(T[info.k], { x: info.x })); }\n        return teile.join(' \u00b7 ');\n    }\n    var letztes = null;\n\n    function zeigen(res) {\n        letztes = res;\n        var c = res.container;\n        el_('go-behaelter').textContent = fmt(c.name ? T.behaelter_mit_name : T.behaelter_ohne_name,\n            { name: c.name, id: c.oeffentlich, n: zahl(res.elemente), k: zahl(res.kandidaten), f: zahl(res.fehler) });\n        if (res.teilexport) {\n            el_('go-behaelter').appendChild(document.createElement('br'));\n            el_('go-behaelter').appendChild(knoten('strong', 'go-warnung', T.hinweis_teilexport));\n        }\n        if (res.ohneId) {\n            el_('go-behaelter').appendChild(document.createElement('br'));\n            el_('go-behaelter').appendChild(knoten('strong', 'go-warnung', T.hinweis_ohne_id));\n        }\n\n        var tb = el_('go-zahlen');\n        tb.textContent = '';\n        ARTEN.forEach(function (a) {\n            var z = res.zahlen[a];\n            if (!z.gesamt) { return; }\n            var tr = document.createElement('tr');\n            tr.appendChild(knoten('td', '', T['art_' + a]));\n            tr.appendChild(knoten('td', 'go-zahl', zahl(z.gesamt)));\n            tr.appendChild(knoten('td', 'go-zahl', zahl(z.kandidaten)));\n            tb.appendChild(tr);\n        });\n\n        \/\/ Loeschliste: je Art eine Tabelle mit Name, Ordner, Grund\n        var lw = el_('go-loeschliste');\n        lw.textContent = '';\n        var gruppen = loeschGruppen(res), gesamt = 0;\n        LOESCH_ARTEN.forEach(function (a) {\n            var liste = gruppen[a];\n            if (!liste.length) { return; }\n            gesamt += liste.length;\n            var g = knoten('div', 'go-gruppe');\n            g.setAttribute('data-art', a);\n            var kopf = knoten('div', 'go-gruppe-kopf', T['loesch_' + a] + ' ');\n            kopf.appendChild(knoten('span', 'go-anzahl', '(' + zahl(liste.length) + ')'));\n            g.appendChild(kopf);\n            var wrap = knoten('div', 'go-tabelle');\n            var tab = knoten('table', 'go-loesch');\n            var th = document.createElement('thead'), trh = document.createElement('tr');\n            trh.appendChild(knoten('th', '', T.sp_name));\n            trh.appendChild(knoten('th', 'go-o', T.sp_ordner));\n            trh.appendChild(knoten('th', '', T.sp_grund));\n            th.appendChild(trh); tab.appendChild(th);\n            var tb2 = document.createElement('tbody');\n            liste.slice(0, MAX_ZEILEN).forEach(function (f) {\n                var tr = document.createElement('tr');\n                tr.appendChild(knoten('td', 'go-n', f.e.name || T.ohne_namen));\n                tr.appendChild(knoten('td', 'go-o', res.ordnerName[f.e.ordner] || '\u2013'));\n                tr.appendChild(knoten('td', 'go-g', grundText(f)));\n                tb2.appendChild(tr);\n            });\n            if (liste.length > MAX_ZEILEN) {\n                var trm = document.createElement('tr'), tdm = knoten('td', 'go-mehr', fmt(T.weitere, { n: zahl(liste.length - MAX_ZEILEN) }));\n                tdm.colSpan = 3; trm.appendChild(tdm); tb2.appendChild(trm);\n            }\n            tab.appendChild(tb2); wrap.appendChild(tab); g.appendChild(wrap);\n            lw.appendChild(g);\n        });\n        if (!gesamt) { lw.appendChild(knoten('p', 'go-nichts', T.loesch_nichts)); }<\/p>\n<p>        \/\/ Fehler und Hinweise, die kein Loeschen bedeuten\n        var weitere = res.befunde.filter(function (b) { return !KANDIDAT[b.key]; });\n        el_('go-weitere-block').hidden = !weitere.length;\n        var ul = el_('go-befunde');\n        ul.textContent = '';\n        weitere.forEach(function (b) {\n            var li = document.createElement('li');\n            li.setAttribute('data-befund', b.key);\n            li.appendChild(knoten('span', 'go-marke go-' + b.stufe, T['stufe_' + b.stufe]));\n            var inh = knoten('div', 'go-inhalt');\n            inh.appendChild(knoten('span', 'go-titel', T['b_' + b.key] + ' (' + zahl(b.eintraege.length) + ')'));\n            inh.appendChild(knoten('span', 'go-hilfe', T['b_' + b.key + '_hilfe']));\n            var d = document.createElement('details');\n            d.appendChild(knoten('summary', '', T.zeige_elemente));\n            var liste = knoten('ul', 'go-elemente');\n            b.eintraege.slice(0, MAX_ZEILEN).forEach(function (f) {\n                var z = document.createElement('li');\n                z.appendChild(knoten('span', 'go-art', T['art_' + f.e.art + '_eins']));\n                z.appendChild(document.createTextNode((f.e.name || T.ohne_namen) + ' '));\n                z.appendChild(knoten('span', 'go-nr', detailText(f.info, res.ordnerName, f.e)));\n                liste.appendChild(z);\n            });\n            if (b.eintraege.length > MAX_ZEILEN) {\n                liste.appendChild(knoten('li', 'go-mehr', fmt(T.weitere, { n: zahl(b.eintraege.length - MAX_ZEILEN) })));\n            }\n            d.appendChild(liste);\n            inh.appendChild(d);\n            li.appendChild(inh);\n            ul.appendChild(li);\n        });\n        el_('go-export').hidden = !res.befunde.length;\n        el_('go-ergebnis').hidden = false;\n    }<\/p>\n<p>    \/\/ Reihenfolge, in der im Tag Manager geloescht werden kann (zuerst, was auf anderes verweist)\n    var LOESCH_ARTEN = ['tag', 'trigger', 'variable', 'vorlage', 'ordner', 'builtin'];\n    var GRUND_RANG = { tag_ohne_ausloeser: 0, trigger_ungenutzt: 0, variable_ungenutzt: 0, vorlage_ungenutzt: 0, builtin_ungenutzt: 0, ordner_leer: 0,\n        tag_pausiert: 1, trigger_tot: 1, variable_tot: 1, vorlage_tot: 1 };\n    function loeschGruppen(res) {\n        var g = {}, gesehen = {};\n        LOESCH_ARTEN.forEach(function (a) { g[a] = []; });\n        res.befunde.forEach(function (b) {\n            if (!KANDIDAT[b.key]) { return; }\n            b.eintraege.forEach(function (f) {\n                if (gesehen[f.e.n] || !g[f.e.art]) { return; }\n                gesehen[f.e.n] = true;\n                g[f.e.art].push({ e: f.e, key: b.key, info: f.info });\n            });\n        });\n        LOESCH_ARTEN.forEach(function (a) {\n            g[a].sort(function (x, y) {\n                return (GRUND_RANG[x.key] - GRUND_RANG[y.key]) || x.e.name.localeCompare(y.e.name);\n            });\n        });\n        return g;\n    }\n    function grundText(f) {\n        if (f.key === 'tag_ohne_ausloeser' && f.info) { return fmt(T.g_tag_nur_von, { x: f.info.x }); }\n        if (f.key === 'ordner_leer' && f.info) { return T.g_ordner_wird_leer; }\n        return fmt(T['g_' + f.key], { x: f.info ? f.info.x : '' });\n    }<\/p>\n<p>    \/\/ --- Export ---------------------------------------------------------------------------\n    function csvZelle(x) {\n        var t = s(x);\n        if (\/^[=+\\-@\\t\\r]\/.test(t)) { t = \"'\" + t; }\n        return '\"' + t.replace(\/\"\/g, '\"\"') + '\"';\n    }\n    function csvBauen(res) {\n        var zeilen = [[T.csv_aktion, T.csv_art, T.csv_name, T.csv_ordner, T.csv_hinweis, T.csv_id, T.csv_typ].map(csvZelle).join(',')];\n        var gr = loeschGruppen(res);\n        LOESCH_ARTEN.forEach(function (a) {\n            gr[a].forEach(function (f) {\n                zeilen.push([a === 'builtin' ? T.csv_deaktivieren : T.csv_loeschen, T['art_' + a + '_eins'], f.e.name, res.ordnerName[f.e.ordner] || '',\n                    grundText(f), f.e.id, f.e.typ].map(csvZelle).join(','));\n            });\n        });\n        res.befunde.forEach(function (b) {\n            if (KANDIDAT[b.key]) { return; }\n            b.eintraege.forEach(function (f) {\n                zeilen.push([T['stufe_' + b.stufe], T['art_' + f.e.art + '_eins'], f.e.name, res.ordnerName[f.e.ordner] || '',\n                    T['b_' + b.key] + (f.info ? ': ' + fmt(T[f.info.k], { x: f.info.x }) : ''), f.e.id, f.e.typ].map(csvZelle).join(','));\n            });\n        });\n        return '\ufeff' + zeilen.join('\\r\\n') + '\\r\\n';\n    }\n    function listeBauen(res) {\n        var aus = [], gr = loeschGruppen(res);\n        LOESCH_ARTEN.forEach(function (a) {\n            if (!gr[a].length) { return; }\n            aus.push(T['loesch_' + a] + ' (' + gr[a].length + ')');\n            gr[a].forEach(function (f) { aus.push('- ' + (f.e.name || T.ohne_namen) + '  (' + grundText(f) + ')'); });\n            aus.push('');\n        });\n        return aus.join('\\n');\n    }\n    function kopieren() {\n        if (!letztes) { return; }\n        var text = listeBauen(letztes);\n        function geschafft() { status(T.s_kopiert, false); }\n        function misslungen() { status(T.s_kopieren_fehl, true); }\n        if (navigator.clipboard && navigator.clipboard.writeText) { navigator.clipboard.writeText(text).then(geschafft, misslungen); return; }\n        misslungen();\n    }\n    function csvLaden() {\n        if (!letztes) { return; }\n        var blob = new Blob([csvBauen(letztes)], { type: 'text\/csv;charset=utf-8' });\n        var url = URL.createObjectURL(blob);\n        var a = document.createElement('a');\n        a.href = url; a.download = 'gtm-container-cleanup.csv';\n        document.body.appendChild(a); a.click(); document.body.removeChild(a);\n        setTimeout(function () { URL.revokeObjectURL(url); }, 2000);\n    }<\/p>\n<p>    \/\/ --- Ablauf ------------------------------------------------------------------------------\n    function los(text, meldung) {\n        var eingabe = text === undefined ? el_('go-json').value : text;\n        if (!\/\\S\/.test(eingabe)) { el_('go-ergebnis').hidden = true; status(T.s_leer, true); return null; }\n        var t0 = (window.performance && performance.now) ? performance.now() : Date.now();\n        var gelesen = textLesen(eingabe);\n        if (gelesen.fehler === 'json') { el_('go-ergebnis').hidden = true; status(T.s_json + (gelesen.info ? ' ' + gelesen.info : ''), true); return null; }\n        if (gelesen.fehler === 'container') { el_('go-ergebnis').hidden = true; status(T.s_kein_container, true); return null; }\n        var res = analysiere(gelesen.cv);\n        zeigen(res);\n        var ms = Math.max(1, Math.round(((window.performance && performance.now) ? performance.now() : Date.now()) - t0));\n        status(meldung || fmt(T.s_ok, { n: zahl(res.elemente), ms: ms }), false);\n        return res;\n    }\n    function dateiLesen(datei) {\n        if (!datei) { return; }\n        if (datei.size > MAX_BYTES) { el_('go-ergebnis').hidden = true; status(T.s_zu_gross, true); return; }\n        status(T.s_lesen, false);\n        var fr = new FileReader();\n        fr.onload = function () { el_('go-json').value = String(fr.result); los(); };\n        fr.onerror = function () { status(T.s_lesefehler, true); };\n        fr.readAsText(datei);\n    }<\/p>\n<p>    var BEISPIEL = JSON.stringify({\n        exportFormatVersion: 2,\n        exportTime: '2026-11-03 09:00:00',\n        containerVersion: {\n            path: 'accounts\/1\/containers\/2\/versions\/0', accountId: '1', containerId: '2', containerVersionId: '0',\n            container: { accountId: '1', containerId: '2', name: 'example.com', publicId: 'GTM-EXAMPLE', usageContext: ['WEB'] },\n            folder: [{ folderId: '1', name: 'GA4' }, { folderId: '2', name: 'Old campaign' }, { folderId: '3', name: 'Experiments' }],\n            builtInVariable: [{ type: 'PAGE_URL', name: 'Page URL' }, { type: 'CLICK_TEXT', name: 'Click Text' }, { type: 'PAGE_PATH', name: 'Page Path' }],\n            variable: [\n                { variableId: '1', name: 'Const - GA4 ID', type: 'c', parameter: [{ type: 'TEMPLATE', key: 'value', value: 'G-EXAMPLE123' }], parentFolderId: '1' },\n                { variableId: '2', name: 'DLV - currency', type: 'v', parameter: [{ type: 'INTEGER', key: 'dataLayerVersion', value: '2' }, { type: 'TEMPLATE', key: 'name', value: 'ecommerce.currency' }], parentFolderId: '1' },\n                { variableId: '3', name: 'Const - old pixel ID', type: 'c', parameter: [{ type: 'TEMPLATE', key: 'value', value: '1234567890' }], parentFolderId: '2' }\n            ],\n            trigger: [\n                { triggerId: '1', name: 'All Pages', type: 'PAGEVIEW' },\n                { triggerId: '2', name: 'CE - purchase', type: 'CUSTOM_EVENT', customEventFilter: [{ type: 'EQUALS', parameter: [{ type: 'TEMPLATE', key: 'arg0', value: '{{_event}}' }, { type: 'TEMPLATE', key: 'arg1', value: 'purchase' }] }], parentFolderId: '1' },\n                { triggerId: '3', name: 'Click - spring sale banner', type: 'CLICK', filter: [{ type: 'CONTAINS', parameter: [{ type: 'TEMPLATE', key: 'arg0', value: '{{Click Text}}' }, { type: 'TEMPLATE', key: 'arg1', value: 'Spring sale' }] }], parentFolderId: '2' }\n            ],\n            tag: [\n                { tagId: '1', name: 'GA4 - Google tag', type: 'googtag', parameter: [{ type: 'TEMPLATE', key: 'tagId', value: '{{Const - GA4 ID}}' }], firingTriggerId: ['1'], parentFolderId: '1' },\n                { tagId: '2', name: 'GA4 - purchase', type: 'gaawe', parameter: [{ type: 'TEMPLATE', key: 'eventName', value: 'purchase' }, { type: 'TEMPLATE', key: 'measurementIdOverride', value: '{{Const - GA4 ID}}' }], firingTriggerId: ['9'], parentFolderId: '1' },\n                { tagId: '3', name: 'Pixel - old campaign', type: 'html', paused: true, parameter: [{ type: 'TEMPLATE', key: 'html', value: '<script>track(\"{{Const - old pixel ID}}\");<\\\/script>' }], firingTriggerId: ['3'], parentFolderId: '2' },\n                { tagId: '4', name: 'Floodlight - draft', type: 'fls', parameter: [{ type: 'TEMPLATE', key: 'activityTag', value: 'draft' }] },\n                { tagId: '5', name: 'HTML - consent bridge', type: 'html', parameter: [{ type: 'TEMPLATE', key: 'html', value: '<script>window.cmp = \"{{DLV - consent}}\"; var u = \"{{Page URL}}\";<\\\/script>' }], firingTriggerId: ['1'] }\n            ],\n            customTemplate: [{ templateId: '1', name: 'Unused gallery template', fingerprint: '1', templateData: '___INFO___' }]\n        }\n    }, null, 2);<\/p>\n<p>    window.LW_TEST = window.LW_TEST || {};\n    window.LW_TEST.GTMORPHAN = { T: T, analysiere: analysiere, textLesen: textLesen, holeContainer: holeContainer, los: los, csvBauen: csvBauen, listeBauen: listeBauen,\n        BEISPIEL: BEISPIEL, ORDNUNG: ORDNUNG, ARTEN: ARTEN, loeschGruppen: loeschGruppen, BUILTIN_TRIGGER: BUILTIN_TRIGGER };\n    \/\/ KERN-ENDE<\/p>\n<p>    if (!el_('go-wurzel') || !el_('go-json')) { return; }\n    el_('go-los').addEventListener('click', function () { los(); });\n    el_('go-beispiel').addEventListener('click', function () { el_('go-json').value = BEISPIEL; los(BEISPIEL, T.s_beispiel); });\n    el_('go-leeren').addEventListener('click', function () {\n        el_('go-json').value = ''; el_('go-datei').value = ''; el_('go-ergebnis').hidden = true; letztes = null; status('', false);\n    });\n    el_('go-datei').addEventListener('change', function () { dateiLesen(this.files && this.files[0]); });\n    el_('go-kopieren').addEventListener('click', kopieren);\n    el_('go-csv').addEventListener('click', csvLaden);\n})();\n<\/script><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Liest den Export eines Google-Tag-Manager-Containers im Browser und listet, was den Anschluss verloren hat: Tags, die nie feuern k\u00f6nnen, Trigger und Variablen, die nichts verwendet, \u00fcbrig gebliebene Vorlagen und Ordner, nur von pausierten Tags am Leben gehaltene Elemente und ins Leere zeigende Verweise. Es wird nichts hochgeladen.<\/p>\n","protected":false},"author":1,"featured_media":0,"parent":9283,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"template-tool-base.php","meta":{"footnotes":""},"tags":[92088,92145,92032],"class_list":["post-28768","page","type-page","status-publish","hentry","tag-data-quality-de","tag-google-tag-manager-de","tag-tracking-de"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v28.1 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>GTM-Container aufr\u00e4umen: verwaiste Tags, Trigger und Variablen finden | Lukas Wojcik<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.lukaswojcik.com\/blog\/de\/werkzeuge\/gtm-container-orphan-checker-unused-tags-triggers-variables\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"GTM-Container aufr\u00e4umen: verwaiste Tags, Trigger und Variablen finden | Lukas Wojcik\" \/>\n<meta property=\"og:description\" content=\"Liest den Export eines Google-Tag-Manager-Containers im Browser und listet, was den Anschluss verloren hat: Tags, die nie feuern k\u00f6nnen, Trigger und Variablen, die nichts verwendet, \u00fcbrig gebliebene Vorlagen und Ordner, nur von pausierten Tags am Leben gehaltene Elemente und ins Leere zeigende Verweise. Es wird nichts hochgeladen.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.lukaswojcik.com\/blog\/de\/werkzeuge\/gtm-container-orphan-checker-unused-tags-triggers-variables\/\" \/>\n<meta property=\"og:site_name\" content=\"Lukas Wojcik - Blog\" \/>\n<meta property=\"article:modified_time\" content=\"2026-11-04T18:17:22+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/08\/og-default.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"1200\" \/>\n\t<meta property=\"og:image:height\" content=\"630\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data1\" content=\"3 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/de\\\/werkzeuge\\\/gtm-container-orphan-checker-unused-tags-triggers-variables\\\/\",\"url\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/de\\\/werkzeuge\\\/gtm-container-orphan-checker-unused-tags-triggers-variables\\\/\",\"name\":\"GTM-Container aufr\u00e4umen: verwaiste Tags, Trigger und Variablen finden | Lukas Wojcik\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/#website\"},\"datePublished\":\"2026-11-04T17:06:25+00:00\",\"dateModified\":\"2026-11-04T18:17:22+00:00\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/de\\\/werkzeuge\\\/gtm-container-orphan-checker-unused-tags-triggers-variables\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/de\\\/werkzeuge\\\/gtm-container-orphan-checker-unused-tags-triggers-variables\\\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/de\\\/werkzeuge\\\/gtm-container-orphan-checker-unused-tags-triggers-variables\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Toolbox\",\"item\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/de\\\/werkzeuge\\\/\"},{\"@type\":\"ListItem\",\"position\":3,\"name\":\"GTM-Container aufr\u00e4umen: verwaiste Tags, Trigger und Variablen finden\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/#website\",\"url\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/\",\"name\":\"Lukas Wojcik - Blog\",\"description\":\"\",\"publisher\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/#\\\/schema\\\/person\\\/895f7604f9b6b71aad9bba33af28d0f9\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":[\"Person\",\"Organization\"],\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/#\\\/schema\\\/person\\\/895f7604f9b6b71aad9bba33af28d0f9\",\"name\":\"Lukas Wojcik\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/07\\\/lw-x2.jpg\",\"url\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/07\\\/lw-x2.jpg\",\"contentUrl\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/07\\\/lw-x2.jpg\",\"width\":424,\"height\":636,\"caption\":\"Lukas Wojcik\"},\"logo\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/07\\\/lw-x2.jpg\"},\"sameAs\":[\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\"]}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"GTM-Container aufr\u00e4umen: verwaiste Tags, Trigger und Variablen finden | Lukas Wojcik","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.lukaswojcik.com\/blog\/de\/werkzeuge\/gtm-container-orphan-checker-unused-tags-triggers-variables\/","og_locale":"en_US","og_type":"article","og_title":"GTM-Container aufr\u00e4umen: verwaiste Tags, Trigger und Variablen finden | Lukas Wojcik","og_description":"Liest den Export eines Google-Tag-Manager-Containers im Browser und listet, was den Anschluss verloren hat: Tags, die nie feuern k\u00f6nnen, Trigger und Variablen, die nichts verwendet, \u00fcbrig gebliebene Vorlagen und Ordner, nur von pausierten Tags am Leben gehaltene Elemente und ins Leere zeigende Verweise. Es wird nichts hochgeladen.","og_url":"https:\/\/www.lukaswojcik.com\/blog\/de\/werkzeuge\/gtm-container-orphan-checker-unused-tags-triggers-variables\/","og_site_name":"Lukas Wojcik - Blog","article_modified_time":"2026-11-04T18:17:22+00:00","og_image":[{"width":1200,"height":630,"url":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/08\/og-default.jpg","type":"image\/jpeg"}],"twitter_card":"summary_large_image","twitter_misc":{"Est. reading time":"3 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/www.lukaswojcik.com\/blog\/de\/werkzeuge\/gtm-container-orphan-checker-unused-tags-triggers-variables\/","url":"https:\/\/www.lukaswojcik.com\/blog\/de\/werkzeuge\/gtm-container-orphan-checker-unused-tags-triggers-variables\/","name":"GTM-Container aufr\u00e4umen: verwaiste Tags, Trigger und Variablen finden | Lukas Wojcik","isPartOf":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/#website"},"datePublished":"2026-11-04T17:06:25+00:00","dateModified":"2026-11-04T18:17:22+00:00","breadcrumb":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/de\/werkzeuge\/gtm-container-orphan-checker-unused-tags-triggers-variables\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.lukaswojcik.com\/blog\/de\/werkzeuge\/gtm-container-orphan-checker-unused-tags-triggers-variables\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/www.lukaswojcik.com\/blog\/de\/werkzeuge\/gtm-container-orphan-checker-unused-tags-triggers-variables\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.lukaswojcik.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Toolbox","item":"https:\/\/www.lukaswojcik.com\/blog\/de\/werkzeuge\/"},{"@type":"ListItem","position":3,"name":"GTM-Container aufr\u00e4umen: verwaiste Tags, Trigger und Variablen finden"}]},{"@type":"WebSite","@id":"https:\/\/www.lukaswojcik.com\/blog\/#website","url":"https:\/\/www.lukaswojcik.com\/blog\/","name":"Lukas Wojcik - Blog","description":"","publisher":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/#\/schema\/person\/895f7604f9b6b71aad9bba33af28d0f9"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.lukaswojcik.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":["Person","Organization"],"@id":"https:\/\/www.lukaswojcik.com\/blog\/#\/schema\/person\/895f7604f9b6b71aad9bba33af28d0f9","name":"Lukas Wojcik","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/07\/lw-x2.jpg","url":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/07\/lw-x2.jpg","contentUrl":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/07\/lw-x2.jpg","width":424,"height":636,"caption":"Lukas Wojcik"},"logo":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/07\/lw-x2.jpg"},"sameAs":["https:\/\/www.lukaswojcik.com\/blog"]}]}},"_links":{"self":[{"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/pages\/28768","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/comments?post=28768"}],"version-history":[{"count":4,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/pages\/28768\/revisions"}],"predecessor-version":[{"id":28792,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/pages\/28768\/revisions\/28792"}],"up":[{"embeddable":true,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/pages\/9283"}],"wp:attachment":[{"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/media?parent=28768"}],"wp:term":[{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/tags?post=28768"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}