Weebly GA4 Event Tracking: Setup Guide | OpsBlu Docs

Weebly GA4 Event Tracking: Setup Guide

Track Weebly-specific events in GA4 including form submissions, button clicks, ecommerce events, and custom interactions.

Learn how to track Weebly-specific events in Google Analytics 4, including form submissions, button clicks, ecommerce events (via Square), and custom user interactions.

Prerequisites

Before implementing event tracking:

  • GA4 installed on Weebly
  • Weebly paid plan (Personal, Professional, or Performance for code access)
  • Access to Weebly's Header/Footer Code sections
  • Basic understanding of JavaScript (for custom events)

Implementation Methods

Method Best For Customization Plan Required
Enhanced Measurement Quick setup, standard events Low - automatic Any with GA4
Manual gtag.js Events Custom tracking needs Medium - code required Personal+
Google Tag Manager Complex tracking, multiple events High - visual interface Personal+

Enhanced Measurement (Automatic Events)

GA4's Enhanced Measurement tracks common interactions automatically. No Weebly code changes required!

Enable Enhanced Measurement

  1. In GA4, go to Admin → Data Streams
  2. Click your Web stream
  3. Toggle Enhanced Measurement ON
  4. Configure which events to track:
    • Page views (always on)
    • ✓ Scrolls (90% depth)
    • ✓ Outbound clicks
    • ✓ Site search
    • ✓ Video engagement (YouTube, Vimeo)
    • ✓ File downloads (PDF, DOC, etc.)

Events Tracked Automatically

page_view - Every page load including Weebly blog posts

scroll - User scrolls 90% of page depth

click - Outbound link clicks (links to external domains)

file_download - Downloads of: pdf, doc, docx, txt, rtf, csv, xls, xlsx, ppt, pptx, zip

video_start, video_progress, video_complete - Embedded YouTube/Vimeo videos

view_search_results - Weebly search results (if search enabled)

Custom Event Tracking on Weebly

Track Weebly-specific interactions with custom events using Header/Footer Code.

Access Weebly Code Injection

  1. In Weebly editor, click Settings → SEO
  2. Scroll to Header Code and Footer Code sections
  3. Add tracking code to appropriate section:
    • Header Code: For tracking that needs to load early
    • Footer Code: For tracking that can load after page content (recommended for performance)

Form Submissions

Track Weebly contact forms and lead forms.

Method 1: Generic Form Tracking

Add to Weebly's Footer Code section:

<script>
document.addEventListener('DOMContentLoaded', function() {
  // Track all Weebly forms
  const forms = document.querySelectorAll('form, .wsite-form-container form');

  forms.forEach(function(form) {
    form.addEventListener('submit', function(e) {
      const formName = this.getAttribute('name') ||
                       this.getAttribute('class') ||
                       'weebly_contact_form';

      // Don't prevent default - let Weebly handle submission
      gtag('event', 'form_submission', {
        'form_name': formName,
        'form_location': window.location.pathname,
        'form_type': 'contact_form'
      });
    });
  });
});
</script>

Method 2: Track Specific Weebly Forms

Weebly forms have specific classes you can target:

<script>
document.addEventListener('DOMContentLoaded', function() {
  // Track contact form
  const contactForm = document.querySelector('.wsite-form-container form');

  if (contactForm) {
    contactForm.addEventListener('submit', function(e) {
      gtag('event', 'contact_form_submit', {
        'form_type': 'contact',
        'page_path': window.location.pathname,
        'form_fields': this.querySelectorAll('input, textarea').length
      });
    });
  }

  // Track newsletter/email signup forms
  const emailForms = document.querySelectorAll('.wsite-form-type-email form');

  emailForms.forEach(function(form) {
    form.addEventListener('submit', function(e) {
      gtag('event', 'newsletter_signup', {
        'method': 'weebly_form',
        'page_path': window.location.pathname
      });
    });
  });
});
</script>

Method 3: Track Form Fields Completed

Track which form fields users interact with:

<script>
document.addEventListener('DOMContentLoaded', function() {
  const formInputs = document.querySelectorAll('form input, form textarea, form select');

  formInputs.forEach(function(input) {
    let interacted = false;

    input.addEventListener('blur', function() {
      if (!interacted && this.value.trim() !== '') {
        interacted = true;

        gtag('event', 'form_field_interaction', {
          'field_type': this.type || 'textarea',
          'field_name': this.name || this.id || 'unknown',
          'page_location': window.location.pathname
        });
      }
    });
  });
});
</script>

Button Click Tracking

Track important button clicks including CTAs:

