Open a Singapore Google Ads account and you’ll often find Smart Bidding chasing generate_lead while sales is still counting WhatsApp threads, missed +65 call-backs, and HubSpot forms that never made it into GA4. The job this guide finishes is narrower than a full analytics rebuild. You want three named enquiry events (form submit, click-to-call, chat or WhatsApp) firing once, marked as key events, and usable as conversion actions in Google Ads, so PMax and Search stop optimising to pageviews and thank-you-page reloads.
“Done” looks like this: DebugView shows one event per real enquiry, Realtime does not double-count on GST invoice thank-you pages, and a test PayNow or demo form from a Tampines landing page lands as the same event name in GA4 and in Ads. You’re not chasing a prettier dashboard. You’re feeding first-party signals into bidding while CPCs stay unforgiving and 20%+ of conversion data already leaks to blockers and consent.
This is a how-to for marketing owners at companies selling into Central, East, West, North, and North-East traffic, not a consumer tutorial. If you run aircon servicing, SaaS demos, or condo fit-out leads, the mechanics are the same: name the enquiry, fire it once, prove it in GA4, then import it.
What has to be live in your Singapore stack before you write a tag
Skip this and you’ll ship a tag that “works” in Preview and lies in production. You need a GA4 property you actually own (not a contractor’s sandbox), a GTM web container published on every template that can take an enquiry, and admin on the Google Ads account that spends SGD against those pages. If consent is collected (PDPA banners are common on SG corporate sites), Consent Mode v2 has to be configured so analytics_storage and ad_storage resolve before you treat a click as a conversion. Fire before consent and you’ll inflate key events; fire never and Smart Bidding starves.
Name the three enquiry types in writing before GTM. Form means a completed submit that sales will work (not a newsletter footer). Call means a tap on a tel: link that starts with +65, or a tracked number if you use one. Chat means WhatsApp (wa.me or the click-to-chat widget), not a buried Messenger icon nobody uses. If your team also takes PayNow screenshots as “leads,” do not map that to generate_lead until someone in sales confirms it is a real pipeline event. Ambiguous names are how last-click reports count the same person three times across channels.
You also need a destination you can test without bothering customers: a staging form, a test +65 number, a dummy WhatsApp. Turn on GA4 DebugView and GTM Preview on the same browser. If Core Web Vitals are already weak (fewer than half of mobile origins pass all three Core Web Vitals thresholds), extra tags will make INP worse on mobile, and mobile is most of paid search clicks. Check the landing page before you pile on listeners. If you want a specialist to own the measurement layer rather than a one-off tag dump, HeyLead’s GA4 work is built around this exact enquiry mapping.
Last prerequisite: agree who owns the event dictionary. If paid media marks generate_lead on button click and the site team marks it on thank-you, you will never reconcile CRM and GA4. One owner, one name, one trigger per enquiry type.
Wire form, call, and WhatsApp events in GTM, then mark them in GA4
Work in this order. Do not start in the GA4 admin UI inventing events you have not fired from the page. GTM is the source of truth for clicks and submits; GA4 only receives, marks as key events, and (later) shares with Ads.
How-to
Action checklist
- In GTM, create a Form Submission trigger only if the form does a real HTML submit. Many Singapore WordPress and HubSpot embeds do not. If the form is AJAX, use a Custom Event or Element Visibility on the success message instead of the native Form trigger, or you will never see the hit.
- Create a GA4 Event tag named generate_lead (or a tighter name like form_enquiry_sg). Event name must be lowercase with underscores. Add parameters: lead_type = form, page_location, and a form_id if you have more than one form (contact vs demo vs aircon booking).
- For calls, add a Click trigger: Click URL contains +65 or 65. Fire a second GA4 Event tag with the same event name generate_lead and lead_type = call. Do not invent a second key event unless sales treats phone as a different funnel stage. One key event with a parameter is easier to import into Ads.
- For chats, trigger on Click URL contains wa.me or api.whatsapp.com, or on the CSS selector of your widget button. Same event name, lead_type = whatsapp. WhatsApp enquiry is the default chat in SG. Do not also fire generate_lead on every chat widget load.
- Add a blocking exception: if the click is a header number that also sits in the footer, use a unique CSS class so one tap is one event. Duplicate links are the usual reason DebugView shows two hits for one tap on a page with both a header and a footer tel: link.
- Publish to a GTM environment, open Preview, submit the test form, tap the test tel link, tap WhatsApp. Confirm the dataLayer push or the GA4 Event tag fires once. Then open GA4 DebugView (Admin, DebugView) on the same session and confirm generate_lead arrives with lead_type populated.
- In GA4, go to Admin, Events. Mark generate_lead as a key event. Do not also mark form_submit, click, and page_view as key events. Key events are what bidding and most exec reports treat as “the conversion.”
- Create an exploration or a simple report filtered by lead_type. You should see form vs call vs whatsapp split. If 90% of events are click with empty lead_type, the parameter never left GTM.
- In Google Ads, import the GA4 key event as a conversion action. Set the count to One if a person can submit and then WhatsApp in the same session and sales only wants one conversion. Set to Every if you truly want both. This is the decision that stops last-click double counting across tools.
- Turn on Enhanced Conversions (the unified toggle) if you collect email or phone on the form. That first-party hash is how you claw back some of the 20%+ signal loss from blockers. Do not send raw numbers in event parameters.
- UTMs so GA4 session source/medium is not (direct) for branded Search. Use a builder, then paste into Ads final URLs. Broken UTMs make a perfect event look like organic.
- Watch Realtime for 24 hours after publish. Compare three real enquiries your team already logged (CRM, WhatsApp Business, call recording) against GA4. If GA4 is higher, you have a duplicate tag. If GA4 is lower, the AJAX form or SPA route never hit the trigger.
Free tools - try these yourself
After the tags are live, sit on the landing page like a sceptical visitor. If the form is long, proof is below the fold, or the WhatsApp button overlaps the submit, people bounce before your event can fire. Session recordings and heatmaps in HeyLead Insights show whether the miss is tracking or UX: rage clicks on a broken HubSpot iframe, scroll depth that never reaches the form on Woodlands mobile traffic, or a sticky bar covering the tel link. Fix the page if the event is correct and conversion rate is still thin.
Keep parameters boring. lead_type, form_id, and page_location are enough for a marketing lead. Do not send full message body from a chat widget into GA4. You do not need it for bidding, and you do not want PDPA questions over a debug export.
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 GA4 setups usually fire the wrong enquiry
The broken version of this setup is almost always “we have generate_lead.” Then you open DebugView and find it on newsletter signup, on every tel: in the footer firing twice, and on a thank-you page that also has a GTM History Change trigger. Ads then optimises to cheap newsletter volume while WhatsApp (the actual sales queue) is invisible. Performance Max will happily spend into that signal. Accounts where conversion actions match worked enquiries - not clicks - consistently outperform those that don’t, regardless of the ROAS benchmark you use.
SPA and multi-step forms are the next stall. A quote wizard on a landed-home renovation site changes the URL without a full load. Native Form Submission never fires. Teams add a page_view key event as a workaround. Bidding then treats every step as a lead. The fix is a dataLayer push from the developer on the success state only, with a Custom Event trigger. If you cannot get that push, Element Visibility on the exact success copy (“We’ll WhatsApp you within 15 minutes”) is the fallback. Test it in Preview with the overlay, not in production on a live HDB servicing form.
Consent and duplicate containers round out the mess. Two GTM snippets (theme plus a plugin) double every event. A banner that defaults to denied, then a tag that ignores consent, creates a gap between what Ads reports and what GA4 shows after modelled conversions. Align Consent Mode, then re-test. If you use Google tags in both GTM and the GA4 “install with a snippet” path, pick one. Two collectors is how you get two key events for one form.
If form friction is the real leak, do not keep adding events. Watch recordings, shorten fields, move proof next to the submit. Traffic that never converts cannot be fixed in Admin, Events.
What marketing leaders are seeing
In one B2B services account we audited, generate_lead fired on the thank-you page and on the HubSpot submit. PMax scaled spend for two weeks. Sales said the extra volume was newsletter signups from a Woodlands campaign. Deleting one tag made CPL look worse for a week, then the pipeline number finally matched GA4.
In one home services account we audited, call clicks were 4× form submits on mobile. Half were accidental taps on a sticky +65 bar. Requiring a longer press and setting lead_type = call dropped call events by about 40%, and the remaining calls actually booked.

