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
- Go to GA4 Admin → Data Streams
- Click your web stream
- Enable Enhanced measurement
- 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>
Download Link Tracking
<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>
Outbound Link Tracking
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
- Enable debug mode in your GA4 code:
gtag('config', 'G-XXXXXXXXXX', {
'debug_mode': true
});
- Visit your site and trigger events
- Check Admin → DebugView in GA4
- 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
- Install GTM - Easier event management
- Troubleshoot Events - Debug tracking issues
- GA4 Event Reference - Official documentation
For general event tracking concepts, see Google Analytics Event Tracking.