<script>
document.addEventListener('DOMContentLoaded', function() {
  // Track Weebly button elements
  const buttons = document.querySelectorAll('.wsite-button, .wsite-button-normal, .wsite-button-highlight');

  buttons.forEach(function(button) {
    button.addEventListener('click', function() {
      const buttonText = this.textContent.trim();
      const buttonClass = this.className;
      const isHighlight = buttonClass.includes('highlight');

      gtag('event', 'button_click', {
        'button_text': buttonText,
        'button_location': window.location.pathname,
        'button_type': isHighlight ? 'highlight' : 'normal',
        'button_url': this.href || 'no_link'
      });
    });
  });

  // Track custom CTA buttons (if you've added custom classes)
  const ctaButtons = document.querySelectorAll('[data-track="cta"]');

  ctaButtons.forEach(function(button) {
    button.addEventListener('click', function() {
      gtag('event', 'cta_click', {
        'cta_text': this.textContent.trim(),
        'cta_location': window.location.pathname,
        'cta_destination': this.href || ''
      });
    });
  });
});
</script>

Phone Number Clicks (Click-to-Call)

Track when users click phone numbers on Weebly sites:

<script>
document.addEventListener('DOMContentLoaded', function() {
  const phoneLinks = document.querySelectorAll('a[href^="tel:"]');

  phoneLinks.forEach(function(link) {
    link.addEventListener('click', function() {
      const phoneNumber = this.getAttribute('href').replace('tel:', '');

      gtag('event', 'phone_call', {
        'phone_number': phoneNumber,
        'page_location': window.location.pathname,
        'link_text': this.textContent,
        'link_class': this.className
      });
    });
  });
});
</script>

Track mailto link clicks:

<script>
document.addEventListener('DOMContentLoaded', function() {
  const emailLinks = document.querySelectorAll('a[href^="mailto:"]');

  emailLinks.forEach(function(link) {
    link.addEventListener('click', function() {
      gtag('event', 'email_click', {
        'email_to': this.getAttribute('href').replace('mailto:', '').split('?')[0],
        'page_location': window.location.pathname,
        'link_text': this.textContent
      });
    });
  });
});
</script>

Track social media icon clicks in Weebly:

<script>
document.addEventListener('DOMContentLoaded', function() {
  // Weebly social icons have specific classes
  const socialLinks = document.querySelectorAll('.wsite-social-item a, a[href*="facebook.com"], a[href*="twitter.com"], a[href*="instagram.com"], a[href*="linkedin.com"], a[href*="youtube.com"]');

  socialLinks.forEach(function(link) {
    link.addEventListener('click', function() {
      let platform = 'unknown';
      const href = this.href.toLowerCase();

      if (href.includes('facebook.com')) platform = 'facebook';
      else if (href.includes('twitter.com') || href.includes('x.com')) platform = 'twitter';
      else if (href.includes('instagram.com')) platform = 'instagram';
      else if (href.includes('linkedin.com')) platform = 'linkedin';
      else if (href.includes('youtube.com')) platform = 'youtube';
      else if (href.includes('pinterest.com')) platform = 'pinterest';
      else if (href.includes('tiktok.com')) platform = 'tiktok';

      gtag('event', 'social_click', {
        'social_network': platform,
        'link_url': this.href,
        'page_location': window.location.pathname,
        'link_location': 'weebly_social_icons'
      });
    });
  });
});
</script>

Ecommerce Tracking (Weebly/Square Integration)

Weebly's ecommerce is powered by Square. Tracking ecommerce events requires accessing product data from the page.

Important Note: Weebly doesn't provide a native data layer for ecommerce. Square handles checkout, making comprehensive tracking limited. Consider using Square's analytics for detailed ecommerce data.

View Item (Product Page)

Track product page views by extracting data from the page:

<script>
document.addEventListener('DOMContentLoaded', function() {
  // Check if we're on a product page
  const productName = document.querySelector('.wsite-com-product-title');
  const productPrice = document.querySelector('.wsite-com-product-price');
  const productImage = document.querySelector('.wsite-com-product-images img');

  if (productName && productPrice) {
    const price = parseFloat(productPrice.textContent.replace(/[^0-9.]/g, ''));
    const name = productName.textContent.trim();

    gtag('event', 'view_item', {
      'currency': 'USD', // Change to your currency
      'value': price,
      'items': [{
        'item_name': name,
        'price': price,
        'quantity': 1
      }]
    });
  }
});
</script>

Add to Cart

Track add to cart button clicks:

