Tutorial: Agreeing a GTM Naming Convention and Enforcing It on an Existing Container

Contents
A tag manager container has no folders that mean anything, no types that group, and no search that understands structure. It has a list, sorted alphabetically, and that list is the entire interface for finding things.
Which makes the first word of every name the only grouping mechanism there is. A convention is therefore not tidiness – it is the difference between finding a tag in three seconds and reading through three hundred lines.

Why the Name Is the Only Structure
Folders exist and are worth using, but they change nothing about the two places where a name is actually read: the search box and the reference inside another element. A trigger appears under a tag by name, a variable appears in a field by name, and neither of them shows which folder it lives in.
The list itself is the second reason. Sorting is alphabetical and cannot be changed, so anything that should appear together has to begin with the same characters. That is a constraint rather than a preference, and a convention that ignores it produces names that are descriptive and useless.
A third point settles the direction of the scheme: names sort left to right. The most important distinction therefore belongs first, and the most specific detail last. Which distinction is most important is the one question worth discussing before writing any names down – for most containers it is the platform, because that is what a question usually starts from.
A Convention That Survives Three Hundred Tags
Three segments, separated consistently, are enough. More segments look more precise and get abbreviated by whoever is in a hurry.
Tags <Platform> - <Kind> - <What>
GA4 - Event - add_to_cart
GA4 - Config - Alle Seiten
Meta - Event - purchase
Sonstige - Conversion Linker
Ausloeser <Kind> - <Condition>
CE - add_to_cart
PV - kasse
Klick - cta-kopfbereich
Variablen <Source> - <Name>
DLV - ecommerce.items
JS - artikelliste
Const - GA4 Mess-ID
LT - laendercode
The three-letter abbreviations for trigger and variable kinds are deliberate. They are short enough that the interesting part of the name stays visible in a narrow column, and they are the same words the interface itself uses, so nobody has to learn a second vocabulary.
Two rules keep it working under pressure. The separator is always the same – a space, a hyphen, a space – because a mixture of hyphens and colons breaks the sort in a way that is hard to see. And the last segment matches the technical name exactly: a tag for the add_to_cart event is called add_to_cart, not Add to Cart, so a search for the event name finds the tag, the trigger and the variable in one go.
Auditing the Existing Container
The container export is a JSON file with three arrays in it, and checking three hundred names against a scheme is a short script rather than an afternoon.
import json, re, sys
VORSATZ = {
"tag": re.compile(r"^(GA4|Meta|Ads|LinkedIn|TikTok|Sonstige) - "),
"trigger": re.compile(r"^(CE|PV|Klick|Formular|Timer|Sichtbar|Sonstige) - "),
"variable": re.compile(r"^(DLV|JS|Const|LT|URL|Cookie|Sonstige) - "),
}
daten = json.load(open(sys.argv[1]))["containerVersion"]
for art, muster in VORSATZ.items():
posten = daten.get(art, [])
fehlt = [p["name"] for p in posten if not muster.match(p["name"])]
print(f"{art:9s} {len(posten) - len(fehlt):3d} von {len(posten):3d} nach Schema")
for name in sorted(fehlt):
print(f" {name}")
What comes out of a first run is usually two thirds compliant and one third not, and the non-compliant third splits into three groups worth treating differently.
Names that are simply old follow the scheme after a rename and nothing else happens. Names that describe something no longer in use – a tag for a platform that was dropped – are a finding of their own and belong in the list of things to delete rather than rename. And names containing a person or a date – Test Anna 03.02. – are the ones to look at first, because they usually mark something that was never meant to stay.
Renaming Without Breaking a Reference
This is where the asymmetry sits, and it is the reason a bulk rename needs to be done in a specific order.
Tags and triggers are referenced internally by a numeric identifier. Renaming them changes nothing anywhere else, and a trigger that fires a tag keeps firing it under any name.
Variables are different, because a variable is referenced by its name in double braces. The interface knows about the references it created and updates them when a variable is renamed – a field that contains {{DLV - artikel}} follows along. What does not follow is every place where those braces are text rather than a field: inside a custom HTML tag, inside a custom JavaScript variable, inside a template parameter. Those are strings, and a rename leaves them pointing at a name that no longer exists.
# alle Namensverweise im Export finden, bevor umbenannt wird
grep -o '{{[^}]*}}' export.json | sort | uniq -c | sort -rn | head -30
Running that before and after is the whole safety net. The list of referenced names should be identical except for the ones deliberately changed, and every difference that was not intended is a reference that now resolves to nothing – which in a tag produces an empty value rather than an error.
Doing It in One Workspace
A rename of two hundred elements is one change with two hundred entries, and it belongs in a workspace of its own for three reasons.
The version that comes out of it is a single entry in the container history, which is what a colleague looking at the change list six months later needs to see. A workspace shared with a functional change makes both of them harder to review and impossible to revert separately.
The preview mode still works inside the workspace, so the whole container can be exercised once before publishing – and the specific thing to exercise is every custom HTML tag, because those are where the string references live.
And the container can be exported from the workspace before publishing, which gives a file to compare against the one from before. Two exports, one grep, and the question of whether anything broke is settled without guessing.
Keeping It That Way
A convention decays at the speed at which people add things in a hurry, and three habits slow that down more than a document does.
The audit script belongs somewhere it runs by itself. Once a month against a fresh export is enough, and the output is short: either everything matches, or it names the three elements added since the last run.
The scheme belongs in the container rather than in a wiki. A note element – a tag that never fires, named 0 - Namensschema so it sorts to the top – carries the convention where the person naming something is already looking.
And the deletion list from the audit is worth acting on rather than filing. A container with forty paused tags nobody recognises is a container where the convention will be ignored again, because the list is already unreadable – and the fastest way to make a list readable is to make it shorter.