Troubleshooting · part of GTM not working

Your GTM element visibility trigger is not firing

The element is on screen, the selector looks right, and the trigger does nothing.

Element visibility is the most configurable trigger in Google Tag Manager and therefore the one with the most ways to be quietly wrong. Three of its defaults cause most of the failures, and one of them is hidden under Advanced. Here are the seven causes, in the order worth checking them.

  1. The element is added after the page loads, and Observe DOM changes is off

    Check: Open the trigger and expand Advanced. Is Observe DOM changes ticked? Then ask whether the element exists in the initial HTML: view source, not the inspector, and search for it. Modals, cookie banners, lazy-loaded sections, anything rendered by React or Vue after hydration, and anything injected by a third-party script all fail this test.

    Fix: Tick Observe DOM changes. It is the only setting that tracks elements added as the DOM changes, it is off by default, and it is hidden under Advanced, which is why this is the single most common cause. Google notes that monitoring many elements can affect performance, so keep the selector narrow when you turn it on.

  2. The ID does not exist, is duplicated, or is generated fresh on each load

    Check: If the selection method is ID, confirm the element genuinely has that exact id attribute in the live HTML. Then search the page for the same ID a second time.

    Fix: ID selects a single element. If the ID appears twice, only the first match fires the trigger, so the one you care about may never be reached. Frameworks that generate IDs per render, such as the auto-generated ones ending in random characters, are worse: the ID you configured on Tuesday does not exist on Wednesday. Switch to a CSS selector targeting something stable, such as a data attribute.

  3. The CSS selector matches nothing, or matches the wrong thing

    Check: Paste the selector into the browser console inside document.querySelectorAll() and count the results. Zero means the trigger can never fire. A large number means you are monitoring far more than you intended.

    Fix: Narrow it to the smallest stable thing that identifies the element, and prefer a data attribute added for the purpose over a class name, which a designer will rename without telling you. Google's own guidance is to keep selectors narrow or use ID where possible.

  4. The element never reaches 50% visible

    Check: Look at Minimum Percent Visible on the trigger. The default is 50%. Then look at the element on a laptop and on a phone: is half of it ever in the viewport at once?

    Fix: A tall element, a full-width section, or a long form can scroll through the viewport without 50% of it ever being on screen simultaneously, particularly on mobile. Lower the threshold to something the element can actually achieve, or target a smaller child element such as the heading rather than the whole section.

  5. A minimum on-screen duration was set and is never met

    Check: Is Set minimum on-screen duration enabled, and what value? It is off by default, so if it is on, somebody chose it.

    Fix: The time is cumulative across the page view, so separate glances do add up, but a multi-second threshold on an element people scroll straight past will still never fire. Either lower it or accept that it is measuring sustained attention rather than appearance, which may be what you wanted but is rarely what people configure by accident.

  6. The firing frequency is wrong for what you are measuring

    Check: Which of the three options is selected: once per page, once per element, or every time an element appears?

    Fix: Once per page fires on the first matched element only, so a page with six matching cards reports one. Once per element gives you one per element. Every time fires on each reappearance, including when the user scrolls back up, which inflates counts if you wanted impressions rather than views. Pick deliberately: each one produces a different number from the same page.

  7. The element is not in the document GTM is running in

    Check: Is the element inside an iframe? Chat widgets, embedded booking tools, hosted payment steps and some consent banners are all iframes.

    Fix: A container runs inside the document it was loaded into, and an iframe is a separate document, so an element inside a third-party iframe is not visible to your trigger at all. Nothing you change in the trigger will fix it. Either the embedded tool has its own event API you can listen to, or the measurement has to happen on their side.

The three defaults to check first

  • Observe DOM changes: off. Under Advanced. Anything added to the page after load is invisible to the trigger until this is on.
  • Minimum Percent Visible: 50%. Half the element has to be in the viewport at once, which a tall section may never manage on a phone.
  • Minimum on-screen duration: off. Good, but if somebody switched it on, the element has to stay visible that long, counted cumulatively across the page view.

Between them these account for most element visibility triggers that look correctly configured and never fire.

A note on testing it

Preview mode will show you whether the trigger evaluated and why it did or did not fire, which is exactly what it is good for. What it cannot tell you is whether the same thing happens for a real visitor who declined the cookie banner, uses a smaller screen, or loads the page on a connection slow enough that the element arrives after the trigger has stopped looking. Once it works in Preview, confirm it on the live site in a fresh browser, which is covered in how to check if GTM is working.

A trigger that never fires is one kind of silent failure. Tracking Auditor finds the rest: tags with no trigger at all, tags paused with active triggers, consent gates blocking tags that look live, and events arriving twice. A free audit every month.

Run a free audit →

Go deeper

For the other six reasons a container looks broken, see Google Tag Manager not working. For container health more widely, from orphaned tags to consent gating, the GTM audit guide. If the tag fires but the event never appears in reports, that is a parameter problem, and if it appears twice, see why GA4 events fire twice. More symptoms are indexed at Fix GA4.

FAQs

Why is my GTM element visibility trigger not firing?

The most common cause by a distance is that the element is added to the page after load while Observe DOM changes is switched off. That setting is the only one that tracks elements added as the DOM changes, it defaults to off, and it sits under Advanced where people do not look. After that: an ID that does not exist or is duplicated, a CSS selector matching nothing, and the 50% visibility default on an element too tall to reach it.

What is the default minimum percent visible in GTM?

50%. An element has to have half of it in the viewport before the trigger fires, which a tall section or a long form may never achieve on a phone. You can lower it, or target a smaller child element instead.

Does the element visibility trigger work on elements loaded by JavaScript?

Only if Observe DOM changes is enabled. Without it the trigger looks at the elements present when it starts watching, so anything a framework or third-party script injects afterwards is invisible to it.

Why does my trigger fire once when several elements match?

The firing frequency is set to once per page, which fires on the first matched element and then stops. Switch it to once per element for one per element, bearing in mind that with duplicate IDs only the first match counts.

Can an element visibility trigger see inside an iframe?

No. The container runs in the document it was loaded into, and an iframe is a separate document, so elements inside a third-party embed are out of reach regardless of the selector. You need an event from the embedded tool itself.

The selection methods, firing frequencies, the 50% default, the on-screen duration behaviour and the Observe DOM changes setting are all from Google’s own documentation for the Element Visibility trigger, checked on 21 October 2026.