folder_open Demand Generation

When Singapore ads land on a different host in GA4

Martin Marinov Martin Marinov
15 min read
Topics hostname-mismatchenquiry-eventsgtm-measurement-idsingapore-paid-funnelssession-continuity

A Search click from anywhere in Singapore or a Meta lead form that routes into a booking subdomain should still show as one paid journey when finance asks which campaign funded the WhatsApp enquiry. In Singapore that hop is ordinary: ads point at lp.brand.sg, the form posts to app.brand.sg, checkout lives on a payment host, and the thank-you page sits back on www. If GA4 treats each hostname as a new visit, your Google Ads and Meta conversion columns look healthier than the pipeline, and smart bidding trains on the wrong event.

The job is not “install a linker.” The job is a single client ID, a campaign that survives the hop, and an enquiry event that matches what sales actually books, in SGD, after GST. Everything below is how that mechanism works in GA4 and GTM, what a healthy setup reports, and what you can safely ignore.

GA4 identifies a user with a client ID stored in a first-party cookie on the hostname that set it. Cross a host and the browser will not send that cookie. Without help, the second host mints a new ID, a new session starts, and the UTM (or gclid / wbraid / fbclid) that paid for the click dies on the first page. You still get pageviews. You lose the paid source on the form submit.

GTM’s Google tag (or the GA4 config tag) has a linker. You list every host that belongs to the same journey: www, lp, app, book, pay. On outbound links and form actions that leave the current host, the tag appends a _gl parameter. The destination Google tag reads it, stamps the same client ID, and continues the session if the hit lands inside the session timeout. That is the whole trick. It is not magic across unrelated brands, and it will not stitch a user who opens a PayNow QR in a different app. It only preserves identity when your own markup carries the parameter.

Operators in Singapore usually miss three mechanical details. First, the linker list must match real hostnames, not a marketing “domain family.” book.brand.sg and www.brand.com.sg are different registrable domains; you still add both, and you still need the same Measurement ID on both containers or a shared GTM container that fires the same Google tag. Second, form posts that skip a full navigation (XHR to an API host) never get _gl unless you decorate the request yourself or keep the confirmation URL on a listed host. Third, consent mode in SG still fires cookieless pings when ads storage is denied. Those pings will not carry a stable client ID across hosts. If a large share of paid traffic refuses cookies, your hop will look broken even when the linker is perfect.

Events are separate from the linker. The linker keeps the user. You still need one enquiry definition: generate_lead or a custom whatsapp_click that fires once, on the host where the action completes, with value in SGD if you pass value, and with campaign still in the event’s traffic source. Align that event with the Google Ads conversion and the Meta CAPI event so bidding is not learning from a thank-you pageview on the wrong host. If you need a partner to own that wiring rather than another dashboard, the GA4 cross-domain funnel tracking work is exactly this loop: hosts, linker, enquiry, ad-platform match.

A realistic failure: a growth lead runs Search into lp.brand.sg. The CTA posts to app.brand.sg/enquire. GTM on the landing host is clean. The app host has an old gtag.js with a different Measurement ID and no linker. GA4 shows two sessions, first-touch (direct) / (none) on the enquiry, and Google Ads still counts a conversion from the landing-page tag that fired on button click. Pipeline in HubSpot says organic. Nobody is lying. Three systems counted three different moments.

What a healthy Singapore GA4 property reports after the host change

Open Explorations, set the dimension to Session source / medium and Hostname, and filter to the last 14 days of paid. You want one session per click that completed an enquiry, even if hostname changes mid-path. Session campaign should still be the Search or Meta campaign, not (organic) or (referral) from the second host. If you see your own app host as a referrer eating paid sessions, the linker is not decorating that path.

