Auditing and Fixing Cross-Domain Google Analytics Implementation Across queenofsandiego.com and sailjada.com

Cross-domain tracking is one of the most commonly broken—and most impactful—analytics implementations. When two distinct domains share a business funnel, a missing linker configuration silently breaks session continuity, misattributing conversions to "direct" traffic and inflating your cost-per-acquisition metrics. This post walks through a systematic audit and repair of that exact problem across two production domains.

What Was Discovered

A complete audit of Google Analytics implementation across queenofsandiego.com and sailjada.com revealed:

  • Linker Configuration Gap: ~60 pages on queenofsandiego.com had GA4 tracking installed but were missing the cross-domain linker. This meant any click from a QOS event page to a sailjada.com booking page lost session context.
  • Coverage Gaps: Three public pages had GA missing entirely: /charters/index.html, /charters/nerissa/index.html, and /thank-you/index.html.
  • Event Tracking Incomplete: The booking funnel tracked purchase, begin_checkout, and generate_lead events correctly, but was missing view_item events on charter detail pages—critical for understanding product interest in the conversion funnel.
  • Clean Implementation on sailjada.com: All 22 public pages had both GA tracking and linker config correctly installed.

The Property ID in use was G-N6HKL4KLKT, a single GA4 property configured for both domains—the correct approach for cross-domain measurement.

Audit Methodology

The audit was conducted in layers:

  • Coverage scan: Extracted all unique GA snippet patterns from both sites' HTML files using grep and regex, identifying which files had the gtag() initialization.
  • Linker validation: Checked each QOS file containing GA for the presence of gtag('config', 'G-N6HKL4KLKT', { 'linker': { 'domains': [...] } }) patterns.
  • Event enumeration: Parsed event tracking code to map which conversion points were instrumented and which were missing.
  • Deployment verification: Cross-referenced S3 bucket structure and CloudFront distribution aliases to confirm which pages were actually live.

Commands used included:

find /path/to/queenofsandiego.com -name "*.html" -exec grep -l "gtag" {} \;
grep -o "gtag('config'[^)]*)" file.html | sort | uniq
grep -o "'linker'[^}]*}" file.html

Root Cause Analysis

The linker gap likely originated from a partial migration or incremental deployment. The sailjada.com implementation was done correctly from the start, but as new pages were added to queenofsandiego.com (particularly event pages and charter detail pages), they were copied from templates that lacked the linker configuration. The linker configuration—a small addition to the gtag config call—was not part of the standard boilerplate.

This is a common pattern: GA tracking gets added (satisfying the "do we have analytics?" checkbox), but cross-domain configuration gets overlooked because it's not immediately visible in the UI and only surfaces when analyzing traffic patterns.

Fix: Linker Configuration

The fix required consistent application of a linker configuration across all 60+ affected QOS pages. The corrected gtag config pattern looks like:

gtag('config', 'G-N6HKL4KLKT', {
  'linker': {
    'domains': ['queenofsandiego.com', 'www.queenofsandiego.com', 'sailjada.com', 'www.sailjada.com']
  }
});

A Python script was written to:

  1. Identify all HTML files in the QOS S3 bucket lacking this linker config.
  2. Parse the existing gtag config call (accounting for variations in whitespace and formatting).
  3. Inject the linker configuration into the gtag config object.
  4. Write corrected files back to S3.

The script also handled edge cases:

  • Pages where gtag was entirely missing (charters, thank-you pages)—these received the full GA initialization block inserted into the <head> before any other scripts.
  • Pages with malformed gtag calls—these were logged for manual review before modification.

Infrastructure Details

S3 Buckets:

  • queenofsandiego.com (apex) and www.queenofsandiego.com are served from S3 buckets with the same names, deployed via CloudFront distribution E2MLBZVR48STAG (apex distribution with alias www.queenofsandiego.com).
  • sailjada.com is served from an S3 bucket and CloudFront distribution configured similarly.
  • Subdomains like radyshell.queenofsandiego.com are served from separate S3 bucket prefixes and their own CloudFront distributions.

Deployment Process:

Fixed files were uploaded directly to S3 with --metadata-directive REPLACE and --cache-control max-age=3600 to ensure immediate cache invalidation. CloudFront cache was invalidated with a wildcard pattern covering all affected paths.

aws s3 cp fixed_file.html s3://queenofsandiego.com/path/fixed_file.html \
  --metadata-directive REPLACE \
  --cache-control "max-age=3600"

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

Event Tracking Additions

Beyond the linker fix, the audit revealed that view_item events were missing from charter detail pages. These events are critical for understanding product interest and are automatically used by GA4's conversion modeling. A secondary script added view_item event tracking to:

  • All pages under /charters/*/index.html
  • Fired on page load with item metadata (charter name, price range, duration)
  • Integrated with existing ecommerce schema already in place on the booking flow

Validation and Results

Post-deployment validation confirmed:

  • All 60+ previously-missing linker configs are now present.
  • Missing GA initializations were added to 3 pages.
  • Linker domain lists are consistent across both properties.
  • Real-time analytics dashboard shows cross-domain session flow preserved (no session breaks on sailjada.com arrival from QOS).

Session attribution on sailjada.com booking pages shifted noticeably within 24 hours—traffic from queeno