Zyro GA4 Event Tracking: Setup Guide | OpsBlu Docs

Zyro GA4 Event Tracking: Setup Guide

Implement custom event tracking for Zyro sites including form submissions, button clicks, and user interactions.

Beyond basic page views, track user interactions on your Zyro site with custom GA4 events. This guide covers Zyro-specific event implementation.

Prerequisite: Complete GA4 Setup before implementing custom events.

Event Tracking Methods

Method Difficulty Use Case
Enhanced Measurement Easy Automatic scrolls, clicks, video
Direct gtag Events Medium Custom button/form tracking
GTM Events Medium-Hard Complex multi-tag tracking

Enhanced Measurement (Automatic Events)

Enable in GA4 for automatic tracking without additional code.

Enable Enhanced Measurement

  1. Go to GA4 AdminData Streams
  2. Click your web stream
  3. Enable Enhanced measurement
  4. Configure which events to track:

Available Events:

  • Page views - Automatic
  • Scrolls - When user scrolls 90%
  • Outbound clicks - Clicks to external sites
  • Site search - If you have search functionality
  • Video engagement - YouTube/Vimeo plays
  • File downloads - PDF, DOC, etc.

Customize Enhanced Measurement

// Modify scroll threshold
gtag('config', 'G-XXXXXXXXXX', {
  'send_page_view': true,
  'scroll_threshold': 75 // Track at 75% instead of 90%
});

Tracking Zyro Forms

Track contact form submissions on your Zyro site.

Basic Form Tracking

Add this code to Settings → Website code → Footer code:

<script>
document.addEventListener('DOMContentLoaded', function() {
  // Zyro forms typically have class '.zyro-form' or 'form'
  const forms = document.querySelectorAll('.zyro-form, form');

  forms.forEach(function(form, index) {
    form.addEventListener('submit', function(e) {
      // Get form identifier
      const formName = form.getAttribute('name') ||
                      form.id ||
                      'form-' + index;

      gtag('event', 'form_submit', {
        'form_name': formName,
        'form_type': 'contact'
      });
    });
  });
});
</script>

Advanced Form Tracking with Fields

Track which fields users submit:

<script>
document.addEventListener('DOMContentLoaded', function() {
  const forms = document.querySelectorAll('form');

  forms.forEach(function(form, index) {
    form.addEventListener('submit', function(e) {
      const formName = form.getAttribute('name') || 'form-' + index;

      // Get form fields submitted
      const formData = new FormData(form);
      const fields = [];
      formData.forEach(function(value, key) {
        fields.push(key);
      });

      gtag('event', 'form_submit', {
        'form_name': formName,
        'fields_submitted': fields.join(','),
        'field_count': fields.length
      });
    });
  });
});
</script>

Newsletter Signup Tracking

<script>
document.addEventListener('DOMContentLoaded', function() {
  // Track newsletter signups
  const newsletterForms = document.querySelectorAll('form[action*="subscribe"], form[action*="newsletter"]');

  newsletterForms.forEach(function(form) {
    form.addEventListener('submit', function(e) {
      gtag('event', 'newsletter_signup', {
        'method': 'website_form',
        'location': getFormLocation(form)
      });
    });
  });

  function getFormLocation(element) {
    // Determine which section contains the form
    const section = element.closest('section, .section');
    return section ? (section.id || 'unknown') : 'footer';
  }
});
</script>

Button Click Tracking

Track CTA buttons and important interactions.

Generic Button Tracking

<script>
document.addEventListener('DOMContentLoaded', function() {
  // Track all buttons with data-event attribute
  document.addEventListener('click', function(e) {
    const button = e.target.closest('[data-event]');

    if (button) {
      const eventName = button.getAttribute('data-event');
      const eventLabel = button.getAttribute('data-label') ||
                        button.textContent.trim();

      gtag('event', eventName, {
        'event_category': 'button',
        'event_label': eventLabel,
        'button_text': button.textContent.trim()
      });
    }
  });
});
</script>

HTML Usage: Add data-event attribute to buttons in Zyro editor:

<button data-event="cta_click" data-label="Get Started">
  Get Started
</button>

Specific CTA Tracking

Track Zyro's button elements:

<script>
document.addEventListener('DOMContentLoaded', function() {
  // Track Zyro buttons
  const ctaButtons = document.querySelectorAll('.zyro-button, button, .btn');

  ctaButtons.forEach(function(button) {
    button.addEventListener('click', function() {
      gtag('event', 'cta_click', {
        'event_category': 'engagement',
        'event_label': button.textContent.trim(),
        'cta_location': getElementLocation(button)
      });
    });
  });

  function getElementLocation(element) {
    const section = element.closest('section, [data-section]');
    if (section) {
      return section.id || section.dataset.section || 'unknown';
    }
    return 'unknown';
  }
});
</script>
<script>
document.addEventListener('click', function(e) {
  const link = e.target.closest('a');

  if (link && link.href) {
    const href = link.href;
    const fileExtensions = /\.(pdf|doc|docx|xls|xlsx|zip|rar|txt|csv)$/i;

    if (fileExtensions.test(href)) {
      const fileName = href.split('/').pop();

      gtag('event', 'file_download', {
        'event_category': 'download',
        'event_label': fileName,
        'file_type': href.split('.').pop().toLowerCase()
      });
    }
  }
});
</script>

