New · A dedicated AI SEO channel: see conversions from ChatGPT, Perplexity, Claude & Gemini →
← Blog
Part of: SEO Conversion Tracking: Measure Conversions and Value from Organic Search →

GA4 Cross Domain Tracking: Setup, Testing and Fixes

Portrait of Samy ThuillierBy ··15 min read
Diagram of GA4 cross domain tracking passing a visitor's client ID from a marketing site to a checkout domain

GA4 cross domain tracking makes Google Analytics 4 count a visitor as one user, in one session, when they move between two different domains, such as your marketing site and a separate checkout or booking domain. You turn it on in Admin > Data streams > your web stream > Configure tag settings > Configure your domains, list every domain, and make sure all of them use the same Measurement ID. Without it, GA4 starts a new user and session on the second domain and credits your own site as the traffic source.

This guide covers how it works, the setup in the GA4 admin and in code, how to test it, the cases it does not handle, and how to debug it. It also shows, in dollars, what a broken handoff does to your channel and landing page revenue, which is usually why people go looking for this setting in the first place.

Why GA4 Splits One Visitor Into Two

GA4 recognizes a browser through first-party cookies. The main one, _ga, holds a random client ID. A second one, _ga_<container ID>, holds the session state. Browsers only let a site read cookies that belong to its own domain. So when someone clicks from yourbrand.com to yourbrandshop.com, the tag on the shop cannot see the cookies from the first site. It creates new ones.

Three things go wrong at that moment:

  • Users and sessions are inflated. One person becomes two users with two sessions, one on each domain.
  • Your own site shows up as a referrer. The new session on the shop has yourbrand.com as its source, a problem usually called a self-referral. See what referral traffic is for how GA4 classifies those visits.
  • Conversions lose their real source. The purchase or lead on the second domain is credited to the self-referral, not to the Google search, ad or email that started the visit.

This happens whenever a journey crosses root domains: a hosted cart, a course platform such as Teachable (its checkout runs on a Teachable domain when your school uses a custom domain), a booking tool, a separate store domain, or country sites like example.com and example.ca.

How the _gl Linker Works

Cross-domain measurement uses a linker. When a visitor clicks a link that points to one of your listed domains, the Google tag on the source page rewrites the link and adds a _gl query parameter, for example ?_gl=1~abcde5~. That parameter carries the values of the source domain’s measurement cookies. The Google tag on the destination page reads it and writes those values into its own first-party cookies before it sends any events.

The _gl value bundles several cookies, each prefixed with its name. Depending on what runs on your site, it can include _ga (the GA4 client ID), _ga_XXXXXXX (the GA4 session cookie), _gcl_aw (the Google Ads click ID) and FPLC (used by server-side Tag Manager). The result: both domains end up with the same client ID and the same session ID, so GA4 sees one user and one continuous session. According to Google’s developer guide, the same mechanism serves Google Ads conversion measurement and Floodlight as well as Analytics.

Before You Start

  • One Measurement ID on every domain. Every page of every domain must send data to the same GA4 web data stream (the same G- ID). Two separate properties cannot share a session. Use one web stream for all the domains, not one stream per domain in the same property.
  • The right role. Google’s setup article asks for the Editor role or above. Several guides say you need Administrator; Editor is enough.
  • Room for your domains. The same article allows up to 100 conditions in Configure your domains, and conditions are combined with OR, so a page matching any one of them counts.
  • Plain links between domains. The automatic setup decorates normal <a href> links. Check how visitors actually move between your domains before you assume it will just work (more under limitations).
  • No history is lost. Turning it on in an existing property changes how new data is collected. Past data stays as it was, including its self-referrals.

How to Set Up GA4 Cross Domain Tracking

Since the setting lives in the GA4 admin, there is no code to change if the tag is already installed everywhere.

  1. Install the same Measurement ID everywhere. Check every domain in the journey, including checkout, thank-you and booking pages. gtag.js or Google Tag Manager both work; only the Measurement ID has to match. Different GTM containers on each domain are fine.
  2. Open the data stream. Click Admin, then under Data collection and modification click Data streams, choose Web and select your stream.
  3. Open Configure tag settings. Scroll to the bottom of the stream page, click Configure tag settings, then Configure your domains.
  4. Add each domain. GA4 may show recommended domains it has detected; add the ones you own. To add one manually, click Add condition, keep the match type Contains and enter the root domain, for example yourbrandshop.com. Add your main domain too. Click Save.
  5. Test the handoff, as described in the next section, a few minutes after saving.
Side effect on outbound clicks

Enhanced measurement counts clicks to other domains as outbound clicks. Once a domain is listed in Configure your domains, clicks to it are no longer outbound clicks, because GA4 now treats it as part of your site. If a report or audience relied on those clicks, rebuild it on a page view or a custom event on the destination domain.

