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:
- User clicks link from domain A to domain B
- GA4 appends
_glparameter to the URL - Domain B reads the parameter and uses the same client ID
- Both sessions are unified in GA4 reports
Setting Up Cross-Domain Tracking in GA4
Method 1: GA4 Admin Interface (Simplest)
- Go to GA4 → Admin → Data Streams
- Click your web data stream
- Click “Configure tag settings”
- Click “Configure your domains”
- 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:
- Open your GA4 Configuration tag
- Click “Configuration Settings”
- Add a field:
- Field Name:
linker - Value: Create a Custom JavaScript variable
- Field Name:
// 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:
- In GA4 Config tag, expand “Fields to Set”
- Click “Add Row”
- Field Name:
linker - 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:
- GA4 → Admin → Data Streams
- Click your data stream
- “Configure tag settings”
- “List unwanted referrals”
- 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
Step 1: Check the Link Decoration
- Open your primary site
- Right-click a link to your secondary domain
- Copy link address
- Verify
_glparameter 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
- Enable debug mode on both domains
- Navigate from primary to secondary domain
- In GA4 DebugView, verify:
- Same device/client ID appears
- No “session_start” event on secondary domain (if same session)
Step 4: Real-Time Reports
- Open GA4 → Reports → Real-time
- Click through from primary to secondary domain
- 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:
- Check that cookie domain is set to the root domain
- Verify no conflicting cookie settings
- 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.
Selective Link Decoration
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
-
_glparameter appears on links between domains -
decorate_formsenabled 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:
-
Data stream → Configure tag settings → Configure your domains
- Add:
yourstore.com(Contains) - Add:
checkout.yourstore.com(Contains)
- Add:
-
Data stream → Configure tag settings → List unwanted referrals
- Add:
yourstore.com(Contains) - Add:
checkout.yourstore.com(Contains)
- Add:
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:
- Visit yourstore.com/products
- Click “Buy Now” (links to checkout.yourstore.com)
- Verify URL contains
_glparameter - Check GA4 real-time: should show as ONE user
- 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:
- Multiple GTM containers may be conflicting
- Server-side redirects might be stripping parameters
- CDN or caching layers might be interfering
- Cookie consent implementations might be blocking
Get a free cross-domain tracking audit and we’ll analyze your specific setup across all your domains.