Track clicks to external websites:

<script>
document.addEventListener('DOMContentLoaded', function() {
  document.addEventListener('click', function(e) {
    const link = e.target.closest('a');

    if (link && link.href) {
      // Check if external link
      const isExternal = link.hostname !== window.location.hostname;

      if (isExternal) {
        gtag('event', 'outbound_click', {
          'event_category': 'outbound',
          'event_label': link.href,
          'link_text': link.textContent.trim(),
          'link_domain': link.hostname
        });
      }
    }
  });
});
</script>

Zyro E-commerce Events

Track Zyro eCommerce store interactions (requires eCommerce plan).

Product View Events

<script>
document.addEventListener('DOMContentLoaded', function() {
  const productItems = document.querySelectorAll('.product-item, [data-product]');

  productItems.forEach(function(item) {
    item.addEventListener('click', function() {
      const productName = item.querySelector('.product-name, h3')?.textContent || 'Unknown';
      const productPrice = item.querySelector('.product-price, .price')?.textContent || '0';
      const productId = item.dataset.productId || item.dataset.id || 'unknown';

      gtag('event', 'view_item', {
        'currency': 'USD',
        'value': parsePrice(productPrice),
        'items': [{
          'item_id': productId,
          'item_name': productName,
          'price': parsePrice(productPrice)
        }]
      });
    });
  });

  function parsePrice(priceString) {
    return parseFloat(priceString.replace(/[^0-9.]/g, '')) || 0;
  }
});
</script>

Add to Cart Event

<script>
document.addEventListener('click', function(e) {
  const addToCartBtn = e.target.closest('.add-to-cart, [data-add-to-cart]');

  if (addToCartBtn) {
    const productContainer = addToCartBtn.closest('.product-item, [data-product]');
    const productName = productContainer?.querySelector('.product-name, h3')?.textContent || 'Unknown';
    const productPrice = productContainer?.querySelector('.product-price, .price')?.textContent || '0';
    const productId = productContainer?.dataset.productId || 'unknown';

    gtag('event', 'add_to_cart', {
      'currency': 'USD',
      'value': parsePrice(productPrice),
      'items': [{
        'item_id': productId,
        'item_name': productName,
        'price': parsePrice(productPrice),
        'quantity': 1
      }]
    });
  }

  function parsePrice(priceString) {
    return parseFloat(priceString.replace(/[^0-9.]/g, '')) || 0;
  }
});
</script>

Purchase Event (Thank You Page)

Add to custom code on your order confirmation page:

<script>
// Only fire on order confirmation page
if (window.location.pathname.includes('/order-confirmation') ||
    window.location.search.includes('order_id=')) {

  gtag('event', 'purchase', {
    'transaction_id': getOrderId(),
    'value': getTotalValue(),
    'currency': 'USD',
    'tax': getTax(),
    'shipping': getShipping(),
    'items': getOrderItems()
  });
}

function getOrderId() {
  // Extract from URL or page content
  const urlParams = new URLSearchParams(window.location.search);
  return urlParams.get('order_id') || 'unknown';
}

function getTotalValue() {
  // Extract from page content
  const totalElement = document.querySelector('.order-total, .total-price');
  if (totalElement) {
    return parseFloat(totalElement.textContent.replace(/[^0-9.]/g, '')) || 0;
  }
  return 0;
}

function getTax() {
  const taxElement = document.querySelector('.tax-amount');
  return taxElement ? parseFloat(taxElement.textContent.replace(/[^0-9.]/g, '')) : 0;
}

function getShipping() {
  const shippingElement = document.querySelector('.shipping-amount');
  return shippingElement ? parseFloat(shippingElement.textContent.replace(/[^0-9.]/g, '')) : 0;
}

function getOrderItems() {
  const items = [];
  const orderItems = document.querySelectorAll('.order-item');

  orderItems.forEach(function(item) {
    items.push({
      'item_id': item.dataset.productId || 'unknown',
      'item_name': item.querySelector('.item-name')?.textContent || 'Unknown',
      'price': parseFloat(item.querySelector('.item-price')?.textContent.replace(/[^0-9.]/g, '')) || 0,
      'quantity': parseInt(item.querySelector('.item-quantity')?.textContent) || 1
    });
  });

  return items;
}
</script>

Scroll Depth Tracking

More granular scroll tracking than Enhanced Measurement:

