Webclat / GTM Practice

Why does dynamic phone number swapping (call tracking) stop working after I move the script into GTM?

Quick answer

DNI scripts typically need to run and finish swapping numbers before a user can see or click them, but GTM's default triggers often run at a different point than the DNI vendor's script expects, or the script's own number-matching logic depends on finding phone numbers already rendered in the DOM at the exact moment it executes. Moving it into GTM changes execution timing relative to page render, which is very often the entire cause.

Why this happens

Dynamic Number Insertion scripts work by scanning the rendered page for phone number patterns or specific placeholder elements and swapping them for a session-specific tracking number. When the DNI script was a plain script tag placed directly in the page, it ran at a predictable point relative to the numbers being in the DOM. Once moved into GTM as a Custom HTML tag, it now runs on whatever trigger you assigned - if that is DOM Ready but the numbers are rendered by a slower client-side component that mounts later, the DNI script scans before the numbers exist and finds nothing to swap.

Fix it

  1. Confirm the symptom: check the browser console for any error or "no numbers found" warning the DNI vendor's script logs - most log something diagnostic if their scan comes back empty, confirming a timing problem versus a script-loading problem.
  2. Check what trigger the Custom HTML tag is using and compare against when the phone number elements actually appear in the DOM - if they are rendered by a component that mounts after DOM Ready, move the tag's trigger to Window Loaded, or a custom event your framework pushes once the content has rendered.
  3. If the DNI vendor's script supports a callback or re-scan function, call it again after your framework's content renders, rather than relying purely on trigger timing to get it right once.
  4. Confirm the Custom HTML tag has "Support document.write" disabled unless the DNI script specifically requires it - older DNI scripts using document.write behave differently, and are often blocked outright, when injected asynchronously via GTM.
  5. If the script depends on session or referrer data to pick the correct tracking number, confirm that data is still available at the point GTM fires the tag - it may have been reliably present at page load but lost by the time an async GTM tag runs, especially after an SPA route change.

How to verify it worked

Load the page from a real ad click (or a URL carrying the campaign parameters your DNI vendor expects) and visually confirm the displayed phone number is the swapped tracking number, not the static default. Place a test call and check the DNI vendor's own dashboard or call log to confirm it was attributed to the correct source - GTM Preview alone only proves the Custom HTML tag executed, not that the DOM swap itself succeeded.

Still stuck after working through this?

Send us what you are seeing in Preview and the Network tab. We trace GTM containers for a living and can usually tell you what is actually happening in one look.

Ask a GTM Engineer