Loading tutorials…
Loading tutorials…
If your funnel crosses domains — marketing site to app, storefront to external checkout, landing page to booking platform — every cross-domain hop loses attribution unless you configure this. Most sites haven't.
Who this is forOwners whose user journey crosses two or more domains: e.g., acme.com → app.acme.com, or storefront → checkout.acme.com, or landing page → Calendly. If you can't tell where conversions originated because reports show "acme.com / referral" for half your traffic, this is the fix.
What you'll need
Step 1
Write down every domain a user can land on or pass through. Subdomains count if they're independent (different tracking).
Example: marketing site = acme.com. App = app.acme.com. Checkout = checkout.acme.com. Help docs = docs.acme.com. Status page = status.acme.com (hosted on a third party). Booking = calendly.com (third party, won't be in GA4 directly).
Identify which domains you control AND want measured. Third-party tools you can't install GA4 on (Calendly, Stripe checkout, ConvertKit hosted forms) need different strategies (covered in step 7).
Identify the primary domain (the one users see most often) — this is what we'll anchor cross-domain tracking around.
If you have 5+ domains, simplify where possible. Subdomains under the same registered domain (acme.com) are easier to track than entirely separate domains (acme-app.io and acmehq.com).
Step 2
GA4 → Admin → Data Streams → Web → Configure tag settings → Configure your domains. Add each domain in scope.
Go to GA4 → Admin → Data Streams. Click the Web stream that covers your funnel.
Click Configure tag settings (gear icon, top right of the stream details panel).
Click Configure your domains.
Click Add condition. Enter the first domain (e.g., acme.com — without the www prefix is fine).
Click Add condition again for each additional domain. Include all variants: acme.com, app.acme.com, checkout.acme.com.
Don't add third-party domains you don't control — Calendly, Stripe, ConvertKit. Those have separate strategies.
Save. The Google Tag will now treat clicks between these domains as a single session and pass the GA4 client_id via URL parameter.
Step 3
GA4 → Admin → Data Streams → Web → Configure tag settings → List unwanted referrals. This prevents internal domain crossings from being counted as 'referral' traffic.
Same path: GA4 → Admin → Data Streams → Web stream → Configure tag settings.
Click List unwanted referrals.
Add each domain in your funnel that should NOT be counted as a referrer when traffic moves to your main domain.
Example: when a user moves from app.acme.com → acme.com, without this list GA4 will mark the session as a referral from app.acme.com — which is misleading because it's the same business.
Add: app.acme.com, checkout.acme.com, docs.acme.com, etc. The traffic that flows between these is internal and should preserve its original source/medium (the channel they originally arrived through).
Save. New traffic going forward will use the corrected source/medium.
Step 4
Use DebugView + the cross-domain URL parameter (_gl) to confirm client_id continuity.
In GA4 → Admin → DebugView, open the panel.
In an incognito browser tab (with no ad blockers), visit domain 1 (e.g., acme.com).
In DebugView, you should see a session start. Note the client_id at the top of the session panel.
On domain 1, click a link to domain 2 (e.g., a "Start free trial" button that goes to app.acme.com/signup).
Inspect the URL when you land on domain 2. You should see a query parameter like ?_gl=... — that's GA4's cross-domain linker passing the client_id.
In DebugView, the session should continue (not restart) and the client_id should match what you saw on domain 1.
If the session restarts on domain 2 with a new client_id, cross-domain config isn't working. Check that the GTM/Google Tag is installed correctly on both domains.
Step 5
Ensure all ad platforms have auto-tagging enabled so their click IDs (gclid, fbclid, msclkid) survive cross-domain hops alongside client_id.
In Google Ads → Admin → Account settings → Auto-tagging: toggle ON. This adds gclid to ad-click destination URLs.
In Microsoft Ads (Bing): Settings → Final URL → enable Auto-tagging. Adds msclkid.
Meta Ads automatically passes fbclid when click tracking is enabled (default).
For LinkedIn, TikTok, and other platforms: confirm their auto-tagging equivalent is enabled.
Why this matters: when GA4 passes client_id between your domains via _gl, the ad-platform click IDs also need to survive that hop. Auto-tagging puts them in the URL; the cross-domain linker preserves them through redirects.
Step 6
Add a Conversion Linker tag in GTM. It stores ad click IDs in first-party cookies so they survive even when URL parameters get stripped.
In GTM, create a new tag of type Conversion Linker.
Leave default settings. Trigger = All Pages.
Save and publish.
What it does: when a user arrives with gclid, fbclid, or msclkid in the URL, the Conversion Linker stores it in a first-party cookie. If the user then navigates to a page where the URL no longer has the click ID, GA4 (and Google Ads/Meta) can still pull it from the cookie.
This is especially valuable for funnel paths where users land on a marketing page (URL has gclid) but convert on an app page 30 minutes later (URL doesn't have gclid). Without Conversion Linker, attribution is lost.
Step 7
For Calendly, Stripe Checkout, Typeform, etc., use webhooks + Measurement Protocol to fire GA4 events server-side with the original client_id.
Some funnel steps happen on third-party domains where you can't install GA4 (Calendly, Stripe Checkout, Typeform, Tally).
For Calendly: enable their GA4 integration (Calendly → Integrations → Google Analytics 4 → connect). They'll fire calendar booking events to your property when a booking completes. You need to pass your GA4 client_id to Calendly via URL parameter (?client_id={{GA4_CLIENT_ID}}) — get the client_id from a GTM variable.
For Stripe Checkout: use the Stripe webhook on payment_intent.succeeded to call the GA4 Measurement Protocol from your server, sending a purchase event with the customer's client_id (passed as metadata when creating the session).
For Typeform/Tally: same pattern — push the GA4 client_id as a hidden field, capture it on submit, fire a GA4 server-side event with it.
This is the advanced version. If you're not comfortable with server-side webhooks, hire a specialist for this part — it's the highest-leverage attribution work for funnel sites.
Common mistakes
Not adding domains to "Configure your domains"
What goes wrong: Every cross-domain hop is a new session with a new client_id. Funnel reports show users dropping off at each domain boundary even when they're completing the full funnel. Conversion rates look 40-60% lower than reality.
How to avoid: GA4 → Admin → Data Streams → Web → Configure tag settings → Configure your domains. Add every domain in your funnel.
Forgetting to exclude internal referrers
What goes wrong: Traffic moving from app.acme.com → acme.com is logged as referral / app.acme.com. Your top traffic source in reports is your own subdomain. You can't see the true acquisition channels.
How to avoid: List unwanted referrals in the same Configure tag settings panel. Add every internal domain that traffic could legitimately move from.
Different GA4 properties per subdomain
What goes wrong: You set up a separate GA4 property for acme.com and app.acme.com. They can't share client_id. Cross-domain user journeys are impossible to track. Every report has to be manually joined.
How to avoid: Use a single GA4 property + a single Web data stream for all related domains. Subdomains and brand domains should share one property.
Redirects that strip the _gl parameter
What goes wrong: You configure cross-domain correctly, but a redirect chain (e.g., HTTPS redirect, WAF, marketing automation tool) strips query parameters. The _gl linker is lost and client_id doesn't pass.
How to avoid: Test the actual production redirect chain in DebugView. If _gl is lost, fix the redirect to preserve query parameters (or use 301/302 that preserves params, not a meta-refresh that loses them).
Not handling third-party funnel steps
What goes wrong: Users book a Calendly call and you can't tell which ad campaign drove the booking. Your highest-value events (calls, demos) are attribution-orphaned.
How to avoid: For each third-party funnel step, set up either their native GA4 integration (Calendly) or a server-side Measurement Protocol fire (Stripe, custom forms). Pass GA4 client_id explicitly.
Recap
Done — what's next
How to set up Google Analytics 4 from scratch
Read the next tutorial
Hand it off
Cross-domain tracking failures silently destroy attribution data. If your funnel crosses domains and your reports don't match your actual conversion paths, a vetted GA4 specialist can debug, fix, and validate the full chain in 4-8 hours — typically $80-200 total at $14-16/hr.
See specialist rates
No. www.acme.com and acme.com are the same domain to GA4 — first-party cookies cover both. Cross-domain tracking applies to genuinely different domains (different second-level domains, or subdomains where you want to be explicit).
Open DebugView in one tab. In another incognito tab, navigate through your funnel crossing each domain. The session in DebugView should NOT restart at each domain hop — the client_id stays the same and the session continues. If it restarts, cross-domain isn't working.
That's GA4's cross-domain linker. When the user clicks a link from acme.com to app.acme.com, the Google Tag automatically appends _gl=... to the URL. The receiving domain reads this parameter and uses it to maintain the same client_id. It's safe and expected.
Yes — direct gtag.js installs also support cross-domain via the Configure your domains setting. GTM is convenient but not required. The setting is at the data-stream level in GA4, not in GTM.
Two common causes: (1) ad blocker on the second domain stripping the GA4 tag; (2) the second domain doesn't have the GA4 Google Tag installed at all. Verify the tag is firing on both domains using GTM Preview or Tag Assistant.
Google Analytics 4
GA4 isn't hard to install — it's hard to install *correctly* so the data is actually usable six months from now. This is the walkthrough that prevents the rebuild most owners do at month four.
Google Analytics 4
GTM is the right install path for any site that runs more than one tracking pixel. It's also where most DIY installs go sideways — wrong trigger, wrong variable, wrong fire order. Here's the path that actually works.
Google Analytics 4
GA4 Realtime is supposed to show traffic within 60 seconds. When it shows zero — and your site is clearly getting visits — the cause is one of about six things. This is the diagnostic order.
Google Analytics 4
DIY GA4 is a great idea — until it isn't. This is the honest framework: when the cost of unreliable data exceeds the cost of hiring help, and how to tell which side you're on.