Overview
Cross-domain tracking maintains user session and conversion attribution when users navigate between multiple domains or subdomains. Without proper configuration, each domain transition creates a new session, breaking the attribution chain from ad click to conversion.
When Cross-Domain Tracking is Needed
Common Scenarios
- Multi-domain checkout: User browses on
www.example.com, checks out oncheckout.example.com - Third-party payment processor: User redirects to
secure-payments.processor.comduring purchase - Separate domains: Main site on
example.com, blog onblog.example.net - Subdomain separation: Marketing site on
www.example.com, app onapp.example.com - Regional domains: US on
example.com, UK onexample.co.uk
Signs You Need Cross-Domain Tracking
- Conversions attributed to "(direct)" instead of ad campaign
- Session breaks between browsing and checkout
- Lost MSCLKID parameter during domain transitions
- Lower conversion rates than expected
- Attribution mismatches between platforms
How Cross-Domain Tracking Works
MSCLKID Parameter Preservation
Microsoft Advertising uses the msclkid (Microsoft Click ID) parameter for attribution:
- User clicks ad on Microsoft Advertising
- Landing URL includes
msclkidparameter:example.com?msclkid=abc123xyz - UET tag stores
msclkidin first-party cookie - When user navigates to different domain,
msclkidmust be passed - UET tag on second domain reads
msclkidand maintains attribution - Conversion properly attributed to original ad click
Cookie Limitations
Cookies don't work across different domains due to browser security:
- Cookie set on
example.comcannot be read bycheckout.example.net - Cookie set on
www.example.comcan be read byapp.example.com(same root domain) - Solution: Pass
msclkidas URL parameter during transitions
Subdomain Tracking
Same Root Domain
For subdomains under the same root domain (e.g., www.example.com, app.example.com, checkout.example.com):
Step 1: Configure Cookie Domain
No special configuration needed. UET automatically sets cookies for the root domain:
// UET automatically sets cookie for .example.com
// Readable by all subdomains: www.example.com, app.example.com, etc.
Step 2: Deploy UET Tag on All Subdomains
Ensure the same UET tag ID is deployed on all subdomains:
<!-- On www.example.com -->
<script>
(function(w,d,t,r,u){
var f,n,i;
w[u]=w[u]||[],f=function(){
var o={ti:"12345678"}; // Same tag ID
// ... rest of UET tag
}
// ...
})(window,document,"script","//bat.bing.com/bat.js","uetq");
</script>
<!-- On checkout.example.com -->
<script>
(function(w,d,t,r,u){
var f,n,i;
w[u]=w[u]||[],f=function(){
var o={ti:"12345678"}; // Same tag ID
// ... rest of UET tag
}
// ...
})(window,document,"script","//bat.bing.com/bat.js","uetq");
</script>
Step 3: Test
- Click ad and land on
www.example.comwithmsclkidparameter - Navigate to
checkout.example.com - Complete conversion
- Verify conversion attributes to ad campaign (not direct)
Different Root Domains
For completely different domains (e.g., example.com and example.net), additional configuration is required.
Cross-Domain Tracking Implementation
Method 1: Automatic Parameter Forwarding (Recommended)
Step 1: Enable Auto-Tagging
In Microsoft Advertising:
- Navigate to Accounts > Account settings
- Scroll to Tracking template section
- Ensure Auto-tagging is enabled
- Save settings
Auto-tagging automatically appends msclkid to all destination URLs.
Step 2: Preserve Parameters in Links
Add JavaScript to preserve msclkid when linking between domains:
// Add to all pages on source domain (example.com)
(function() {
// Get MSCLKID from URL
function getMSCLKID() {
var urlParams = new URLSearchParams(window.location.search);
return urlParams.get('msclkid');
}
// Append MSCLKID to cross-domain links
function appendMSCLKIDToLinks() {
var msclkid = getMSCLKID();
// Also check for MSCLKID in cookie (set by UET)
if (!msclkid) {
var cookies = document.cookie.split(';');
for (var i = 0; i < cookies.length; i++) {
var cookie = cookies[i].trim();
if (cookie.indexOf('_uetmsclkid=') === 0) {
msclkid = cookie.substring('_uetmsclkid='.length);
break;
}
}
}
if (msclkid) {
// Find all links to checkout domain
var links = document.querySelectorAll('a[href*="checkout.example.com"]');
links.forEach(function(link) {
var url = new URL(link.href);
url.searchParams.set('msclkid', msclkid);
link.href = url.toString();
});
}
}
// Run on page load
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', appendMSCLKIDToLinks);
} else {
appendMSCLKIDToLinks();
}
})();
Step 3: Preserve Through Redirects
If using server-side redirects:
<?php
// PHP example - preserve msclkid through redirect
$msclkid = isset($_GET['msclkid']) ? $_GET['msclkid'] : '';
$redirect_url = 'https://checkout.example.com/cart';
if ($msclkid) {
$redirect_url .= '?msclkid=' . urlencode($msclkid);
}
header('Location: ' . $redirect_url);
exit;
?>
// Node.js example
app.get('/checkout', (req, res) => {
const msclkid = req.query.msclkid;
let redirectUrl = 'https://checkout.example.com/cart';
if (msclkid) {
redirectUrl += `?msclkid=${encodeURIComponent(msclkid)}`;
}
res.redirect(redirectUrl);
});
Step 4: Deploy UET Tag on Second Domain
Ensure UET tag with same tag ID is on the destination domain:
<!-- On checkout.example.com -->
<script>
(function(w,d,t,r,u){
var f,n,i;
w[u]=w[u]||[],f=function(){
var o={ti:"12345678"}; // Same tag ID as example.com
// ... rest of UET tag
}
// ...
})(window,document,"script","//bat.bing.com/bat.js","uetq");
</script>
UET will automatically read msclkid from URL parameter and restore attribution.
Method 2: Manual Cookie Sharing
For more control, manually store and retrieve msclkid:
On Source Domain (example.com)
// Capture and store MSCLKID
function getMSCLKIDFromURL() {
var urlParams = new URLSearchParams(window.location.search);
return urlParams.get('msclkid');
}
function storeMSCLKID() {
var msclkid = getMSCLKIDFromURL();
if (msclkid) {
// Store in localStorage (works cross-domain if manually transferred)
localStorage.setItem('msclkid', msclkid);
// Store in cookie for 90 days
var expires = new Date();
expires.setTime(expires.getTime() + (90 * 24 * 60 * 60 * 1000));
document.cookie = 'msclkid=' + msclkid + ';expires=' + expires.toUTCString() + ';path=/';
}
}
storeMSCLKID();
On Destination Domain (checkout.example.com)
// Retrieve MSCLKID and add to conversion
function getMSCLKIDForConversion() {
// Check URL first
var urlParams = new URLSearchParams(window.location.search);
var msclkid = urlParams.get('msclkid');
// If not in URL, check localStorage (manual transfer needed)
if (!msclkid) {
msclkid = localStorage.getItem('msclkid');
}
return msclkid;
}
// When conversion occurs
var msclkid = getMSCLKIDForConversion();
if (msclkid) {
// Add to page URL so UET can pick it up
if (!window.location.search.includes('msclkid')) {
history.replaceState(null, '', window.location.pathname + '?msclkid=' + msclkid);
}
}
// Fire conversion
window.uetq = window.uetq || [];
window.uetq.push('event', 'purchase', {
'revenue_value': 99.99,
'currency': 'USD'
});
Payment Processor Integration
Third-Party Checkout (Stripe, PayPal, etc.)
When users redirect to payment processor and return:
Step 1: Pass MSCLKID to Payment Processor
// Before redirecting to payment processor
function redirectToCheckout() {
var msclkid = getMSCLKID(); // From URL or cookie
var returnUrl = 'https://example.com/thank-you';
// Append MSCLKID to return URL
if (msclkid) {
returnUrl += '?msclkid=' + encodeURIComponent(msclkid);
}
// Redirect to payment processor with return URL
window.location = 'https://checkout.stripe.com/pay?return_url=' + encodeURIComponent(returnUrl);
}
Step 2: Configure Return URL
Most payment processors allow custom return URLs. Include msclkid:
Stripe Example:
stripe.redirectToCheckout({
sessionId: 'sess_123',
successUrl: 'https://example.com/thank-you?msclkid={{MSCLKID}}&session_id={CHECKOUT_SESSION_ID}',
cancelUrl: 'https://example.com/cancel?msclkid={{MSCLKID}}'
});
PayPal Example:
<input type="hidden" name="return" value="https://example.com/thank-you?msclkid=abc123xyz">
Step 3: Fire Conversion on Return
When user returns from payment processor with msclkid:
// On thank-you page
var urlParams = new URLSearchParams(window.location.search);
var msclkid = urlParams.get('msclkid');
// UET tag will automatically read msclkid from URL
window.uetq = window.uetq || [];
window.uetq.push('event', 'purchase', {
'revenue_value': orderTotal,
'currency': 'USD'
});
Google Tag Manager Cross-Domain Configuration
GTM Method
Step 1: Create Utility Variables
Variable: Get MSCLKID from URL
- Variable Type: URL
- Component Type: Query
- Query Key:
msclkid - Variable Name:
URL - MSCLKID
Variable: Get MSCLKID from Cookie
- Variable Type: 1st Party Cookie
- Cookie Name:
_uetmsclkid - Variable Name:
Cookie - MSCLKID
Step 2: Create Cross-Domain Link Decorator Tag
Tag Type: Custom HTML
<script>
(function() {
var msclkid = {{URL - MSCLKID}} || {{Cookie - MSCLKID}};
if (msclkid) {
// Decorate cross-domain links
var links = document.querySelectorAll('a[href*="checkout.example.com"], a[href*="otherdomain.com"]');
links.forEach(function(link) {
link.addEventListener('click', function() {
var url = new URL(this.href);
if (!url.searchParams.has('msclkid')) {
url.searchParams.set('msclkid', msclkid);
this.href = url.toString();
}
});
});
}
})();
</script>
Trigger: All Pages
Step 3: Test in GTM Preview Mode
- Click Preview in GTM
- Click ad with
msclkidparameter - Click link to cross-domain site
- Verify
msclkidis appended to URL - Complete conversion and verify attribution
Testing Cross-Domain Tracking
Test Plan
Generate test click:
- Use Microsoft Advertising ad preview tool
- Click ad to generate
msclkidparameter - Note the
msclkidvalue
Navigate through funnel:
- Land on first domain with
msclkid - Navigate to second domain
- Check URL includes
msclkidparameter - Check browser DevTools > Application > Cookies for UET cookie
- Land on first domain with
Complete conversion:
- Fire conversion event
- Use UET Tag Helper to verify
- Check Network tab for bat.bing.com request with
msclkid
Verify in Microsoft Advertising:
- Wait 2-4 hours for processing
- Check conversion appears in reporting
- Verify attributed to correct campaign (not "(direct)")
Debugging Checklist
- Auto-tagging enabled in Microsoft Advertising account
- Same UET tag ID on all domains
- Links between domains include
msclkidparameter - Redirects preserve
msclkidparameter - Payment processor return URLs include
msclkid - UET Tag Helper shows tag firing on all domains
- Network requests show
msclkidin bat.bing.com calls - Conversions attributed to ad campaigns, not "(direct)"
Common Issues & Solutions
MSCLKID Lost During Navigation
Symptom: Parameter missing when navigating between domains
Solutions:
- Check links include
msclkidin href - Verify JavaScript decorator runs before clicks
- Ensure redirects preserve query parameters
- Check form submissions include
msclkidas hidden field
Conversion Attributed to "(direct)"
Symptom: Conversions show as direct traffic instead of ad campaign
Solutions:
- Verify
msclkidparameter present on conversion page URL - Check UET tag is same ID on all domains
- Ensure conversion fires within 90-day click window
- Verify auto-tagging is enabled
Multiple Domains Don't Share Cookies
Symptom: Cookie set on domain A not readable on domain B
Expected behavior: Cookies can't be shared across different root domains
Solution: Use URL parameter method to pass msclkid between domains
Payment Processor Strips Parameters
Symptom: msclkid removed during payment redirect
Solutions:
- Store
msclkidin payment metadata/custom fields - Return
msclkidin webhook/callback - Use server-side session to preserve value
- Configure payment processor return URL with
msclkid
Advanced Scenarios
Multi-Step Checkout Across Domains
For complex funnels spanning multiple domains:
example.com (product browse)
↓
cart.example.com (shopping cart)
↓
checkout.example.net (checkout form)
↓
secure.processor.com (payment)
↓
example.com/thank-you (confirmation)
Solution: Pass msclkid at each transition:
- example.com → cart.example.com: Append to "Add to Cart" link
- cart.example.com → checkout.example.net: Append to "Checkout" button
- checkout.example.net → secure.processor.com: Include in payment return URL
- secure.processor.com → example.com/thank-you: Return in redirect
Regional Domain Tracking
For businesses with regional domains (example.com, example.co.uk, example.de):
Option 1: Separate UET Tags
- Create separate UET tag for each region
- Create separate conversion goals
- Report shows conversions by region
Option 2: Shared UET Tag
- Use same UET tag across all regional domains
- Implement cross-domain tracking
- Use event labels to differentiate regions:
window.uetq = window.uetq || [];
window.uetq.push('event', 'purchase', {
'revenue_value': 99.99,
'currency': 'GBP',
'event_label': 'uk' // Regional identifier
});
Single Sign-On (SSO) Flows
When users authenticate on separate domain:
app.example.com (main app)
↓
sso.example.com (authentication)
↓
app.example.com (return after login)
Solution: SSO redirect should preserve msclkid:
// On app.example.com
function redirectToSSO() {
var msclkid = getMSCLKID();
var returnUrl = 'https://app.example.com/dashboard';
if (msclkid) {
returnUrl += '?msclkid=' + encodeURIComponent(msclkid);
}
window.location = 'https://sso.example.com/login?return=' + encodeURIComponent(returnUrl);
}
Best Practices
- Use same UET tag ID: All domains must use identical tag ID
- Preserve parameters: Always append
msclkidwhen linking between domains - Test thoroughly: Verify attribution before launching campaigns
- Document flows: Map out all domain transitions in user journey
- Monitor attribution: Regularly check for "(direct)" conversions that should be attributed
- Server-side backup: Store
msclkidserver-side for critical conversions - 90-day window: Conversions must occur within 90 days of click
- HTTPS everywhere: Use HTTPS on all domains for security
Cross-Domain Tracking Checklist
- Auto-tagging enabled in Microsoft Advertising
- Same UET tag ID deployed on all domains
- Links between domains include
msclkidparameter - Form submissions preserve
msclkid(hidden field or URL) - Redirects maintain
msclkidin query string - Payment processor return URLs include
msclkid - JavaScript decorator runs on all cross-domain links
- GTM cross-domain configuration tested (if using GTM)
- Test conversions attribute correctly (not to direct)
- Documentation created for all domain transitions
Next Steps
- Explore server-side conversion tracking for enhanced reliability
- Review troubleshooting guide for common issues
- Set up offline conversion imports for CRM-based attribution