<script>
document.addEventListener('DOMContentLoaded', function() {
  const addToCartButtons = document.querySelectorAll('.wsite-com-product-add-to-cart');

  addToCartButtons.forEach(function(button) {
    button.addEventListener('click', function() {
      // Get product data from page
      const productContainer = this.closest('.wsite-com-product-container');
      const productName = productContainer?.querySelector('.wsite-com-product-title')?.textContent?.trim();
      const productPrice = productContainer?.querySelector('.wsite-com-product-price')?.textContent;

      if (productName && productPrice) {
        const price = parseFloat(productPrice.replace(/[^0-9.]/g, ''));

        gtag('event', 'add_to_cart', {
          'currency': 'USD',
          'value': price,
          'items': [{
            'item_name': productName,
            'price': price,
            'quantity': 1
          }]
        });
      }
    });
  });
});
</script>

View Cart

Track when users view their shopping cart:

<script>
// Add to cart page
if (window.location.pathname.includes('/cart') || document.querySelector('.wsite-commerce-cart')) {
  gtag('event', 'view_cart', {
    'currency': 'USD'
    // Note: Cart items are in Square's iframe, so we can't easily access them
  });
}
</script>

Begin Checkout

<script>
document.addEventListener('DOMContentLoaded', function() {
  const checkoutButton = document.querySelector('.wsite-commerce-checkout-button');

  if (checkoutButton) {
    checkoutButton.addEventListener('click', function() {
      gtag('event', 'begin_checkout', {
        'currency': 'USD'
        // Cart total is in Square iframe, difficult to access
      });
    });
  }
});
</script>

Square Checkout Limitation: Weebly uses Square for checkout, which happens in an iframe or redirects to Square. You cannot track the final purchase event on Square's domain. Consider:

  • Using Square Analytics for purchase data
  • Server-side tracking via Square API
  • Conversion tracking via thank you page (if available)

Blog Engagement Tracking

Track Weebly blog post interactions:

Blog Post Views

<script>
// Detect if we're on a blog post
if (document.querySelector('.blog-post') || document.querySelector('.wsite-blog-post')) {
  const postTitle = document.querySelector('.blog-title, .wsite-blog-title')?.textContent?.trim();
  const postCategory = document.querySelector('.blog-category, .wsite-blog-category a')?.textContent?.trim();

  gtag('event', 'view_blog_post', {
    'blog_title': postTitle || 'Unknown',
    'blog_category': postCategory || 'Uncategorized',
    'page_location': window.location.pathname
  });
}
</script>

Time on Article

Track engaged time on blog posts:

<script>
if (document.querySelector('.blog-post, .wsite-blog-post')) {
  let startTime = Date.now();
  let engagementSent = false;

  window.addEventListener('beforeunload', function() {
    const timeSpent = Math.round((Date.now() - startTime) / 1000); // seconds

    if (timeSpent > 30 && !engagementSent) {
      gtag('event', 'blog_engagement', {
        'time_spent_seconds': timeSpent,
        'blog_title': document.querySelector('.blog-title')?.textContent?.trim(),
        'engaged': timeSpent > 60 ? 'yes' : 'no'
      });
      engagementSent = true;
    }
  });

  // Also track at 60 second mark
  setTimeout(function() {
    if (!engagementSent) {
      gtag('event', 'blog_engagement', {
        'time_spent_seconds': 60,
        'blog_title': document.querySelector('.blog-title')?.textContent?.trim(),
        'engaged': 'yes'
      });
      engagementSent = true;
    }
  }, 60000);
}
</script>

Blog Comments

Track comment submissions on Weebly blog:

<script>
document.addEventListener('DOMContentLoaded', function() {
  const commentForm = document.querySelector('.blog-comment-form form, #commentform');

  if (commentForm) {
    commentForm.addEventListener('submit', function() {
      gtag('event', 'blog_comment', {
        'blog_title': document.querySelector('.blog-title')?.textContent?.trim(),
        'page_location': window.location.pathname
      });
    });
  }
});
</script>

Track blog search usage:

<script>
document.addEventListener('DOMContentLoaded', function() {
  const blogSearch = document.querySelector('.blog-search input');

  if (blogSearch) {
    const blogSearchForm = blogSearch.closest('form');

    if (blogSearchForm) {
      blogSearchForm.addEventListener('submit', function() {
        gtag('event', 'search', {
          'search_term': blogSearch.value,
          'search_type': 'blog'
        });
      });
    }
  }
});
</script>

Video Tracking (Custom Players)