Key events should fire once per completed enquiry. Duplicate generate_lead on both hosts is worse than a miss: bidding inflates, CPL in-platform looks cheap, and you will argue with finance. Check DebugView on a real hop from a Singapore mobile network (StarHub or Singtel, Chrome), not only a desktop VPN. Mobile is most of paid search clicks; INP on a heavy app host is where tags delay or never fire. Google’s CrUX report (Q1 2025) shows roughly 55-58% of origins globally pass all three Core Web Vitals - Singapore mobile origins tend to lag desktop - so do not assume the booking host is as fast as the landing page.

Directionally, a healthy paid hop in a mid-size SG account looks like this: session continuity on 90%+ of test clicks that complete a form, enquiry count in GA4 within a small band of CRM WhatsApp or form rows (you will never match 100% with ad blockers and iOS), and Google Ads conversions using the same event rather than a separate “button click” proxy. Meta will still disagree on windows. That disagreement is expected. A new session on every hostname is not.

Watch the landing page after the hop with behaviour data, not guesses. If users rage-click the enquire button then bounce on app.brand.sg, the linker can be perfect and you still bought a dead form. HeyLead Insights is the right place to see scroll depth, form abandon, and whether proof above the fold actually gets seen before the host change. Fix the page; do not “optimise” the tag to fire earlier so the metric looks closed.

UTMs still matter on the first URL. The linker preserves identity. It does not invent campaign names. If the ad lands without utm_campaign (or gclid that GA4 can join), the second host cannot recover a source you never sent. Keep a short taxonomy, decorate every paid URL, and do not let the app team strip query strings on redirect.

Not sure where your funnel leaks?
Get a free marketing audit - we review your search, ads, and landing pages and send back what to fix first.
Get a free audit

Reports, toggles, and theatre that do not book the next enquiry

Ignore hostname as a vanity KPI. Seeing two hostnames in a path is normal. The failure is a new session and a lost campaign, not the presence of app.brand.sg in the report. Ignore “users” jumping after a site migration. That is cookie reset, not growth.

Ignore stuffing twenty sister brands into one linker list “just in case.” Unrelated checkout vendors, 3D Secure banks, and PayNow pages you do not control will not read _gl. Listing them creates a false sense of coverage. Decorate only hosts where your Google tag actually loads.

Ignore last-click channel scorekeeping as the CEO answer. Last-click already double-counts across Google and Meta. Cross-domain bugs make that worse. Use the hop test to trust the enquiry event, then talk incrementality and pipeline in SGD. Ignore daily Meta CPA swings at low spend while you debug hosts; learning-phase noise is not a linker issue.

Ignore firing the conversion on the first host “to be safe.” That is how you train bidding on intent to submit, not on the submit. If the app host is slow, speed it up or keep the confirmation on a tagged host. Do not move the conversion earlier to paper over INP.

If the hop is clean and the form still dies, the problem is message match and proof, not GTM. Dedicated landing pages beat dumping paid traffic on the homepage. That is a CRO job sitting next to measurement, not a reason to rebuild the linker every quarter.

A compact hop test you can run on this week’s paid URLs

Use this as an operator pass, not a 40-page measurement strategy. One person with Tag Assistant, a Singapore mobile, and access to GTM can finish it.

DIY playbook

  1. List every hostname in the paid path: ad URL, form action, thank-you, payment if you own it. Write the Measurement ID on each. If they differ, stop and unify before touching linker settings.

  2. In the Google tag, set cross-domain linking with those hosts only. Confirm outbound links and form actions include _gl in a test click from Google Ads preview or a UTM’d URL.

  3. Complete a dummy enquiry. In GA4 DebugView, confirm one client ID, one session, Session campaign still equal to the test campaign, and a single key event on the completing host.

  4. Compare that event to Google Ads and to the CRM or WhatsApp log for the same 48 hours. Investigate duplicates and (direct) enquiries before you change bids.

  5. Repeat on mobile Chrome with a slow 4G profile. If the event vanishes, you have a performance or consent problem, not a “GA4 is broken” story.

  6. Lock the enquiry name so landing, app, Ads, and Meta CAPI use the same definition. Document it where media buyers can find it.

