Session Stitching Issues | Blue Frog Docs

Session Stitching Issues

Diagnose and fix session continuity problems that break user journey tracking across page navigations

Session Stitching Issues

What This Means

Session stitching issues occur when analytics platforms fail to maintain session continuity as users navigate through your website. This results in single visits being split into multiple sessions, breaking user journey analysis and attribution data.

Impact on Your Business

Broken User Journeys:

Inflated Session Counts:

  • Same visit counted as multiple sessions
  • Session-based metrics artificially high
  • Bounce rate calculations incorrect
  • Average session duration underreported

Attribution Problems:

  • Last-click attribution credits wrong source
  • Multi-touch attribution impossible
  • Cannot identify true conversion path
  • ROI calculations based on incomplete data

How to Diagnose

Method 1: Test Session Continuity

  1. Clear cookies and start fresh test:

    • Open incognito/private browser window
    • Navigate to homepage
    • Note the time
  2. Navigate through multiple pages:

    • Click to product page (wait 10 seconds)
    • Click to cart page (wait 10 seconds)
    • Click to checkout (wait 10 seconds)
    • Complete purchase
  3. Check analytics in real-time:

    • GA4: Reports → Realtime → Event count by Event name
    • Look for your test session
    • Verify all pages in single session

What to Look For:

  • Multiple sessions for single visit
  • Session breaks between page loads
  • Different session IDs on sequential pages
  • New session started mid-journey

Method 2: Check GA4 DebugView

  1. Enable debug mode:

    gtag('config', 'G-XXXXXXXXXX', {
      'debug_mode': true
    });
    
  2. Open GA4 DebugView:

    • GA4 → Configure → DebugView
    • Navigate through site
    • Watch session_start events
  3. Look for multiple session_start events:

    • Should only fire once per visit
    • Multiple fires = session stitching problem
    • Note which navigation triggers new session

What to Look For:

  • session_start firing on every page
  • Different session_id values
  • Session timeout occurring too quickly
  • Client ID changing between pages
  1. Open Chrome DevTools:

    • Press F12
    • Navigate to Application tab
    • Click Cookies in left sidebar
  2. Check GA4 cookies:

    _ga: Client ID (should persist across pages)
    _ga_XXXXXXXXXX: Session data (should persist)
    
  3. Navigate between pages:

    • Check if cookies persist
    • Verify values remain constant
    • Look for cookie deletion/recreation

What to Look For:

  • Cookies deleted on page navigation
  • Cookie domain restrictions
  • SameSite cookie blocking
  • Subdomain cookie issues

Method 4: Test Cross-Subdomain Tracking

  1. Navigate from main domain to subdomain:

    www.example.com → shop.example.com
    blog.example.com → www.example.com
    
  2. Check session continuity:

    • Open DevTools Network tab
    • Filter for "collect" or "analytics"
    • Compare session IDs in requests
  3. Review cookie scope:

    • Check if _ga cookie has domain=.example.com
    • Verify cookie accessible on all subdomains

What to Look For:

  • New session on subdomain navigation
  • Cookie not shared across subdomains
  • Missing linker parameters in URLs
  • Client ID reset on domain switch

General Fixes

Fix 1: Extend Session Timeout

Increase session timeout duration:

  1. GA4 default is 30 minutes:

    gtag('config', 'G-XXXXXXXXXX', {
      'session_timeout': 1800 // 30 minutes (default)
    });
    
  2. Extend for long-form content sites:

    gtag('config', 'G-XXXXXXXXXX', {
      'session_timeout': 3600 // 60 minutes
    });
    
  3. Consider user behavior:

    E-commerce: 30 minutes (default)
    Content sites: 60 minutes
    Educational platforms: 90 minutes
    Video platforms: 120 minutes
    
  4. GA4 Admin setting:

    • Admin → Data Streams → Configure tag settings
    • Adjust session timeout
    • Click Save

