Home / Guides

A GTM click trigger the next deploy will not break

Why a copied CSS selector stops matching, which attributes are worth anchoring to, and the Tailwind class that silently makes a selector invalid.

Most GTM work is the same small task on repeat: something on the page has to become an event. You open DevTools, right-click the button, Copy selector, paste it into a Click trigger, publish. Three weeks later the trigger stops firing and nobody notices until the monthly report looks thin.

Why copied selectors rot

What to anchor on, in order

  1. An ID, if it is a real one. An ID is the shortest possible selector and cannot be ambiguous. Reject it if it starts with a digit, contains a run of eight hex characters, or carries a framework prefix — those are generated, not authored.
  2. An attribute that exists to be targeted. data-gtm, data-testid, name, aria-label. Someone put these there on purpose; a redesign changes the styling and leaves them alone. One caveat: if the value contains { or a quote, you are looking at an un-rendered template, and it will not be the same tomorrow.
  3. Classes, sparingly. Two or three meaningful ones, never the state classes — hover, active, focus, valid, invalid come and go while the user interacts with the page, so a selector built on them matches only sometimes.

The Tailwind trap

Tailwind class names contain characters that mean something in CSS. hover:bg-blue-500 has a colon; md:w-1/2 has a colon and a slash. Written into a selector unescaped, the result is not a selector that fails to match — it is invalid CSS, and GTM's Click trigger simply never fires. There is no error anywhere.

Escaped, it is .hover\:bg-blue-500, and it works. This is the single most common reason a hand-written selector does nothing on a modern site.

Stop as soon as it is unique

The best selector is the shortest one that matches exactly one element on the page. Every ancestor you add past that point is another element that can be restructured. Checking the match count as you build — and stopping the moment it reaches one — produces something far more durable than a full path from body.

The element you clicked is not the element GTM sees

You click a button; the browser reports the deepest element under the cursor, which is usually the <span> holding the label. GTM's Click Element is that span. A trigger written against the button therefore fires only when someone happens to click the padding around the text.

The fix is to climb to the nearest genuinely clickable ancestor — an <a>, a <button>, or something with role="button" — and anchor there. GTM's Click Element variable supports matches CSS selector, which tests the clicked element against the selector, and a descendant selector covers the children automatically.

Tag Master after an element was picked: the generated CSS selector button[data-testid=
The picker chose the stable attribute over the two class names that were also on the button. The test code underneath is runnable, and it is where the comma-versus-dot decision gets made.

Tag Master builds the selector for you: click the element in the page and it climbs to the clickable parent, prefers the stable attributes over generated classes, escapes what needs escaping, and stops at the shortest unique path — then hands you the trigger condition and a variable to copy.

Getting the value out

A click trigger usually needs a number as well: the price on the card you clicked. That means a Custom JavaScript variable that finds the price element relative to the clicked one and parses the text — which is where locale bites. 1.648,25 TL and $1,648.25 both have to become 1648.25, and a naive parseFloat turns the first into 1. Strip everything that is not a digit or a separator, then decide which separator is the decimal one by looking at what follows it.

Verify before you publish

  1. Click the element and confirm exactly one match on the page.
  2. Click a sibling — a different product card, the second button in the row — and confirm it does not match, unless you meant it to.
  3. Click the text inside the element, not just its edge. This is the test that catches the deepest-element problem.
  4. Reload and repeat. Anything that only matched before the reload was matching generated markup.

Related guides

Try it on your own site

Tag Master is free, needs no account, and collects no data.

Add to Chrome — Free