How to send events to Google Analytics from a block (JS) in WordPress

Contents

Overview

This article explains, in full detail, how to send Google Analytics events from a WordPress block (Gutenberg) using JavaScript. It covers GA4 vs Universal Analytics, adding the tracker to WordPress, sending events from the block on the front-end and in the editor, using Google Tag Manager (dataLayer), recommended event schema and parameters, debugging and verification, privacy/consent concerns, server-side fallbacks, and best practices for robust implementation. Code examples are included for PHP, JavaScript, and configuration. Each example is placed inside the required pre block with the correct language attribute.

Prerequisites

  • WordPress site with the Gutenberg editor enabled (WordPress 5.0 recommended).
  • Familiarity with basic Gutenberg block development (registerBlockType, edit, save).
  • A Google Analytics 4 (GA4) property and a Measurement ID (G-XXXXXXX). GA4 is the recommended platform Universal Analytics (UA) is deprecated.
  • Optional: Google Tag Manager container if you prefer GTM for centralized tag management.
  • Build toolchain if you use modern ESNext block development (recommended: @wordpress/scripts). Examples below include both ESNext-style and no-build minimal registrations.

GA4 vs Universal Analytics — which to use?

Google Analytics 4 (GA4) is the current tracking platform. If you have a newer property use GA4 and the gtag.js API or Google Tag Manager. Universal Analytics (analytics.js) is deprecated do not start new projects on UA. All examples below will focus on GA4 with notes about GTM and a short UA example only for legacy compatibility.

How Google Analytics events work (GA4)

  • Tracking library: gtag.js or via Google Tag Managers dataLayer.
  • Event format: gtag(event, , { })
  • Events can be custom (recommended lower_snake_case) and can include arbitrary parameters (strings, numbers, booleans).
  • GA4 emphasizes event-driven measurement you should design event names and parameters for analysis.

Adding the GA4 snippet to a WordPress site

You must ensure the GA4 snipped (gtag.js) or Google Tag Manager container is present on pages where the block will send events. Two main approaches:

  1. Direct gtag.js snippet in the head (basic simplest).
  2. Google Tag Manager (preferred for advanced setups) where your block pushes to the dataLayer and GTM handles sending to GA4.

1) Direct gtag.js snippet (recommended minimal)

Paste the GA4 gtag snippet to your site head. Using wp_head via theme or using a plugin is common. The measurement ID must be your property ID.


window.dataLayer = window.dataLayer  []
function gtag(){dataLayer.push(arguments)}
gtag(js, new Date())
gtag(config, G-XXXXXXX, { send_page_view: true })

2) Google Tag Manager (GTM)

If you use GTM, include the GTM container snippet. Then your block should push event objects into the dataLayer and the GTM tag will forward them to GA4. GTM allows more flexible control, consent handling, and non-developer tag changes.

// Example dataLayer push for a custom event
window.dataLayer = window.dataLayer  []
window.dataLayer.push({
  event: my_block_clicked,
  blockName: fancy-cta,
  action: click,
  label: hero_cta,
  value: 1
})

Registering block assets in WordPress (PHP)

Register and enqueue your blocks front-end script and editor script properly. The front-end script is where you send analytics events for user interactions on the public site. Use wp_register_script and register_block_type or the block.json workflow.

 G-XXXXXXX, // optional - or set to empty if using GTM
        useGtm => false,
    ) )

    register_block_type( my-plugin/fancy-block, array(
        editor_script => my-block-editor,
        script => my-block-frontend, // front-end script
        // style => my-block-style  // optional
    ) )
}
add_action( init, my_block_register_assets )
?>

Block JavaScript: minimal ESNext example (edit save) and sending an event from the frontend

Below is a simple block using @wordpress/blocks and @wordpress/components. The important part is the front-end JavaScript code that triggers an event when a user interacts with the element (for example, clicking a CTA inside the block). In the examples below, I provide:

  • Editor code (edit and save) to render markup and allow attributes.
  • Frontend code that listens for events and sends GA4 events using gtag or pushes to dataLayer for GTM setups.

Editor (block registration) – ESNext style

import { registerBlockType } from @wordpress/blocks
import { Button } from @wordpress/components
import { useBlockProps } from @wordpress/block-editor

registerBlockType(my-plugin/fancy-block, {
    title: Fancy CTA,
    category: widgets,
    attributes: {
        buttonText: { type: string, default: Click me },
        buttonId: { type: string, default: fancy_cta },
    },
    edit: (props) => {
        const blockProps = useBlockProps()
        const { attributes, setAttributes } = props
        return (
            
setAttributes({ buttonText: e.target.value })} />

Preview of the button:

) }, save: (props) => { const blockProps = useBlockProps.save() const { attributes } = props // The button is rendered on the front-end, where analytics will be captured return (
) }, })