Ensure cookies accessible across all pages:

  1. Set cookie domain to root domain:

    gtag('config', 'G-XXXXXXXXXX', {
      'cookie_domain': '.example.com' // Note the leading dot
    });
    
  2. For subdomains:

    // Works for www.example.com, shop.example.com, blog.example.com
    gtag('config', 'G-XXXXXXXXXX', {
      'cookie_domain': '.example.com',
      'cookie_flags': 'SameSite=None;Secure'
    });
    
  3. Auto domain configuration:

    gtag('config', 'G-XXXXXXXXXX', {
      'cookie_domain': 'auto' // Let GA4 determine
    });
    

Fix 3: Enable Cross-Domain Tracking

Maintain sessions across different domains:

  1. Configure linker for cross-domain:

    gtag('config', 'G-XXXXXXXXXX', {
      'linker': {
        'domains': ['example.com', 'shop.example.com', 'checkout.example.net']
      }
    });
    
  2. Automatic link decoration:

    // Automatically adds _gl parameter to links
    gtag('config', 'G-XXXXXXXXXX', {
      'linker': {
        'domains': ['example.com', 'checkout.thirdparty.com'],
        'accept_incoming': true,
        'decorate_forms': true
      }
    });
    
  3. Manual link decoration:

    // For dynamic links
    const decoratedUrl = new URL('https://checkout.example.net/cart');
    gtag('get', 'G-XXXXXXXXXX', 'linker_param', function(linkerParam) {
      decoratedUrl.searchParams.append('_gl', linkerParam);
      window.location.href = decoratedUrl.href;
    });
    
  4. GA4 Admin configuration:

    • Admin → Data Streams → Configure tag settings
    • Configure your domains
    • Add all related domains

Handle third-party cookie restrictions:

  1. Set SameSite=None for cross-domain:

    gtag('config', 'G-XXXXXXXXXX', {
      'cookie_flags': 'SameSite=None;Secure'
    });
    
  2. Ensure HTTPS is enabled:

    SameSite=None requires Secure flag
    Secure flag requires HTTPS
    Result: Must use HTTPS for cross-domain tracking
    
  3. Handle browser restrictions:

    // Detect browser support
    gtag('config', 'G-XXXXXXXXXX', {
      'cookie_flags': 'SameSite=None;Secure',
      'cookie_update': true
    });
    

Fix 5: Fix Single Page Application (SPA) Tracking

Maintain sessions during client-side navigation:

  1. Send page_view on route changes:

    // React Router example
    import { useEffect } from 'react';
    import { useLocation } from 'react-router-dom';
    
    function Analytics() {
      const location = useLocation();
    
      useEffect(() => {
        gtag('event', 'page_view', {
          page_path: location.pathname,
          page_title: document.title
        });
      }, [location]);
    
      return null;
    }
    
  2. Don't reinitialize analytics on navigation:

    // Bad - creates new session on every route
    router.on('navigate', () => {
      gtag('config', 'G-XXXXXXXXXX'); // Don't do this
    });
    
    // Good - only send page_view
    router.on('navigate', () => {
      gtag('event', 'page_view', {
        page_path: window.location.pathname
      });
    });
    
  3. Preserve data layer:

    // Ensure dataLayer persists across navigation
    window.dataLayer = window.dataLayer || [];
    
    // Don't reset dataLayer on route changes
    

Fix 6: Fix Redirect Chain Issues

Preserve sessions through redirects:

  1. Pass session parameters through redirects:

    // Server-side redirect (Node.js example)
    app.get('/old-page', (req, res) => {
      const query = new URLSearchParams(req.query).toString();
      res.redirect(301, `/new-page?${query}`);
    });
    
  2. Preserve UTM and tracking parameters:

    // Client-side redirect
    const currentParams = new URLSearchParams(window.location.search);
    const redirectUrl = new URL('https://example.com/new-page');
    
    // Preserve important parameters
    ['utm_source', 'utm_medium', 'utm_campaign', '_gl', 'gclid'].forEach(param => {
      if (currentParams.has(param)) {
        redirectUrl.searchParams.set(param, currentParams.get(param));
      }
    });
    
    window.location.href = redirectUrl.href;
    
  3. Use 301/302 redirects properly:

    301 Permanent: Preserves query parameters
    302 Temporary: Preserves query parameters
    JavaScript redirect: Must manually preserve parameters
    Meta refresh: Must include parameters in URL
    