If the app host fails Core Web Vitals, fix LCP and INP before you scale Search. Tags that lose the race on a booking SPA will never look “linked.” Keep paid URLs on dedicated pages whose H1 and meta match the ad, then hop. A second look at GA4 configuration is cheaper than another month of Performance Max learning on split sessions. Performance Max already drives a large share of Search budgets; feeding it (direct) enquiries is how automated bidding inflates spend without better quality.

Prefer to just ask? Message Martin directly on WhatsApp: Chat with us on WhatsApp

FAQs

Do I need cross-domain tracking if lp.brand.sg and www.brand.sg share a parent domain?

Yes if they are different hostnames. Cookies are host-scoped unless you deliberately set a parent-domain cookie, which GA4’s default linker path does not require you to hack. Use the linker list. Do not assume “same brand” is enough.

Will this make Google Ads, Meta, and GA4 match exactly?

No. Different windows, modelled conversions, and view-throughs remain. The hop test only stops you from inventing extra sessions and (direct) enquiries. After that, pick one enquiry definition and live with platform disagreement inside a known band.

What about PayNow, 3D Secure, or a bank host?

You cannot linker-decorate a bank. Keep the user on your tagged confirmation URL after payment, or fire the enquiry when your server knows the payment succeeded and you can still join the client ID you already had. Do not expect _gl to survive a third-party checkout you do not tag.

For that user, yes, identity will not persist in a first-party cookie. You still decorate URLs for users who accept. Do not disable the linker because a slice of traffic is cookieless. Report both, and do not let modelled gaps hide a broken hop for the consented majority.

Should the CRM be the source of truth?

For booked work, yes. GA4’s job is to keep campaign on the session that created the row. If CRM source is always “web form” with no campaign, you have a handoff problem after the hop, not a visualisation problem. Fix it by passing the GA4 client ID to the CRM on form submit - either as a hidden field populated by GTM or via a HubSpot/Salesforce custom property - so every CRM row carries the campaign that sourced it.

Putting it to work

Execution sprint

This week

  1. Pull 30-90 days of performance for cross domain tracking for ads that land on a different host in 2 (Search Console, ads, CRM, or call logs - whatever you have).
  2. Flag the top leak: wrong intent, weak page, slow response, or dirty conversion tracking.
  3. Ship one fix on the highest-traffic money path (page, campaign split, or response rule).
  4. Run the free tools below on that same URL or account and log the findings.

Next 30 days

  1. Expand the fix to the next one or two money paths only after the first one shows cleaner bookings.
  2. Align creative, keywords, or content with the same offer the page now states.
  3. Review booked outcomes weekly; cut anything that still only produces unqualified volume.

This week

  • Export last 14 days of GA4 enquiries by Session source / medium and Hostname. Flag paid rows that land as (direct) or as a referral from your own app host.

  • Write the Measurement ID and GTM container ID for every host in that path. Unify IDs before you edit linker settings.

  • Run three live test clicks (Search UTM, Meta UTM, naked gclid) through form submit on a Singapore mobile.

  • Confirm _gl on the hop and a single key event in DebugView.

  • Build one UTM’d QA URL with the UTM link builder so media and web share the same string.

Next 30 days

  • Align Google Ads and Meta to that same enquiry event, including CAPI if you use it.

  • Fix INP/LCP on the completing host if mobile tests drop events.

  • Stop proxy conversions on the first host.

  • Re-check hostname referral theft after any app release.

Pull those 14 days of paid enquiries by hostname and campaign before you touch bids again. If the break is the hop between ad landing page and enquiry host, HeyLead can own the GA4 and GTM linker, the single enquiry event, and the match to ad-platform conversions so you are not reconciling (direct) sessions every month. Chat with us on WhatsApp

Work with HeyLead
Free marketing audit, or reach Martin directly:
Get a free audit Connect on WhatsApp · martin@heylead.com