Frontend JavaScript to send events (vanilla JS) — gtag and GTM examples

Create a front-end script (registered above as my-block-frontend) that attaches event listeners to elements your block outputs and sends analytics events. Always check whether gtag or dataLayer is available to avoid errors, and use defensive coding.

// frontend.js - executed on pages where the block is present
(function() {
  use strict

  // Config passed via wp_localize_script or window global example variable: MyBlockAnalyticsConfig
  var config = window.MyBlockAnalyticsConfig  {}
  var measurementId = config.measurementId  null
  var useGtm = !!config.useGtm

  // Helper: send event using gtag (GA4)
  function sendGtagEvent(eventName, params) {
    if (typeof window.gtag === function) {
      try {
        window.gtag(event, eventName, params  {})
      } catch (err) {
        // swallow errors to not break page
        console.error(gtag error, err)
      }
    } else {
      // If gtag isnt available, optionally fallback to dataLayer push
      if (window.dataLayer  Array.isArray(window.dataLayer)) {
        window.dataLayer.push(Object.assign({ event: eventName }, params  {}))
      }
    }
  }

  // Helper: push to dataLayer (for GTM)
  function pushDataLayer(eventName, params) {
    window.dataLayer = window.dataLayer  []
    var pushObj = Object.assign({ event: eventName }, params  {})
    window.dataLayer.push(pushObj)
  }

  // Attach to block nodes, look for the class used in save: .my-fancy-cta
  function initBlockTracking(root) {
    root = root  document
    var buttons = root.querySelectorAll(.my-fancy-cta)
    buttons.forEach(function(btn) {
      // Guard against attaching multiple listeners
      if (btn.dataset.analyticsAttached === 1) return
      btn.dataset.analyticsAttached = 1

      btn.addEventListener(click, function(event) {
        var id = btn.id  unknown_cta
        var label = btn.textContent.trim()  id

        // Standard GA4 event naming: custom events should be snake_case or lowercase
        var eventName = fancy_cta_click

        // Choose sending method
        if (useGtm) {
          pushDataLayer(eventName, {
            block_name: fancy_cta,
            action: click,
            label: label,
            element_id: id
          })
        } else {
          sendGtagEvent(eventName, {
            block_name: fancy_cta,
            action: click,
            label: label,
            element_id: id
          })
        }

        // Additional optional actions: analytics   local UI update
        // example: analytics   navigate
      })
    })
  }

  // Initialize on DOMContentLoaded and also for new nodes (e.g., AJAX)
  document.addEventListener(DOMContentLoaded, function() {
    initBlockTracking(document)
  })

  // Optional: if your site loads content asynchronously, use MutationObserver
  var observer = new MutationObserver(function(mutations) {
    mutations.forEach(function(mutation) {
      if (mutation.addedNodes  mutation.addedNodes.length) {
        mutation.addedNodes.forEach(function(node) {
          if (node.nodeType === 1) {
            initBlockTracking(node)
          }
        })
      }
    })
  })
  observer.observe(document.documentElement  document.body, {
    childList: true,
    subtree: true
  })

})()

GTM-specific approach: push detailed structured data and map in GTM

If you use Google Tag Manager, prefer pushing well-structured objects to the dataLayer and then configure GTM Triggers and GA4 Event tags using those dataLayer events. Example below shows event structure and a recommended naming convention.

// Recommended structure for an analytics event pushed to dataLayer
window.dataLayer = window.dataLayer  []
window.dataLayer.push({
  event: fancy_block_action, // dataLayer event name
  analytics: {
    category: fancy_block,
    action: click,
    label: hero_cta,
    value: 1
  },
  block: {
    id: fancy_cta,
    variant: primary,
    author: site-team
  }
})

In GTM, create a Trigger that listens for event name fancy_block_action and configure a GA4 Event tag to use fields from the dataLayer (e.g., analytics.action as the event name or set a fixed event name and populate parameters with values from the analytics object).

Event naming and parameter recommendations (GA4)

Event name Use short, descriptive names in lowercase and underscores, e.g., fancy_cta_click
Parameters GA4 supports arbitrary key/value params. Recommended keys: block_name, action, label, element_id, value, content_type. Use consistent keys across site.
Reserved GA4 params GA4 has recommended params like content_type, item_id, value. Use them when appropriate custom params are fine but you may need to register custom dimensions in GA4 UI for reporting.

