Tracking every enquiry without slowing the page down
Ad platforms need to know which taps became enquiries, but tag managers are heavy. How AHA’s landing page defers its tags, queues every event and signals success separately.
The problem
Tag Manager slows the first screen, and a tap on Submit isn’t a lead.
The fix
Load tags on the first tap, queue events in the data layer, and signal success separately.
- First tap
- when tags load, 7 s at most
- 4 + 1
- tap events, plus one for success
- 1
- thank-you URL as a backup signal
Ads learn from what you tell them. When a landing page reports each enquiry, the ad platforms can look for more people like the ones who enquired. But the reporting itself, Google Tag Manager and the tags it loads, is some of the heaviest code a page can carry. On AHA’s ads landing page I wanted both: a fast first screen on a phone, and a record of every step that matters.
Tags wait for the visitor
Tag Manager is where the tracking lives. GA4, Google’s analytics, is set up inside it, and the page warms up connections for the Meta, LinkedIn and Microsoft Clarity tags that load through it. None of that helps draw the first screen, so none of it loads up front.
Instead, Tag Manager loads on the visitor’s first mouse movement, scroll, touch, key press or click, or after 7 seconds, whichever comes first:
// Simplified from the page’s head
window.dataLayer = window.dataLayer || []; // the queue exists first
['mousemove', 'scroll', 'touchstart', 'keydown', 'click']
.forEach(e => addEventListener(e, loadGTM, { once: true, passive: true }));
setTimeout(loadGTM, 7000); // loadGTM runs only once
The first version, on 24 June, sat at the bottom of the page and waited for the first interaction or 3 seconds after the page finished loading. Two days later the loader moved to the top of the page, the fallback became 7 seconds, and mouse movement joined the triggers. The goal, as the project notes put it, was PageSpeed performance. Like the rest of the page, it was built with Claude Code.
Events wait in a queue
Deferring Tag Manager raises an obvious question: what happens to a tap before it arrives?
The answer is the data layer, a plain list on the page that Tag Manager reads. The page creates it before anything else runs, and every event is pushed onto it. If Tag Manager isn’t there yet, the event simply waits in the list. When Tag Manager loads, it works through everything already queued. And because a click is one of the triggers, the click that wakes Tag Manager is also one of the first events it reads.
Moving the loader to the top did that job: the list now exists before any button can be tapped.
Four events with plain names
The page pushes four events:
contact_us_clickfrom each of the three buttons that jump to the form;whatsapp_clickfrom the floating WhatsApp button;submit_button_clickandgenerate_lead, both from the submit button.
On 25 June these were gtag() calls, GA4’s own function. But GA4 lives inside Tag Manager here, so by 26 June they had become plain data-layer pushes. The page now says only what happened, and Tag Manager decides where it goes. The catch is that each event needs a matching tag in Tag Manager, or it goes nowhere.
Tag Manager adds its own triggers on top: page views, scroll depth at 25, 50, 75 and 90%, and taps on the phone number link.
A tap is not a lead
Look again at generate_lead. It fires when the submit button is tapped, before the browser has checked a single field and long before the CRM has anything. A visitor who taps three times on a half-filled form makes three “leads”.
So on 9 July I added a signal at the other end. The form script pushes form_submit_success only after the server endpoint answers OK, then opens a thank-you page. That page:
- loads Tag Manager straight away, since the visitor has already enquired;
- is marked
noindex, nofollow, so it stays out of search results; - gives the ad platforms a plain address to count as a conversion, one that still works if a custom event is set up wrong.
On the main website, a success screen that appeared when the save had failed taught a related lesson the hard way: A thank-you page that lied.
Checking it on the live page
The release checklist ends the same way every time: a hard refresh on the live page, then Google’s Tag Assistant to watch the expected events arrive. A deferred loader can break quietly, and an event that never fires looks exactly like a quiet day.
What I’d keep, and change
- Create the data layer first, load the tags later. Nothing is lost while the page draws.
- Let the page describe events and Tag Manager route them.
- Name events for what happened. I’d rename the tap-time
generate_leadand keep “lead” for the success event, so no platform optimises for taps. - Back custom events with an address. A thank-you page is the conversion that survives a broken tag.
- Test on the live page. That’s where caching and tags finally meet.