Google Tag Manager
Google Tag Manager container audit
Twenty-nine checks every GTM container should pass before it is handed off to a client.
A GTM container is one of the highest-leverage surfaces in any ad-tech setup. It sits between the site and every measurement endpoint (Google Ads, GA4, Meta CAPI, TikTok Events, whatever else). When it works, attribution works. When it drifts, every downstream report drifts with it.
AdLint runs 29 checks against any GTM container export. The checks cover four things: tags that should fire and do not (missing Conversion Linker, missing Consent Settings), tags that should not fire and do (debug-named tags in production, duplicate conversion tags), data-layer hygiene (variables bound to the wrong paths, missing currency, mixed Data Layer Version), and operational governance (naming conventions, unused triggers, stale tags, container size approaching the workspace limit).
Each finding links to a defensible explanation, a fix, and a copy-pasteable citation for client deliverables. No upload, no account. Everything runs in your browser.
critical (5)
Conversion Tags Missing Error Handling
criticalYou have Google Ads conversion tags wired to click or form-submit triggers, with no "Wait for Tags" setting and no event callback. When a user clicks Submit, the browser starts navigating to the next page immediately. The conversion request often doesn't finish before navigation kills it. That conversion is gone, and you'll never know it happened.
Conversion Linker Sequencing
criticalYou have a Conversion Linker in the container. Good. But it isn't declared as a setup tag for your Google Ads conversion tags. On a fast page load the linker happens to fire first and everything works. On a slow load, a redirect-heavy checkout, or a consent banner mid-page, the order flips. The conversion tag fires before the GCLID has been written to `_gcl_aw`, and that conversion ships without click context. The dashboards still look fine.
E-commerce Data Layer Structure
criticalYour purchase event isn't pushing a dataLayer object that conversion tags can actually read. Either `value`, `currency`, `transaction_id`, or the `items` array is missing, or the whole thing is shaped wrong. Tags still fire on the confirmation page, but the value they ship is zero or undefined. Google Ads counts the conversion. It just thinks every order is worth $0.
Enhanced Conversions Missing User Data
criticalEnhanced Conversions is turned on for one of your conversion tags. The user-data fields are empty. So the feature is on in name only. Google Ads receives the conversion but none of the hashed identifier that makes Enhanced Conversions worth turning on in the first place. Match rate sits at zero. The team probably thinks the feature doesn't work.
Missing Google Ads Conversion Linker
criticalYour container is missing the Conversion Linker. Every Google Ads conversion on the site is firing without the GCLID. Whenever the click lands on one page and the purchase happens two pageviews later (basically always), the click context is gone. Google still counts the conversion. It just can't tell you which ad caused it.
warning (17)
Circular Tag Dependencies
warningGTM's Tag Sequencing feature lets one tag declare another as a setup tag that must fire first. a cycle in those declarations: Tag A is configured to fire after Tag B, but Tag B is configured to fire after Tag A. GTM resolves cycles by ignoring one side of the dependency, so the actual ordering is non-deterministic and likely wrong.
Google Ads Tags May Fire Without Consent
warningSome of your Google Ads tags have no Consent Settings configured. They fire on every page load regardless of whether the user granted `ad_storage`. In GDPR or UK GDPR jurisdictions, that's a compliance problem first and a measurement problem second. Data from consent-denied users should never have left the browser.
GTM Container Size and Tag Count
warningGTM has documented workspace size limits and operational thresholds that this container is approaching or exceeding. A container near the size limit cannot be published once it crosses the threshold, and a container with hundreds of tags becomes slow to audit and increases page-load weight for every site visitor.
Cross-Domain Tracking Misconfigured
warningThis container has a Conversion Linker tag, but its auto-link domains list does not cover every domain in the conversion funnel. When a user clicks from the marketing site to a separately-hosted checkout, booking engine, or payment processor, Google Ads cannot connect the conversion back to the ad click. The GCLID lives in a cookie scoped to one domain and never reaches the other.
DataLayer Variable Dependencies
warningTag parameters in this container reference variables using `{{Variable Name}}` syntax, but the named variables do not exist in the container's User-Defined Variables. At runtime, GTM resolves these placeholders to empty strings, so the tags fire with missing data. Currency, transaction ID, user identifiers, or whatever the unresolved variable was supposed to carry.
Inconsistent Data Layer Variable Naming
warningData Layer Variables in this container use mixed naming patterns. Some use `dot.notation`, others `camelCase`, others `snake_case`. The dominant pattern accounts for less than 80% of variables, which means the dataLayer is being read inconsistently across the container.
Mixed Data Layer Versions
warningThis container has Data Layer Variables configured on both Version 1 and Version 2. The two versions resolve nested dataLayer paths differently. Version 2 can read into nested objects like `ecommerce.value`, while Version 1 cannot. Mixed-version containers produce two variables that read the same path but return different values, which breaks downstream conversion tracking in ways that are very hard to debug.
Preview/Debug Tags in Production
warningOne or more tags with debug-style names (containing "debug," "test," "preview," "staging," or "dev") are firing on the production All Pages trigger. These tags were almost certainly created during implementation and forgotten. They can ship duplicate conversions, leak implementation details to third-party endpoints, or interfere with real diagnostics.
Duplicate Data Layer Variable Paths
warningThis container has multiple GTM Data Layer Variables bound to the same dataLayer path. For example, both `DLV - value` and `DLV - purchase revenue` reading `ecommerce.value`. This is a maintenance hazard: when someone updates one variable's version or default value, the other copy continues to feed downstream tags, producing inconsistent behaviour across tags that should be reading the same business value.
Excessive Custom HTML Tags
warningA high share of tags in this container are Custom HTML. Arbitrary JavaScript injected at runtime instead of native, audited GTM tag templates. Custom HTML tags are powerful but expensive: each one is unaudited code with full DOM access, runs on the main thread, and is harder for the next engineer to understand than a native template would be.
Excessive Tag Sequencing Depth
warningA tag in this container has a sequencing chain more than three setup tags deep. Tag A depends on B which depends on C which depends on D. At each link, GTM must wait for the upstream tag to complete before firing the next one, which serializes work that often does not need to be serial and can add hundreds of milliseconds to time-to-fire.
Invalid CSS Selectors in Triggers
warningOne or more Click or Element Visibility triggers use CSS selectors with syntax errors. Unclosed brackets, malformed pseudo-classes, or unescaped special characters. Invalid selectors do not match anything at runtime, so the trigger never fires and any tag dependent on it is dead.
Missing Data Layer Variables
warningConversion tags in this container reference fields that are not exposed as GTM Data Layer Variables. Typically `ecommerce.value`, `ecommerce.currency`, or `ecommerce.transaction_id`. The tags still fire on the right trigger, but the fields they read resolve to empty, which means the conversion is reported with no value. The dashboard shows a count; the bidding signal is noise.
Overlapping Trigger Conditions
warningThis container has multiple triggers configured with the same type and identical filter conditions. For example, two Custom Event triggers both filtering on `event equals purchase`. The duplicates do not cause direct measurement problems by themselves, but they multiply tag fires when a tag is wired to both of them.
Performance-Heavy Triggers
warningOne or more triggers in this container fire so frequently that they add measurable CPU and main-thread work to every page. The most common offenders are Timer triggers with intervals under 5 seconds and History Change triggers that fire on every browser-state push, regardless of whether the change is meaningful.
Remarketing Tag Issues
warningOne or more remarketing tags in this container (Google Ads remarketing or Floodlight counter) are missing a required parameter. Typically the conversion ID or tag ID. The tag fires, but the request lacks the identifier Google needs to attach the visitor to the correct audience list.
Trigger Conflicts
warningOne or more tags in this container fire on multiple triggers of different types. For example, both a Page View trigger and a Custom Event trigger. The tag will fire on every match across all triggers, which can produce duplicate conversions or fires in contexts the tag was not designed for.
info (7)
Documentation Completeness
infoGTM lets you add a Notes/Description field to every tag, trigger, and variable. AdLint scores this container below 50% on documentation completeness. The majority of assets have no description, which makes every audit, handoff, and change harder than it needs to be.
GTM Naming Convention Violations
infoGTM does not enforce naming conventions, so containers accumulate inconsistent names over time. "GA4 Event," "ga4-purchase," "Purchase (GA4)," "PurchaseEvent_v2" all coexisting. The technical impact is zero. The operational impact is significant: every new audit, handoff, or change requires re-reading every tag to understand what it does, and findings become harder to defend to clients because they cannot tell which tag handles which business event.
Orphaned Tag Sequence References
infoOne or more tags in this container have Tag Sequencing relationships pointing to setup tags or blocking tags that have been deleted. The reference is left behind in the configuration but resolves to nothing at runtime, which means the intended sequencing simply does not happen.
Potentially Stale Tags
infoOne or more tags in this container have names containing words like "old," "legacy," "backup," "deprecated," "temp," or "test." The names are operational signals from previous engineers that these tags are unfinished business. Kept around because someone was not sure they could be safely removed.
Unused Data Layer Variables
infoThis container defines Data Layer Variables that no tag or trigger references. They exist in Workspace → Variables but are never read at runtime. The variables themselves cost nothing, but they are usually a signal that something was abandoned half-implemented, and they make audits harder by adding noise to the variable list.
Unused Triggers
infoThis container has triggers in Workspace → Triggers that no tag uses for firing or blocking. The triggers do not affect runtime behaviour, but they clutter the Triggers screen and usually indicate something was left unfinished.
Unused Variables
infoThis container has user-defined variables. Data Layer Variables, Custom JavaScript, Lookup Tables, and so on. That no tag or trigger uses. The variables exist in Workspace → Variables but never get evaluated at runtime.
Run a free Google Tag Manager audit
AdLint runs every check on this page against your export in seconds. Nothing uploaded. Nothing logged. Everything stays in your browser.
Open the Google Tag Manager auditor