Does the linker work in both directions?

Yes, as long as every domain is listed and every domain runs the tag. A visitor can start on the shop and go to the blog, or bounce back and forth, and the same IDs are carried each way.

Do Subdomains Need Cross-Domain Tracking?

Usually not. By default, the Google tag writes its cookies on the root domain (for example .yourbrand.com), so www.yourbrand.com, blog.yourbrand.com and shop.yourbrand.com all read the same _ga cookie. Visitors moving between them stay one user in one session, as long as every subdomain uses the same Measurement ID.

Most guides go further and say you should never list subdomains. Google’s own setup article is more nuanced: it recommends the setting for subdomains when they use a different cookie domain, because then self-referrals can appear. Both are right in their own case:

  • Default cookie settings: leave subdomains out. Listing them only adds _gl to internal links for no benefit.
  • Custom cookie domain per subdomain (someone set cookie_domain to the full hostname, often for an app or a staging rule): either remove that customization, or list the subdomains so the IDs are passed. If you see your own subdomain as a referrer, check this first.

GA4 standard reports show page paths without the hostname, so two subdomains with a /pricing page appear as one row. Add the Hostname dimension (in an exploration, or as a secondary dimension) when you need to separate them.

How to Test It

Run three checks, from quickest to most thorough:

  1. Look for _gl. Open a page on domain A, click a link to domain B and look at the address bar. The URL should contain _gl= followed by a long string. No _gl means the link was never decorated or the parameter was stripped.
  2. Compare the cookies. In your browser’s developer tools (Application > Cookies), compare _ga and _ga_XXXXXXX on both domains. The values must match. If _gl was there but the values differ, the destination tag did not accept it.
  3. Check the session in DebugView. Turn on debug mode, browse from A to B, and open the page_view events in GA4 DebugView. The ga_session_id parameter should stay the same while page_location switches from domain A to domain B.

Google also suggests submitting any cross-domain forms during the test and trying file downloads that live on another domain, to be sure the page still loads correctly with the extra parameter.

What Broken Cross-Domain Tracking Costs You: A Worked Example

Guides describe the self-referral problem in words. Here it is in numbers. The figures below are illustrative, not from any study; swap in your own.

A course creator runs a content site on yourbrand.com and sells on a hosted checkout at yourbrandshop.com. In one month:

Illustrative month
1,000 sessions from Google organic search on the blog
40 of those visitors click through to the checkout domain
20 of them buy a $150 course
Revenue: 20 x $150 = $3,000
What GA4 showsNo cross-domainUnwanted referrals onlyCross-domain working
Users1,0401,0401,000
Sessions1,0401,0401,000
Organic Search revenue$0$0$3,000
Revenue credited toReferral: yourbrand.comDirectOrganic Search
Revenue by organic landing pageNoneNoneBlog posts that started each visit
Organic conversion rate0%0%20 / 1,000 = 2%

Without cross-domain tracking, the 40 click-throughs become 40 extra users and 40 extra sessions (1,040 instead of 1,000, a 4% inflation in this example), and all $3,000 sits under a referral from your own blog. Organic search looks like it brought traffic and no sales, and the blog posts that actually sold the course get no revenue at all in a landing page report.

The middle column is the trap. Adding yourbrand.com to the unwanted referrals list removes the self-referral from your reports, so the data looks clean. But the checkout domain still has a brand-new user with no earlier session, so the sale lands in Direct instead. Users stay inflated and Organic Search still gets $0. Only a working linker connects the purchase to the search visit.

Revenue misattributed = sessions handed to the other domain x their conversion rate x average order value

Run that formula for your own handoff pages before you prioritize the fix. If your second domain is where leads or sales happen, every channel and SEO conversion report you build depends on it.

Limitations: What the Automatic Setup Does Not Cover

  • Buttons and JavaScript navigation. The linker listens for clicks on the document and decorates links. A <button> that changes window.location, or any navigation started by a script, is not decorated. A link styled to look like a button works fine.
  • Forms. The admin setting does not decorate form submissions. In gtag.js you can set decorate_forms: true (next section). A form that posts to your server, which then redirects to the other domain, needs your developer to carry the parameter through.
  • Redirects that drop query strings. If domain B redirects the landing URL (adding a trailing slash, switching locale, forcing www) and does not keep the query string, _gl is lost.
  • Scripts that stop click events. If another script calls Event.stopPropagation() on a link click, the event never reaches the linker’s listener on the document.
  • Existing cookies on the destination are overwritten. If domain B already had GA cookies from its own property, the linker replaces them with domain A’s values. A separate GA4 config on domain B can protect its own identifiers with a cookie_prefix.
  • Denied analytics consent. When a visitor has denied analytics_storage, the tag does not write analytics cookies, so there is no client ID to hand over. Consent mode’s URL passthrough only applies to links within the same domain, so it does not stitch cross-domain journeys either.
  • Domains you cannot tag. Cross-domain measurement needs the tag on both sides. A payment page on PayPal or a bank cannot run your tag, so use unwanted referrals for those (see below).

