Cross-Domain Tracking in GA4: Setup Guide & Troubleshooting

Learn how to properly configure GA4 cross-domain tracking. Covers when you need it, GTM setup, referral exclusions, and why your cross-domain tracking might not be working.

GA4cross-domain trackingGTMreferral exclusionsGoogle Analytics

Your users browse your marketing site, click “Buy Now,” land on your checkout domain—and GA4 treats it as a brand new session. Attribution is destroyed. Your funnel reports are useless. Here’s how to fix cross-domain tracking in GA4.

When Do You Actually Need Cross-Domain Tracking?

Cross-domain tracking connects user sessions across different domains. You need it when:

  • Marketing site + checkout: yourstore.com → checkout.stripe.com
  • Main site + app: company.com → app.company.com (different subdomain can work without it, but not always)
  • Regional sites: company.com → company.co.uk
  • Third-party booking: hotel.com → booking-system.com

You do NOT need it for:

  • Different pages on the same domain
  • Subdomains (usually—see caveats below)
  • External links where you don’t control the destination

How Cross-Domain Tracking Works

GA4 uses a _gl parameter to pass the client ID between domains:

https://checkout.example.com?_gl=1*abc123*_ga*MTIzNDU2*_ga_XXXXX*MTY...

When configured correctly:

  1. User clicks link from domain A to domain B
  2. GA4 appends _gl parameter to the URL
  3. Domain B reads the parameter and uses the same client ID
  4. Both sessions are unified in GA4 reports

Setting Up Cross-Domain Tracking in GA4

Method 1: GA4 Admin Interface (Simplest)

  1. Go to GA4 → Admin → Data Streams
  2. Click your web data stream
  3. Click “Configure tag settings”
  4. Click “Configure your domains”
  5. Add all your domains:
yourstore.com
checkout.yourstore.com
payments.thirdparty.com

Match conditions:

  • “Contains” is usually best
  • Include all variations (www and non-www if both are used)

Method 2: GTM Configuration

If using Google Tag Manager:

  1. Open your GA4 Configuration tag
  2. Click “Configuration Settings”
  3. Add a field:
    • Field Name: linker
    • Value: Create a Custom JavaScript variable
// Custom JavaScript variable for linker config
function() {
  return {
    'domains': [
      'yourstore.com',
      'checkout.yourstore.com',
      'payments.thirdparty.com'
    ],
    'accept_incoming': true,
    'decorate_forms': true  // Important for form submissions
  };
}

Or configure via the tag’s built-in settings:

  1. In GA4 Config tag, expand “Fields to Set”
  2. Click “Add Row”
  3. Field Name: linker
  4. Value: {"domains":["yourstore.com","checkout.example.com"]}

Method 3: gtag.js Configuration

If using gtag.js directly:

gtag('config', 'G-XXXXXXX', {
  'linker': {
    'domains': ['yourstore.com', 'checkout.example.com'],
    'accept_incoming': true,
    'decorate_forms': true
  }
});

Setting Up Referral Exclusions

Critical step most people miss: After configuring cross-domain tracking, you must exclude your domains from referrals.

Without referral exclusions:

  • User goes from yourstore.com → checkout.example.com
  • GA4 sees checkout.example.com as a “referral”
  • New session starts, attribution is lost

Configure Referral Exclusions:

  1. GA4 → Admin → Data Streams
  2. Click your data stream
  3. “Configure tag settings”
  4. “List unwanted referrals”
  5. Add all your cross-domain domains:
Match type: Contains
Domain: yourstore.com

Match type: Contains
Domain: checkout.example.com

Important: Add ALL domains involved in cross-domain tracking, including your primary domain.

Testing Cross-Domain Tracking

  1. Open your primary site
  2. Right-click a link to your secondary domain
  3. Copy link address
  4. Verify _gl parameter is present:
https://checkout.example.com/cart?_gl=1*1abc2de*_ga*...

If _gl is missing, the linker isn’t configured correctly.

Step 2: Verify Client ID Consistency

On your primary domain:

// Get client ID
gtag('get', 'G-XXXXXXX', 'client_id', function(clientId) {
  console.log('Primary domain client ID:', clientId);
});

Click through to secondary domain and run:

// Should show SAME client ID
gtag('get', 'G-XXXXXXX', 'client_id', function(clientId) {
  console.log('Secondary domain client ID:', clientId);
});

If client IDs differ, cross-domain tracking isn’t working.

Step 3: Check GA4 DebugView

  1. Enable debug mode on both domains
  2. Navigate from primary to secondary domain
  3. In GA4 DebugView, verify:
    • Same device/client ID appears
    • No “session_start” event on secondary domain (if same session)

Step 4: Real-Time Reports

  1. Open GA4 → Reports → Real-time
  2. Click through from primary to secondary domain
  3. Verify you appear as ONE user, not two

Common Cross-Domain Tracking Issues

Issue 1: _gl Parameter Not Appearing

Cause: Linker not configured or not targeting your links.

Debug:

// Check if linker is configured
console.log(google_tag_manager['G-XXXXXXX'].get('linker'));

