You open Google Ads on a Monday in Singapore and the conversion column looks generous. GA4 key events sit well below it. Meta is in another universe. Finance still wants a CPL in SGD they can reconcile against actual spend, GST inclusive. The job this how-to completes is simple: find the second fire, kill it, and leave one conversion object that Smart Bidding and your weekly report can both trust.
Done looks like this. GTM Preview shows one generate_lead (or purchase) per real enquiry. GA4 DebugView shows one matching event with one transaction_id or lead_id. Google Ads records one conversion for that click, not two because the gtag on the thank-you page and the GTM tag both posted. WhatsApp tap, call tap, and form submit are not three conversions for the same person who bounced between a Punggol landing page and a sticky bar.
This is a Singapore stack problem more often than people admit. Sites mix Webflow, WordPress, and a theme that still injects gtag.js. Agencies add Enhanced Conversions. Someone pastes the Google Ads tag “just in case.” Consent Mode v2 sits half-wired. You do not need another dashboard. You need a walk from Tag Assistant to Ads diagnostics that you can finish this fortnight.
What must already be true before you open Tag Assistant
Skip this and you will “fix” a duplicate that is actually two people, or you will pause the only working tag. You need Admin on the GTM container that actually loads on the live domain (check view-source, not the staging workspace). You need Editor on the GA4 property, and you need conversion access in Google Ads, not just campaign view. If a vendor owns the Ads account, get them on the call. Do not debug in a screenshot thread.
You also need a real test path that matches how Singapore enquiries actually happen. Form to thank-you. WhatsApp click on mobile. Call tap on a Central landing page. PayNow is usually offline; do not fire a Google Ads conversion on “clicked PayNow” unless ops confirms money landed. Write down the conversion names and IDs you care about: Google Ads conversion ID/label, GA4 measurement ID, and any Meta pixel if you later compare last-click double counts. Last-click already inflates the same lead across channels. Your GTM bug is on top of that.
Consent is not optional. If ads_storage is denied, Google Ads may still pick up a server or restored tag later and look like a second conversion. Confirm Consent Mode is firing before tags, not after. Confirm the thank-you URL is unique enough to use as a trigger without matching every /thank-you/ variant from an old campaign. If two containers load (GTM-XXXX and a leftover GTM-YYYY from a previous shop), stop. Unpublish the ghost container first. Duplicate conversion debugging on a double-container site is theatre.
If tracking is already this messy, a short pass with Google Tag Manager and events work is cheaper than another month of Smart Bidding trained on inflated leads.
Walk one enquiry from Preview to Ads and stop the second fire
Work one conversion type at a time. Form first. WhatsApp second. Calls last. Mixing them is how teams “fix” generate_lead and accidentally silence call_click. Use a private window, Singapore IP if you can, and the live domain, not a preview URL that never loads the production container.
How-to
Action checklist
- In GTM, open Preview and enter the exact landing URL you advertise (Tampines service page, not homepage). Confirm the container version number matches what you published. If Tag Assistant connects to a different container, you are debugging the wrong house.
- Submit or custom event. Count how many tags fire for Google Ads conversion, GA4 event, and any leftover Universal Analytics or gtag conversion. Two Ads conversion tags on one event is the usual smoking gun in Singapore rebuilds.
- Open each conversion tag. Note trigger type. Page View on thank-you plus Form Submit on the same path is the classic double. Also check a Custom HTML that still contains gtag('event','conversion'...). Theme files and GTM both posting is not “redundancy.” It is two rows in Ads.
- In the GA4 tag, confirm event name, and that you pass a unique event_id or lead_id (form ID + timestamp is fine). Without an ID, GA4 cannot dedupe even if you later send the same event from a server tag. Do not fire generate_lead on both click and thank-you for the same submit.
- Open GA4 DebugView (enable the debug_mode parameter in the GA4 config tag). The GA Debugger Chrome extension reads outbound hits without firing new ones - it is safe to use alongside DebugView. Avoid third-party GTM injection extensions, which can trigger phantom tag fires that look like duplicates. Submit again. You want one generate_lead. If you see two within a second, GTM fired twice or the page loaded GTM twice. Check the dataLayer pushes in Preview: two identical pushes means the form library and your listener both push.
- In Google Ads, go to Goals, then Conversions, open the conversion action, and check Tag setup / Diagnostics. Look for “tag installed more than once” and for secondary tags on the same domain. Note the conversion ID and label. Search the GTM container and the site source for that label. Every extra paste is a candidate for unpublish, not “pause in GTM and leave in the theme.”
- Turn on Enhanced Conversions only once, in one place. If GTM sends user-provided data and the Ads tag on the page also hashes email, you can get messy matching, not a clean extra conversion, but diagnostics will look haunted. Pick GTM. Remove the page-level tag.
- For WhatsApp, fire on the click of wa.me or the official widget, once, with a dedicated event name (whatsapp_click). Do not also fire generate_lead. Sales will still close in the thread. Ads should optimise to the click only if that is the real KPI; otherwise keep it as a secondary action and primary on qualified form.
- For tel: links, same rule. One call_click. If a call-tracking vendor also posts a Google Ads conversion when the call is answered, you now have click plus answered. That can be correct if you only import answered calls. It is a duplicate if GTM already counted the tap. Choose one source of truth.
- Publish a workspace that only removes the extra tag or tightens the trigger. Test three live conversions. Wait for Ads to show them (not always instant). Compare count to your three tests, not to last week’s inflated baseline. Then, and only then, re-enable Smart Bidding if you had paused it because CPL looked “too good.”
Free tools - try these yourself
Slow thank-you pages make people mash submit. That is a product bug that looks like a tag bug. If INP is ugly, tags can fire on retry. Check the page with the Core Web Vitals checker before you rewrite half the container. Session recordings in HeyLead Insights show the double-submit and the second thank-you load that Preview will also count if you are not watching the user.
Get a free marketing audit - we review your search, ads, and landing pages and send back what to fix first.
Get a free audit