Prevent unintentional cookie deletion:

  1. Don't delete analytics cookies:

    // Bad - clears analytics cookies
    document.cookie.split(";").forEach(c => {
      document.cookie = c.replace(/^ +/, "").replace(/=.*/, "=;expires=" + new Date().toUTCString() + ";path=/");
    });
    
    // Good - preserve analytics cookies
    function clearNonAnalyticsCookies() {
      const preserve = ['_ga', '_ga_', '_gid', '_gac'];
      document.cookie.split(";").forEach(c => {
        const name = c.trim().split('=')[0];
        const shouldPreserve = preserve.some(p => name.startsWith(p));
    
        if (!shouldPreserve) {
          document.cookie = name + "=;expires=" + new Date().toUTCString() + ";path=/";
        }
      });
    }
    
  2. Cookie consent handling:

    // When user accepts analytics cookies
    function enableAnalytics() {
      gtag('consent', 'update', {
        'analytics_storage': 'granted'
      });
    
      // Don't delete existing cookies
      // Let GA4 reuse existing client ID
    }
    
  3. Avoid cookie clearing on login/logout:

    // Preserve analytics cookies during auth changes
    function handleLogout() {
      // Clear user-specific data
      sessionStorage.clear();
    
      // Don't clear analytics cookies
      // Preserves session continuity
    }
    

Platform-Specific Guides

Detailed implementation instructions for your specific platform:

Platform Troubleshooting Guide
Shopify Shopify Session Stitching Guide
WordPress WordPress Session Stitching Guide
Wix Wix Session Stitching Guide
Squarespace Squarespace Session Stitching Guide
Webflow Webflow Session Stitching Guide

Verification

After implementing fixes:

  1. Perform end-to-end test:

    • Clear cookies in incognito window
    • Navigate through complete user journey
    • Check GA4 Realtime for single session
    • Verify all pages attributed to one session
  2. Test cross-domain navigation:

    • Navigate from main site to checkout
    • Check that session ID persists
    • Verify client ID remains same
    • Confirm attribution maintained
  3. Monitor session duration:

    • Check average session duration
    • Should increase after fixes
    • Compare before/after metrics
    • Look for reduction in new sessions
  4. Review funnel reports:

    • GA4 → Explore → Funnel exploration
    • Check drop-off rates between steps
    • Should see improvement in completion
    • Verify multi-step conversions tracked

Common Mistakes

  1. Cookie domain not set correctly - Missing leading dot
  2. Session timeout too short - Users exceed timeout
  3. Cross-domain tracking not configured - Sessions break at checkout
  4. SameSite cookies without Secure flag - Cookies blocked
  5. Analytics code reinitialized on SPA navigation - New session created
  6. Redirect chains lose parameters - Session tracking broken
  7. Cookie consent deletes analytics cookies - Session reset
  8. Different tracking codes on different pages - Separate sessions
  9. Subdomain cookie restrictions - Can't share session data
  10. Not testing in incognito - Cached cookies mask issue

Troubleshooting Checklist

  • Session timeout appropriate for site type
  • Cookie domain set to root domain with leading dot
  • Cross-domain tracking configured if needed
  • SameSite=None;Secure for cross-domain
  • HTTPS enabled across all domains
  • SPA page_view events firing correctly
  • Analytics code not reinitialized on navigation
  • Redirect chains preserve query parameters
  • Cookie consent preserves analytics cookies
  • Same GA4 property ID on all pages
  • Tested in incognito/private mode
  • GA4 DebugView shows single session

Additional Resources

// SYS.FOOTER