Setting It Up in Code: gtag.js, GTM and Google Ads

Google recommends the admin setting for Analytics, but the gtag.js linker gives you options the admin does not. The linker must be set before the config command:

gtag('set', 'linker', {
  'domains': ['yourbrand.com', 'yourbrandshop.com'],
  'decorate_forms': true,     // also decorate form submissions
  'url_position': 'query'     // or 'fragment' to use #_gl=
});
gtag('js', new Date());
gtag('config', 'G-XXXXXXXXXX');
Linker optionDefaultUse it when
domainsnoneYou list the domains whose links get decorated. Use the same snippet on every domain.
accept_incomingtrue when domains has a valueA destination page does not decorate links itself but must read incoming _gl values.
decorate_formsfalseVisitors cross domains by submitting a form.
url_positionqueryYour app reads parameters after # instead of ?, so set it to fragment.

Google Tag Manager. If GTM loads your Google tag, the domains in the GA4 admin apply; there is no Analytics-specific linker setting to tick. To change url_position for GA4 in GTM, add a configuration parameter named linker to the Google tag with a value such as {'url_position': 'fragment', 'domains': ['a.com', 'b.com']}.

Google Ads and Floodlight. These rely on the Conversion Linker tag in GTM. Create a Conversion Linker tag, fire it on all pages, tick Enable linking across domains, enter your domains under Auto Link Domains, and enable Accept incoming linker parameters on the destination. Without it, Ads conversions on the second domain can lose their click ID even when GA4 is fixed.

Manual handoff when links are not links

For button or JavaScript navigation, older guides say there is no API and you have to read cookies yourself. That has changed: the Google tag now has a get command that returns the GA4 client_id and session_id, and Google’s setup article describes the manual route with it. The outline:

  1. On domain A, call gtag('get', 'G-XXXXXXXXXX', 'client_id', callback) and the same for session_id.
  2. Append both values to the destination URL before your script navigates.
  3. On domain B, read them from the URL and pass them in the config command (client_id, session_id) before any event fires.
  4. Add a timestamp and reject old values, so a shared URL does not merge strangers into one user.

This is code you maintain yourself, so try to turn the navigation into a normal link first. It is usually the cheaper fix.

Unwanted Referrals: What It Does and Does Not Fix

You do not need to add your own listed domains to the unwanted referrals list. Per Google’s unwanted referrals article, GA4 already ignores the referrer when it matches the current page’s domain or subdomains, or when the visit arrives with a _gl linker parameter.

An unwanted referral rule adds ignore_referrer=true to the event, so the referring site is not used as the traffic source, and it does not start a new session. You can add up to 50 per data stream. Use it for:

  • Payment gateways and bank verification pages that send buyers back to your thank-you page (PayPal, card 3-D Secure pages).
  • Login or password reset providers that bounce users back to your site.
  • Your own domains, as a last resort, if they still appear as referrers after cross-domain is confirmed working (often a page missing the tag).

It is not a substitute for cross-domain measurement. As the worked example shows, it hides the self-referral but cannot carry the client ID, so the sale moves to Direct instead of returning to its real source.

One Property or Separate Properties?

Cross-domain tracking only joins domains that send data to the same stream. If your domains run separate properties, decide what you actually need:

Your situationWhat to do
Subdomains of one site, same Measurement IDNothing. GA4 shares cookies across subdomains by default.
Main site plus a separate store, checkout, booking or course domain you can tagOne property, one web stream, cross-domain measurement on all domains.
Country or language domains (example.com, example.ca, example.fr) in one funnelOne stream with cross-domain, and filter by Hostname for per-country reports.
Payment page you cannot tag (PayPal, bank)Unwanted referrals for that domain; no cross-domain.
Separate brands or teams that want separate reportsKeep separate properties. Clicks between them show as referrals, which is correct for that setup.
Separate properties plus a joined viewKeep both and add a third property: send a second Google tag on every domain to it, and set up cross-domain there only.

The third-property route keeps each team’s history intact and gives you one place to see the joined journey. The cost is double tagging and an extra property to maintain. In the Google Analytics community thread on this question, a product expert suggested exactly this for an English and a Japanese site managed by different people.

Debugging GA4 Cross Domain Tracking When It Is Not Working