Where Singapore stacks still post the same lead twice
The extra gtag in header.php or the Webflow project settings survives every GTM cleanup. You unpublished the GTM conversion tag, felt virtuous, and Ads still doubled because the native tag never left. View-source after publish. Search for AW- and G- IDs. If both GTM and a hardcoded snippet remain, you are not done.
SPA and “multi-step” forms fire page_view on every step. A trigger of Page Path contains /contact/ fires four times. Switch to a dataLayer event the form pushes once on success. If the developer cannot add that push, use a Unique Event ID and a trigger that requires Form Submit plus a success CSS class, not a generic click on Submit.
Consent banners that reload the container after accept can replay tags that already fired in denied state and then again in granted state, depending how you configured wait_for_update. Test both: first visit with deny, first visit with accept, and accept-after-deny. Google Ads conversion tags should not fire twice when the user flicks the toggle.
Imported CRM conversions plus on-site tags is the quiet one. HubSpot or a local CRM posts an offline conversion when the WhatsApp enquiry is marked qualified, while GTM already counted the form. If sales cycle is days, you will not see it in Preview. You will see it in Ads as two conversions with different timestamps. Pick site-side for bidding or CRM-side for bidding. Reporting can still show both if you mark one as secondary. Do not feed both to tCPA.
Performance Max “drives the bulk now,” as buyers keep saying, and it is greedy for conversion volume. Duplicate leads make PMax look cheap in SGD until sales says half the “leads” are the same Woodlands form sent twice. Clean conversion setup beats adding another campaign. You already lose signal to ad blockers and privacy; do not donate more noise.
If you want a second pair of eyes after you isolate the extra AW- label, that is the moment to use Google Tag Manager and events help rather than shipping another workspace guess.
FAQs
Why do Google Ads conversions exceed GA4 key events in Singapore accounts?
Ads often still has a page-level tag plus GTM, counts view-through, or imports CRM conversions on top of the site event. GA4 may also filter duplicates if you send event_id. Compare like with like: same 7-day click window, same conversion action, test three controlled submits before you argue about last month.
Should generate_lead fire on WhatsApp and the form?
No. Use separate events. Primary conversion should be the action sales will actually work (usually form or answered call). WhatsApp is a strong Singapore enquiry path, but stacking it on the same conversion action trains bidding on taps, not qualified jobs.
Does Consent Mode v2 cause duplicate conversions?
It can replay tags if the banner reloads GTM after grant. It can also look like “missing” conversions when ads_storage is denied. Test deny, accept, and toggle. Do not add a second conversion tag “to catch consented users.”
Can I leave the old gtag “just as backup”?
No. Backup is the duplicate. One delivery path: GTM. One conversion action per real outcome. Enhanced Conversions once.
How long until Smart Bidding behaves after a fix?
Give it enough new, clean conversions rather than a calendar superstition. Google targets roughly 50 conversions in the past 30 days before Smart Bidding exits learning - if your clean volume is below that, expect the learning badge and slower optimisation regardless of data quality. If you had been feeding doubles, expect CPL in SGD to rise toward reality, then quality to improve. That rise is the bug leaving, not the channel dying.

Free tools
DIY free tools for this playbook
Run these on the pages and campaigns this article covers, then fix what they flag before you scale spend or content volume.
Run these on this playbook
If the checklist shows a leak you cannot close in-house, request a free marketing audit.
Putting it to work
Execution sprint
This week
- Pull 30-90 days of performance for how to debug duplicate conversions in gtm ga4 and ads (Search Console, ads, CRM, or call logs - whatever you have).
- Flag the top leak: wrong intent, weak page, slow response, or dirty conversion tracking.
- Ship one fix on the highest-traffic money path (page, campaign split, or response rule).
- Run the free tools below on that same URL or account and log the findings.
Free tools for this sprint
Next 30 days
- Expand the fix to the next one or two money paths only after the first one shows cleaner bookings.
- Align creative, keywords, or content with the same offer the page now states.
- Review booked outcomes weekly; cut anything that still only produces unqualified volume.
This week
-
View-source the live domain and list every AW-, G-, and GTM- ID.
-
Preview one form submit and screenshot every conversion tag that fired.
-
Search the container and theme for the Google Ads conversion label; delete extras, do not pause and forget.
-
Send three live test leads with UTMs from the UTM link builder and match them in Ads and GA4 DebugView.
-
Split WhatsApp and call taps onto their own event names if they currently share generate_lead.
Next 30 days
-
Turn Enhanced Conversions on in GTM only and remove page-level hashing.
-
Decide site-side versus CRM import as the only primary for bidding.
-
Re-test after the next site publish so a rebuild does not re-inject gtag.
-
Watch PMax and Search CPL against sales-accepted leads in SGD, not the old inflated column.
Pull the last 14 days of Google Ads conversion actions next to GA4 key events and your CRM unique enquiries, then walk the first mismatch with Preview the same day. HeyLead can take the duplicate-fire hunt in GTM, GA4, and Google Ads off your plate, including the leftover AW- snippets Singapore rebuilds leave in the head, so bidding trains on one real lead. Chat with us on WhatsApp
Free marketing audit, or reach Martin directly:
Get a free audit Connect on WhatsApp · [email protected]