FAQs
Should form, call, and WhatsApp be three different GA4 event names?
Usually no. One event (generate_lead) with lead_type is easier to mark as a single key event and import into Google Ads. Split names only if bidding must treat a booked call differently from a WhatsApp tap, and sales agrees.
Do I need a Google Ads conversion tag as well as GA4?
If you import the GA4 key event, do not also fire a duplicate Ads conversion tag on the same submit. Two tags on one form is the classic double-count. Use Enhanced Conversions on the imported action instead of a second pixel.
What if most enquiries arrive on WhatsApp and never hit the website form?
Track the click that starts the chat. You will not see the message quality in GA4. Compare a sample of wa.me clicks to WhatsApp Business labels weekly. If click-to-chat quality is poor, tighten the landing offer rather than adding more events.
How long until Smart Bidding uses the new key event?
Give it enough conversion volume to exit learning. Swapping the conversion action mid-flight on a high-spend PMax campaign will reset learning. Switch on a contained Search campaign first, confirm 7-14 days of clean counts, then point PMax at the same action.
Does GST or PayNow need its own event?
Only if finance treats a PayNow as closed revenue you want as a purchase event, separate from enquiry. Do not map PayNow screenshots to generate_lead. That mixes pipeline with payment confirmation and wrecks CPL.
Putting it to work
Execution sprint
This week
- Pull 30-90 days of performance for Singapore Leads: Forms, Calls, and WhatsApp (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
-
Write the three enquiry definitions (form, +65 call, WhatsApp) and who owns the event name.
-
Confirm one GTM container, Consent Mode, and DebugView access.
-
Build the three triggers and one generate_lead tag with lead_type.
-
Mark the key event in GA4 and compare three real CRM or WhatsApp enquiries to DebugView.
-
Import into Google Ads with count = One unless sales wants every channel touch.
-
Run UTMs through the UTM link builder on active ads.
Next 30 days
-
Turn on Enhanced Conversions for form emails and phones.
-
Kill duplicate tags, newsletter mapped as leads, and double tel: clicks.
-
Watch post-click behaviour where forms stall, then tighten the page.
-
Only then point Performance Max at the cleaned key event.
Pull last week’s WhatsApp threads, answered +65 calls, and form rows, then sit them next to GA4 key events until the counts tell the same story. If the counts still don’t match after the checklist above, the gap is almost always a duplicate container or an AJAX form with no dataLayer push - HeyLead’s GA4 audit covers both. Chat with us on WhatsApp
Free marketing audit, or reach Martin directly:
Get a free audit Connect on WhatsApp · [email protected]