SymptomLikely causeFix
No _gl in the destination URLDomain not listed, wrong spelling, or the click is not a plain linkCheck Configure your domains; inspect the element; convert the button to a link or use the manual handoff
_gl appears, then disappearsRedirect on the destination drops the query stringFollow the redirect chain in the Network tab; make the redirect keep query parameters
_gl present but _ga differs on domain BDifferent Measurement ID, or no Google tag on the landing page itselfUse the same G- ID; make sure the Google tag runs on the first page visitors land on
Same client ID but a new ga_session_idDomains on different web streams, or a custom cookie_prefix on one tag (the linker only works with default cookie names)Move both domains to one web stream; remove the custom prefix from that tag
Links decorated on some pages onlyPages without the tag, or a script calling stopPropagation()Audit tag coverage; check event listeners on the link
Own domain still listed as a referralSome pages miss the tag, or a custom cookie domain on a subdomainTag every page; fix cookie_domain; then add the domain to unwanted referrals
Direct traffic and conversions jump after a changeUnwanted referral rule added while the linker is brokenFix the linker; the rule only hid the break

After any fix, give it a few days and compare session source for conversions on the second domain. Self-referrals and Direct should fall, and the share credited to organic, paid and email should rise. Google’s setup article also lists redirects and stopPropagation() as the two main reasons the parameter goes missing.

Reporting Per Domain After the Fix

Once domains share a stream, you still want to see each one. Use the Hostname dimension: add it as a comparison or filter in standard reports, or as a dimension in an exploration next to Landing page and Session source / medium. That gives you one row per domain and page with the correct original source.

The view that matters most is conversions and revenue by original channel and landing page, because that is what cross-domain tracking repairs. Our guide on organic conversion attribution walks through building it in GA4. If you would rather not maintain linker rules at all, SEOConversion reports conversions and revenue by landing page for organic search and AI assistants, using a cookieless first-party script, and on Shopify, WooCommerce and Webflow it reads purchase events from the dataLayer and attributes that revenue to organic and AI search.

Checklist

  • Same G- Measurement ID on every page of every domain in the journey.
  • Every root domain listed in Configure your domains, match type Contains.
  • Subdomains left out unless they use a custom cookie domain.
  • Navigation between domains uses real links, or gtag decorate_forms or a manual handoff covers the rest.
  • _gl visible on arrival, _ga identical on both domains, ga_session_id unchanged in DebugView.
  • Conversion Linker set to link domains if Google Ads or Floodlight measures conversions on the second domain.
  • Payment gateways in unwanted referrals; your own domains only as a last resort.
  • A short note of the domains and settings, rechecked whenever you add a domain, a checkout or a redirect.

FAQ

What is cross-domain tracking in GA4?

It is a setting that lets one GA4 data stream treat a visitor as the same user, in the same session, when they move between two or more different root domains, such as a marketing site and a separate checkout domain. The Google tag adds a _gl parameter to links between the listed domains, and the destination page reads it to reuse the same client and session IDs.

What does cross-domain mean?

In analytics, cross-domain means a visit that moves from one registrable domain to another, for example from yourbrand.com to yourbrandshop.com. Browsers keep cookies separate per domain, so a tool that identifies visitors with first-party cookies cannot recognize the same person on the second domain without extra setup. Moving between blog.yourbrand.com and www.yourbrand.com is not cross-domain in this sense.

Can I have two domains go to the same website?

Yes. You can point several domains at one site, usually by redirecting the extra domains to your main one with a permanent redirect. In that case you do not need cross-domain tracking, because visitors only ever browse the main domain. You need it when people actually browse pages on two domains during one visit.

Does GA4 cross domain tracking work with Google Tag Manager?

Yes. If GTM loads your Google tag with the same Measurement ID on every domain, the domains you list in the GA4 admin apply automatically, with no extra GTM setting for Analytics. For Google Ads and Floodlight tags, add a Conversion Linker tag with linking across domains enabled.

Why is GA4 cross domain tracking not working?

The usual causes are a different Measurement ID on one domain, a domain missing from Configure your domains, navigation that is not a plain link (buttons, forms, JavaScript redirects), a redirect that strips the _gl parameter, or a script that stops click events from reaching the document. Click a cross-domain link and check for _gl in the address bar first, then compare the _ga cookie on both domains.

What is replacing Google Analytics?

Google Analytics 4 replaced Universal Analytics, which no longer processes data, so GA4 is the current version of Google Analytics. Some teams also add privacy-focused or specialized tools next to GA4, for example cookieless trackers that report conversions by channel, but GA4 itself is not being replaced.

Fix the handoff, then measure what each landing page earns.

SEOConversion is a cookieless, first-party tracker that shows which conversions and how much revenue come from organic search and AI assistants, reported by landing page. One script, and on Shopify, WooCommerce and Webflow it reads purchases from the dataLayer.

Start free