Fixes:

  • Verify domains are spelled correctly in configuration
  • Check that GA4 config tag fires before the link is clicked
  • Ensure JavaScript isn’t erroring before GA4 loads

Issue 2: _gl Parameter Present But Sessions Still Split

Cause: Usually referral exclusions not set up.

Fix: Add ALL domains to referral exclusions list (including your primary domain).

Issue 3: Form Submissions Losing Client ID

Cause: Forms that POST to another domain don’t automatically get decorated.

Fix: Enable decorate_forms in your linker config:

'linker': {
  'domains': ['...'],
  'decorate_forms': true  // Decorates form action URLs
}

Or manually decorate form submissions:

document.querySelector('form').addEventListener('submit', function(e) {
  // GA4 will decorate the form action URL
  gtag('event', 'form_submission');
});

Issue 4: JavaScript Redirects Not Decorated

Cause: window.location.href redirects bypass link decoration.

Fix: Use the GA4 linker to get a decorated URL:

// Instead of:
window.location.href = 'https://checkout.example.com';

// Use:
gtag('get', 'G-XXXXXXX', 'linker_param', function(param) {
  window.location.href = 'https://checkout.example.com?' + param;
});

Issue 5: Subdomain Tracking Issues

Subdomains should share cookies automatically, but issues can occur:

Check cookie domain setting:

gtag('config', 'G-XXXXXXX', {
  'cookie_domain': 'example.com'  // Note: no leading dot in GA4
});

If subdomains aren’t sharing sessions:

  1. Check that cookie domain is set to the root domain
  2. Verify no conflicting cookie settings
  3. Add subdomains to cross-domain config as backup

Issue 6: Third-Party Domain Won’t Accept _gl

Cause: You don’t control the destination domain.

Reality check: You can only implement cross-domain tracking on domains you control. If linking to Stripe, PayPal, or other third-party checkouts, you cannot implement cross-domain tracking.

Workaround for third-party checkouts:

  • Track the “begin_checkout” event before redirect
  • Use server-side tracking with transaction webhooks
  • Accept some attribution loss

Issue 7: Safari ITP Blocking

Safari’s Intelligent Tracking Prevention can interfere with cross-domain tracking:

Symptoms:

  • Works in Chrome but not Safari
  • Sessions split only for Safari users

Mitigations:

  • Use first-party cookies only (GA4 default)
  • Consider server-side GTM for Safari users
  • Accept some Safari tracking limitations

Advanced Configuration

Multiple GA4 Properties

If you have different GA4 properties on different domains:

// This WON'T work - different properties can't share sessions
// Domain A: G-AAAAAAA
// Domain B: G-BBBBBBB

You must use the SAME measurement ID on all domains for cross-domain tracking.

Only decorate specific links:

gtag('config', 'G-XXXXXXX', {
  'linker': {
    'domains': ['checkout.example.com'],
    'url_position': 'query'  // or 'fragment' for #_gl=...
  }
});

Debug Parameter Persistence

Check if the _gl parameter persists through your flow:

// On secondary domain, check incoming parameter
const urlParams = new URLSearchParams(window.location.search);
console.log('Incoming _gl:', urlParams.get('_gl'));

If _gl is present in URL but sessions still split, the secondary domain isn’t reading it correctly.

Cross-Domain Tracking Checklist

  • All domains added to GA4 data stream’s domain configuration
  • Same GA4 measurement ID on all domains
  • Referral exclusions configured for ALL domains
  • _gl parameter appears on links between domains
  • decorate_forms enabled if using form submissions
  • JavaScript redirects use decorated URLs
  • Client ID is same across domains (verified in console)
  • Real-time report shows one user across domains
  • DebugView shows continuous session (no new session_start)

The Complete Setup Example

Here’s a full working configuration for cross-domain tracking between a marketing site and checkout:

GA4 Admin Configuration:

  1. Data stream → Configure tag settings → Configure your domains

    • Add: yourstore.com (Contains)
    • Add: checkout.yourstore.com (Contains)
  2. Data stream → Configure tag settings → List unwanted referrals

    • Add: yourstore.com (Contains)
    • Add: checkout.yourstore.com (Contains)

GTM Configuration (optional, for more control):

// GA4 Configuration tag fields:
{
  "linker": {
    "domains": ["yourstore.com", "checkout.yourstore.com"],
    "accept_incoming": true,
    "decorate_forms": true
  }
}

Testing Flow:

  1. Visit yourstore.com/products
  2. Click “Buy Now” (links to checkout.yourstore.com)
  3. Verify URL contains _gl parameter
  4. Check GA4 real-time: should show as ONE user
  5. Complete purchase, verify full funnel in GA4

Still Having Issues?

Cross-domain tracking is one of the most commonly misconfigured GA4 features. If you’ve followed this guide and sessions are still splitting:

  1. Multiple GTM containers may be conflicting
  2. Server-side redirects might be stripping parameters
  3. CDN or caching layers might be interfering
  4. Cookie consent implementations might be blocking

Get a free cross-domain tracking audit and we’ll analyze your specific setup across all your domains.