May 7, 2025
What to do if Element Visibility Trigger is not working in Google Tag Manager
Element Visibility trigger is one of my favorite things in Google Tag Manager. Whenever an element appears on the screen (after scrolling or some other interaction), you can use that as a condition to fire your tags.
One of the use cases is form tracking with the Element Visibility trigger, which I use when other form tracking options are not working properly. However, there are several tricky things you need to know about this trigger. Otherwise, you might get stuck.
In this blog post, I’ll mention several reasons why Element Visibility Trigger is not working in Google Tag Manager (and how to fix that).
Observe DOM changes checkbox
The trigger contains a very powerful checkbox called Observe DOM Changes. It must be used depending on how the element appears on the screen.
If you expect an element to appear on the screen after scrolling, then KEEP THIS CHECKBOX DISABLED.
If, on the other hand, a particular element appears on the screen without scrolling (e.g., a popup just jumps onto the screen), then the Observe DOM changes checkbox must be enabled.

Incorrect CSS Selector
When you use the Element Visibility trigger, you need to instruct Google Tag Manager which exact elements are you interested in. Currently, there are two selection methods to choose from:
- ID
- CSS Selector

If an element (that you want to track) contains an ID, use the first option. How can you know whether the element has an ID? Do the right-click on it > Inspect and check that. Here’s an example of an element that contains an “id” attribute.

The tricky part comes when people start using a much more advanced option, called CSS Selector. To be able to use it, you need to know at least the very basics of it. Here’s a good resource to start. I HIGHLY recommend that you read that guide before using CSS Selectors in your Element Visibility trigger.
Speaking of the most common mistakes I’ve noticed among those who are just starting:
- If you want to target an element with a certain class, then that class must start with a dot, for example, .someClass
- If you want to target based on several classes, then add a dot before every class and leave no empty spaces between them, e.g., .someClass.someOtherClass .
- If you want to target an element by a class that is a direct child of another element with another class, use the following syntax: .parentElementClass > .childElementClass (obviously, those class names are fake and should be replaced with the real ones.
To learn the most common use cases for CSS selectors, head over here.
Selected “ID” but trying to enter CSS selector
Another example of a common mistake is when GTM users select the ID selection method but try to enter CSS selector in the field below.

If you select the ID method, then just enter the ID (without dots or anything else). If you try to enter a CSS Selector, then change the Selection Method to CSS Selector. Looking at the screenshot above, looks like that’s a CSS selector (because a dot must be added in front of a CSS class).
Once again, read this guide if you are not familiar with CSS Selectors for GTM.
Element’s height is 0
This case is not met very often but is still worth mentioning. In fact, that’s something that I was reminded of quite recently. Here’s my case:
There were a bunch of embedded forms (in an iframe) on a website and we wanted to track the moment when they appear on the screen. For some reason, instead of adding some additional attributes to the iframe window, he added a <div> element with a certain value right above that iframe.
As a result, the code looked like this:
<div data-type="form-impression-measurement"></div> <iframe src="https://www.somedomain.com></iframe>
Even though such an element (<div>) exists on a page, there was no style assigned to it, meaning that the element was kinda invisible to a regular visitor and that div’s height is 0px.
When the element’s height is 0px, the Element Visibility trigger will not capture its appearance because, well, that element is still invisible.
What’s the solution? Ask a developer to set that element to be at least 1 or 2 px high. There are various ways to achieve that, for example:
- via style attribute (not vary scalable), <div style=”height:1px” data-type=”form-impression-measurement”>
- with a CSS class, <div class=”for-measurement” data-type=”form-impression-measurement”> and then defining what that class means in the CSS file:
.for-measurement {
height: 1px;
}
Beyond height: 0px, another CSS property can also prevent an element from being considered ‘visible’ by the trigger, especially if the ‘Observe DOM changes’ setting isn’t perfectly aligned with how the element becomes visible.
And that property is display: none. Elements with this style are completely removed from the page layout and are not visible. The trigger generally won’t fire until the display property changes.
Element Visibility trigger not working? Final words
From what I’ve seen, these issues are the most popular when it comes to the Element Visibility Trigger not working in Google Tag Manager.
If none of these tips helps, most likely, it’s issue #2 that you are dealing with (not knowing CSS Selectors well enough). To solve that, I highly recommend reading Simo’s guide.
If that does not help, let me know in the comments, and I’ll take a look. Just please don’t forget to provide as much information as you can. If you want help, you need to put some effort into describing the issue. Here’s a blog post that will help you get better GTM help.

9 COMMENTS
hi,
thank you for your article.
unfortunately, it did not solve the problem of DOM changes on the specified CSS selector.
The CSS selector is correctly defined as .className in GTM, and when the pages loads, the tag gets fired; however, when I remove the element with the specified selector, nothing happens; same thing when I re-add the element with the specified selector; the number of times fired stays at 1.
I need to fire element visibility for an element once on a page, but that should include virtual pageviews too because my application is a Single Page Application.
How do I go about it?
Hello, I face the same issue. I have selected trigger visibility with "once per page" and even though I am firing page_view events after I navigate to a different page, the page is not reset, and next time I visit the same page, the visibility does not fire anymore.
This use case seems to work (reseting the visibility after navigating away from the page) with "once per element", but I can't really explain why. I would love to know the reason.
Thanks
You are probably dealing with a single page application that loads content dynamically. In that case, Element visibility trigger will not work for you properly.
I am tracking a pop up (on click) using Element Visibility, it works but the GTM failed to capture most of the times. Is like 10 times of click on this pop up, only 2 -3 will be captured and the rest they are not capture.
Difficult to comment without seeing the actual website. Maybe your trigger is configured incorrectly, maybe something else.
Hi Julius, thank you for the post!
Unfortunately, I wasn't able to solve the issue. Traying to track a popup view, using ID method. In Preview Mode, I see firing triggers this way:
✖ _event equals gtm.elementVisibility
🗸 _triggers matches RegEx (^$|((^|,)66045501_98($|,)))
What do you think could it be the issue?
It means that you clicked the wrong data layer event on the left side of the preview mode. Your condition for "elementVisibility" trigger was not met.
Hi Julius, i have an issue:
I want to track promotional banners at an ecommerce website. I've used CSS Selectors to pick the .slick-active element, which is a different element whenever the promotional banner being exhibited changes. I've tested the selector on the console and it works properly. I've checked the "Observe DOM Changes" option and configured it to fire once per element. But still, whenever the page loads, the trigger fires for the first banner and the first banner only, once it changes to the second banner it doesn't fire anymore.
What could be the problem here?