<script>
document.addEventListener('DOMContentLoaded', function() {
  const scrollThresholds = [25, 50, 75, 100];
  const triggeredThresholds = new Set();

  window.addEventListener('scroll', function() {
    const scrollPercentage = (window.scrollY + window.innerHeight) / document.body.scrollHeight * 100;

    scrollThresholds.forEach(function(threshold) {
      if (scrollPercentage >= threshold && !triggeredThresholds.has(threshold)) {
        triggeredThresholds.add(threshold);

        gtag('event', 'scroll', {
          'event_category': 'engagement',
          'event_label': threshold + '%',
          'percent_scrolled': threshold
        });
      }
    });
  });
});
</script>

Time on Site Tracking

Track engaged time on site:

<script>
let startTime = Date.now();
let isActive = true;
let lastActivityTime = Date.now();

// Track active time
document.addEventListener('visibilitychange', function() {
  if (document.hidden) {
    isActive = false;
    sendTimeEngaged();
  } else {
    isActive = true;
    lastActivityTime = Date.now();
  }
});

// Reset activity timer on user interaction
['mousedown', 'keydown', 'scroll', 'touchstart'].forEach(function(event) {
  document.addEventListener(event, function() {
    lastActivityTime = Date.now();
  });
});

// Send engaged time every 30 seconds
setInterval(function() {
  if (isActive && (Date.now() - lastActivityTime < 5000)) {
    sendTimeEngaged();
  }
}, 30000);

function sendTimeEngaged() {
  const timeEngaged = Math.round((Date.now() - startTime) / 1000);

  gtag('event', 'time_engaged', {
    'event_category': 'engagement',
    'event_label': Math.floor(timeEngaged / 60) + ' minutes',
    'value': timeEngaged
  });
}

// Send on page unload
window.addEventListener('beforeunload', sendTimeEngaged);
</script>

Testing and Debugging

Test Events in GA4 DebugView

  1. Enable debug mode in your GA4 code:
gtag('config', 'G-XXXXXXXXXX', {
  'debug_mode': true
});
  1. Visit your site and trigger events
  2. Check AdminDebugView in GA4
  3. Verify events appear with correct parameters

Console Logging for Development

// Add to Footer Code for debugging
<script>
const originalGtag = window.gtag;
window.gtag = function() {
  console.log('GA4 Event:', arguments);
  if (originalGtag) {
    originalGtag.apply(this, arguments);
  }
};
</script>

Browser Console Testing

Test events directly in console:

// Test an event
gtag('event', 'test_event', {
  'event_category': 'test',
  'event_label': 'manual test'
});

Best Practices

Event Naming

  • Use lowercase with underscores: form_submit, cta_click
  • Be descriptive but concise
  • Follow GA4 recommended events when possible
  • Consistent naming across similar events

Event Parameters

  • Include relevant context (location, value, type)
  • Keep parameter names consistent
  • Don't send PII (personally identifiable information)
  • Limit to 25 custom parameters per event

Performance

  • Don't track every micro-interaction
  • Use debouncing for scroll/resize events
  • Test impact on page load time
  • Monitor LCP

Data Quality

  • Test all events thoroughly before launch
  • Monitor in GA4 for duplicate events
  • Validate event parameters are correct
  • Document all custom events

Complete Event Tracking Code

Comprehensive starter template for Zyro sites:

<script>
// Add to Footer Code (after GA4 initialization)
(function() {
  'use strict';

  // Wait for DOM
  if (document.readyState === 'loading') {
    document.addEventListener('DOMContentLoaded', init);
  } else {
    init();
  }

  function init() {
    trackForms();
    trackButtons();
    trackOutboundLinks();
    trackScrollDepth();
  }

  // Form submission tracking
  function trackForms() {
    const forms = document.querySelectorAll('form');
    forms.forEach(function(form, i) {
      form.addEventListener('submit', function() {
        gtag('event', 'form_submit', {
          'form_name': form.name || form.id || 'form-' + i
        });
      });
    });
  }

  // Button click tracking
  function trackButtons() {
    document.addEventListener('click', function(e) {
      const btn = e.target.closest('button, .zyro-button, [data-event]');
      if (btn) {
        gtag('event', btn.dataset.event || 'button_click', {
          'event_label': btn.textContent.trim()
        });
      }
    });
  }

  // Outbound link tracking
  function trackOutboundLinks() {
    document.addEventListener('click', function(e) {
      const link = e.target.closest('a');
      if (link && link.hostname !== window.location.hostname) {
        gtag('event', 'outbound_click', {
          'event_label': link.href
        });
      }
    });
  }

  // Scroll depth tracking
  function trackScrollDepth() {
    const depths = [25, 50, 75, 100];
    const reached = new Set();
    window.addEventListener('scroll', function() {
      const pct = (window.scrollY + window.innerHeight) / document.body.scrollHeight * 100;
      depths.forEach(function(d) {
        if (pct >= d && !reached.has(d)) {
          reached.add(d);
          gtag('event', 'scroll', {
            'percent_scrolled': d
          });
        }
      });
    });
  }
})();
</script>

Next Steps

For general event tracking concepts, see Google Analytics Event Tracking.