Enhanced Measurement tracks YouTube and Vimeo automatically. For custom HTML5 video:

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

  videos.forEach(function(video) {
    let videoStarted = false;

    video.addEventListener('play', function() {
      if (!videoStarted) {
        videoStarted = true;
        gtag('event', 'video_start', {
          'video_url': this.currentSrc,
          'video_title': this.title || 'Untitled Video',
          'page_location': window.location.pathname
        });
      }
    });

    video.addEventListener('ended', function() {
      gtag('event', 'video_complete', {
        'video_url': this.currentSrc,
        'video_title': this.title || 'Untitled Video',
        'page_location': window.location.pathname
      });
    });

    // Track 50% progress
    video.addEventListener('timeupdate', function() {
      const progress = (this.currentTime / this.duration) * 100;

      if (progress >= 50 && !this.dataset.halfwayTracked) {
        this.dataset.halfwayTracked = 'true';
        gtag('event', 'video_progress', {
          'video_url': this.currentSrc,
          'video_title': this.title || 'Untitled Video',
          'video_percent': 50
        });
      }
    });
  });
});
</script>

Track Weebly menu interactions:

<script>
document.addEventListener('DOMContentLoaded', function() {
  // Track main menu clicks
  const menuLinks = document.querySelectorAll('.wsite-menu-default a, .wsite-menu a');

  menuLinks.forEach(function(link) {
    link.addEventListener('click', function() {
      gtag('event', 'menu_click', {
        'menu_text': this.textContent.trim(),
        'menu_url': this.href,
        'current_page': window.location.pathname
      });
    });
  });

  // Track hamburger menu toggle (mobile)
  const hamburger = document.querySelector('.hamburger, .wsite-menu-hamburger');

  if (hamburger) {
    hamburger.addEventListener('click', function() {
      gtag('event', 'mobile_menu_toggle', {
        'page_location': window.location.pathname
      });
    });
  }
});
</script>

Membership/Login Tracking

For Weebly sites with membership areas:

<script>
document.addEventListener('DOMContentLoaded', function() {
  // Track login form
  const loginForm = document.querySelector('.wsite-membership-login-form');

  if (loginForm) {
    loginForm.addEventListener('submit', function() {
      gtag('event', 'login', {
        'method': 'weebly_membership',
        'page_location': window.location.pathname
      });
    });
  }

  // Track sign up
  const signupForm = document.querySelector('.wsite-membership-signup-form');

  if (signupForm) {
    signupForm.addEventListener('submit', function() {
      gtag('event', 'sign_up', {
        'method': 'weebly_membership',
        'page_location': window.location.pathname
      });
    });
  }
});
</script>

Error Tracking

Track 404 pages and errors:

<script>
// Track 404 pages
if (document.title.toLowerCase().includes('404') ||
    document.querySelector('.wsite-404') ||
    window.location.pathname.includes('/404')) {

  gtag('event', 'exception', {
    'description': '404_page_not_found',
    'page_location': window.location.pathname,
    'fatal': false
  });
}

// Track JavaScript errors
window.addEventListener('error', function(e) {
  gtag('event', 'exception', {
    'description': 'JavaScript error: ' + e.message,
    'fatal': false
  });
});
</script>

Using Google Tag Manager for Events

For complex event tracking, GTM is recommended over manual code.

Advantages of GTM for Weebly

  • No Weebly code changes needed after GTM installation
  • Visual interface for creating triggers
  • Built-in variables for clicks, forms, etc.
  • Easy to test with Preview mode
  • Version control and rollback capability

Example: Form Submission via GTM

1. Install GTM on Weebly

2. Create Form Submission Trigger

  • Type: Form Submission
  • Wait for Tags: Enable
  • Check Validation: Enable
  • Trigger fires on: All Forms

3. Create GA4 Event Tag

  • Type: Google Analytics: GA4 Event
  • Event Name: form_submission
  • Event Parameters:
    • form_id: {{Form ID}}
    • form_classes: {{Form Classes}}
    • page_path: {{Page Path}}
  • Trigger: Form Submission trigger

4. Test and Publish

  • Use GTM Preview mode
  • Submit a Weebly form
  • Verify event fires in Tag Assistant
  • Check in GA4 DebugView
  • Publish container when confirmed

Testing & Debugging

1. GA4 DebugView

Enable debug mode temporarily (add to Header Code):

<script>
gtag('config', 'G-XXXXXXXXXX', {
  'debug_mode': true
});
</script>

Then check Admin → DebugView in GA4 to see events in real-time with all parameters.

2. Browser Console Testing

Test events manually in browser console:

// Open browser console (F12) on your Weebly site
// Test an event:
gtag('event', 'test_event', {
  'test_parameter': 'test_value'
});

// Then check GA4 Realtime or DebugView

3. Verify Events Are Firing

Check if gtag is loaded:

// In browser console:
console.log(typeof gtag);
// Should return "function", not "undefined"

// Check data layer:
console.log(window.dataLayer);
// Should show array with events

4. Common Testing Issues

Event doesn't fire:

  • Check if selector matches element (use browser inspector)
  • Ensure code is in Footer Code (runs after DOM loads)
  • Check browser console for JavaScript errors
  • Verify GA4 is installed correctly

Event fires multiple times:

  • Check if code is added in multiple locations
  • Use { once: true } option on event listeners
  • Add flags to prevent duplicate sends

Event Naming Best Practices

Use GA4's recommended event names when possible:

  • view_item - Product views
  • add_to_cart - Add to cart
  • begin_checkout - Start checkout
  • purchase - Completed purchase (not accessible on Weebly/Square)
  • search - Site/blog search
  • sign_up - Account creation
  • login - User login

Custom Event Naming

For custom events, follow these guidelines:

  • Use lowercase
  • Use underscores (snake_case)
  • Be descriptive but concise
  • Examples: phone_call, newsletter_signup, blog_comment

Avoid:

  • CamelCase: formSubmission
  • Spaces: form submission
  • Special characters: form-submission!
  • Generic names: click, event1

Event Parameters Best Practices

Common Parameters

Standard parameters to include:

  • page_location: window.location.pathname
  • page_title: document.title
  • button_text or link_text: Element text content
  • form_name or form_id: Form identifier

Value and Currency

For ecommerce events:

  • value: Must be numeric (no symbols)
  • currency: Use ISO 4217 code (USD, EUR, GBP, etc.)

Items Array

For product events, use proper structure:

'items': [{
  'item_id': 'SKU123',       // Product SKU or ID
  'item_name': 'Product Name', // Product name
  'price': 29.99,            // Numeric price
  'quantity': 1              // Quantity
}]

Common Issues

Events Fire Multiple Times

Cause: Event listeners added multiple times or duplicate code

Fix:

// Add 'once' option to event listeners
button.addEventListener('click', function() {
  gtag('event', 'button_click', {
    'button_text': this.textContent
  });
}, { once: true });

Events Don't Fire

Causes:

  • Element selector doesn't match Weebly's HTML
  • Code runs before DOM is ready
  • JavaScript error in console

Fix:

  • Always wrap code in DOMContentLoaded
  • Check browser console for errors (F12)
  • Use browser inspector to find correct selectors
  • Test in incognito mode (disable extensions)

Form Submissions Don't Track

Cause: Form submits and page reloads before event sends

Fix: Use event callback (though Weebly forms redirect, so this is limited):

form.addEventListener('submit', function(e) {
  // GA4 will attempt to send before page unloads
  gtag('event', 'form_submission', {
    'transport_type': 'beacon' // Uses navigator.sendBeacon for reliability
  });
  // Don't prevent default - let Weebly handle form
});

Ecommerce Events Incomplete

Cause: Weebly uses Square for checkout, which is in iframe/separate domain

Solution:

  • Accept limited ecommerce tracking on Weebly side
  • Use Square Analytics for complete purchase data
  • Track what you can: product views, add to cart, begin checkout
  • Purchase event can't be tracked client-side on Weebly

Performance Considerations

Code Placement

Use Footer Code for tracking:

  • Loads after page content
  • Doesn't block page rendering
  • Better for Core Web Vitals

Use Header Code only if:

  • Need to track early page events
  • Setting up data layer before GTM
  • Implementing consent management

Minimize Code Weight

  • Combine multiple event listeners into single scripts
  • Avoid loading external libraries just for tracking
  • Use GTM to consolidate tracking code

Test Performance Impact

Check site speed after adding tracking:

Privacy & Compliance

If you need cookie consent (GDPR, CCPA):

<script>
// Check consent before initializing GA4
if (localStorage.getItem('analytics_consent') === 'granted') {
  gtag('consent', 'update', {
    'analytics_storage': 'granted'
  });
} else {
  gtag('consent', 'default', {
    'analytics_storage': 'denied'
  });
}
</script>

User Privacy

Best practices:

  • Don't track personally identifiable information (PII)
  • Don't send email addresses or phone numbers to GA4
  • Use hashed identifiers if needed
  • Respect Do Not Track settings (optional)

Next Steps

For general event tracking concepts, see GA4 Event Tracking Guide.