Universal Analytics legacy example (analytics.js)

If youre still using Universal Analytics (legacy), events follow category/action/label convention. This is shown for completeness only — GA4 is recommended.

// UA legacy event
if (typeof window.ga === function) {
  ga(send, event, fancy_block, click, hero_cta, 1)
}

Server-side fallback: Measurement Protocol for GA4

If JavaScript is blocked or for reliable conversion measurement, you can send events server-side via GA4s Measurement Protocol. This is an advanced topic: you need the API secret and measurement ID do not expose the secret in client code. Use server-side code to POST events to the GA4 endpoint and validate outcomes.

// Example fetch to your server endpoint that then calls GA4 Measurement Protocol.
// Client-side sends a minimal request to your server:
fetch(/wp-json/myplugin/v1/track-event, {
  method: POST,
  headers: {Content-Type: application/json},
  body: JSON.stringify({ event: fancy_cta_click, params: { label: hero_cta }})
})
 POST,
    callback => myplugin_track_event,
    permission_callback => __return_true, // secure appropriately
  ) )
} )

function myplugin_track_event( request ) {
  data = request->get_json_params()
  // Validate and sanitize data, then send to GA4 Measurement Protocol server-side using secret
  // POST to https://www.google-analytics.com/mp/collect?measurement_id=G-XXXXXXXapi_secret=YOUR_SECRET
  // Build payload per Measurement Protocol docs
  return rest_ensure_response( array( success => true ) )
}
?>

Debugging and verification

  • Use GA4 DebugView: in the GA console enable DebugView or use the gtag debug_mode parameter.
  • Check the browsers network tab for requests to www.google-analytics.com/g/collect or GTM requests.
  • Use console.log in development to verify events are triggered (remove logs for production).
  • If using GTM, use the GTM Preview mode to see dataLayer pushes and whether tags fire.

Privacy, consent, and GDPR considerations

  • Respect user consent. Delay or block analytics until consent is granted. If using GTM or gtag, configure consent mode if needed.
  • Do not send personally identifiable information (PII) — names, email addresses, or other identifying strings should not be sent to GA.
  • Consider anonymizing IP (GA4 has built-in IP handling) and implementing cookie consent logic that prevents tracking before consent.

Best practices and hardening

  1. Defensive coding: always check for window.gtag or window.dataLayer before calling.
  2. Debounce rapid events (e.g., multiple clicks) or aggregate where appropriate to reduce noise.
  3. Use consistent naming conventions and parameter keys across all blocks and events for reliable analysis.
  4. Register custom parameters as custom dimensions/metrics in GA4 if you need them in UI reports.
  5. Do not send high-cardinality data (like raw user IDs) as parameter values without a clear plan high-cardinality parameters can make reports unusable.
  6. Be mindful of performance: attach a single delegated event listener when many blocks are on the page rather than many individual listeners.

Example: Combined minimal end-to-end setup

Summary example for a site that uses gtag (GA4) directly:

  1. Add gtag snippet with your Measurement ID.
  2. Register your frontend block script in PHP with wp_localize_script(MyBlockAnalyticsConfig, [measurementId => G-XXXXXXX, useGtm => false]).
  3. In frontend.js listen to block elements and call gtag(event, …).
  4. Verify via GA4 DebugView and the network requests in the browser.

Troubleshooting common issues

  • No events appearing: verify snippet or GTM container is loaded on the page and measurement ID is correct.
  • Events fired but not showing in GA4: check DebugView and timing (some events appear with a delay) ensure you are looking at the right property.
  • Events sent multiple times: check duplicate listeners or server redirects use dataset flags to prevent multiple attachments.
  • Consent blocks events: ensure consent management triggers enable analytics before sending or use consent mode integration.

Useful links

Official documentation and references:

Final checklist before deploying

  • Confirm GA4 snippet or GTM container on all pages where the block appears.
  • Implement defensive checks for gtag/dataLayer in frontend JS.
  • Respect consent and privacy rules do not send PII.
  • Use consistent event names and parameters and register custom parameters in GA4 when needed.
  • Test in GA4 DebugView and GTM Preview mode thoroughly on staging before production.

Notes

This article covers practical patterns you can apply immediately. Adapt naming, parameter keys, and implementation details to your analytics plan. The code examples demonstrate the typical flows for sending events from a WordPress block using JavaScript, either directly to GA4 with gtag or to Google Tag Manager via dataLayer pushes, together with PHP examples to register the scripts correctly in WordPress.



Acepto donaciones de BAT's mediante el navegador Brave 🙂



Leave a Reply

Your email address will not be published. Required fields are marked *