```html

Cross-Domain Session Attribution in GA4: Fixing Linker Configuration Across Two E-commerce Properties

When you operate multiple domains sharing a single Google Analytics 4 property, session continuity breaks without proper cross-domain linker configuration. This post documents the audit and remediation of GA4 tracking across queenofsandiego.com and sailjada.com—two separate booking platforms unified under one analytics property (G-N6HKL4KLKT)—and how a missing configuration parameter caused ~60 pages to lose conversion attribution.

The Problem: Silent Session Breaks

Both domains share a single GA4 property and drive traffic to each other: QOS event pages link to sailjada.com for bookings, and sailjada.com links back to QOS for charter details. Without cross-domain linker configuration, clicking from QOS → sailjada.com creates a new session in GA, breaking the conversion funnel attribution chain.

The audit revealed:

  • sailjada.com: All 22 public pages correctly implemented GA + linker (clean baseline)
  • queenofsandiego.com:
    • ~60 pages had GA tag but missing linker config
    • 3 pages entirely missing GA (charters detail pages, thank-you page)

Root cause: The QOS gtag configuration was missing the allow_google_signals and cross-domain linker object that tells GA4 to append a tracking parameter to outbound links.

Audit Methodology: Systematic Cross-Domain Verification

The audit proceeded in three phases:

Phase 1: Inventory
Extracted all unique GA snippet patterns from both properties across local and S3-deployed files:

# Find all gtag config calls with unique patterns
grep -r "gtag('config'" /path/to/repos/sites/queenofsandiego.com | \
  sed "s/.*gtag('config'/gtag('config'/" | sort -u

# Check placement (head vs body) and linker presence
grep -B5 "gtag('config'" index.html | grep -E "(head|body|linker)"

Phase 2: Linker Configuration Audit
For each GA tag, verified two critical properties:

  • Presence of linker: { domains: ['queenofsandiego.com', 'sailjada.com'] }
  • Correct tag placement in <head> (not deferred to body, which breaks linker)

Phase 3: Event Tracking Depth
Mapped conversion events across the booking funnel: cta_click → generate_lead → begin_checkout → purchase

Found: Core events firing correctly, but missing view_item on charter detail pages and no video engagement tracking on hero sections.

The Fix: Standardized gtag Configuration

Created a unified configuration template and applied it across all QOS pages. The corrected config object:

gtag('config', 'G-N6HKL4KLKT', {
  'page_path': window.location.pathname,
  'linker': {
    'domains': ['queenofsandiego.com', 'sailjada.com']
  },
  'allow_google_signals': true,
  'allow_ad_personalization_signals': true
});

Key additions:

  • linker: { domains: [...] } — Enables automatic URL parameter injection on cross-domain links
  • allow_google_signals: true — Permits GA to use Google signals for cross-device attribution (requires user consent in most jurisdictions)
  • page_path — Ensures SPA and canonical URL handling (important for Rady Shell event pages served from single index.html)

Files Modified:

  • /Users/cb/Documents/repos/sites/queenofsandiego.com/index.html (5 edits to cover apex + all event page variants)
  • /Users/cb/Documents/repos/sites/queenofsandiego.com/thank-you/index.html (GA tag added)
  • /Users/cb/Documents/repos/sites/queenofsandiego.com/charters/*/index.html (GA + linker added via script generation)

For the 60+ pages without manual edits, a bulk remediation script was created (/tmp/fix_ga.py) that:

# Pseudo-code for automated fix
for each_html_file in qos_pages:
    if 'gtag' in file and 'linker' not in file:
        inject_linker_config(file)
    elif 'gtag' not in file:
        add_full_ga_snippet(file)
    
sync_to_s3(updated_files, bucket='queenofsandiego.com')
invalidate_cloudfront(dist_id='E2MLBZVR48STAG')

Infrastructure: CDN and Deployment

S3 Buckets:

  • queenofsandiego.com — Apex domain content
  • www.queenofsandiego.com — Subdomain alias (redirect via CloudFront function)
  • shell.queenofsandiego.com — Rady Shell event ticketing subdomain
  • sailjada.com — Charter booking platform
  • www.sailjada.com — Alias

CloudFront Distributions:

  • E2MLBZVR48STAG — Serves www.queenofsandiego.com (aliases: queenofsandiego.com, shell.queenofsandiego.com)
  • Separate distribution for sailjada.com apex

Cache Invalidation:
After deploying HTML changes to S3, CloudFront cache TTL required invalidation for all modified paths:

aws cloudfront create-invalidation \
  --distribution-id E2MLBZVR48STAG \
  --paths "/*"

This was critical—without invalidation, users would receive stale HTML missing the linker config.

Bonus: Fixing a Typo Domain

During audit, discovered salejada.com (typo) was registered and ranking in search. Created a CloudFront Function to redirect all traffic to the correct domain:

// CloudFront Function at edge
if (request.headers.host.value === 'salejada.com') {
    return {
        statusCode: 301,
        statusDescription: 'Moved Permanently',
        headers: {
            'location': { value: 'https://sailjada.com'