Google Analytics 4 Custom Events and Parameters with gtag.js

Submitted on Mar 04, 2021, 6:54 p.m.

Here's another PSA for anyone getting started with, or migrating to Google Analytics 4, with custom events and parameter collection via gtag.js.

For starters, below are the key resource links - which seem to be pretty much all over the place at Google.

Special note that if you want your custom parameters to be available as custom dimensions in Analysis Hub - you DO NOT need to register the parameters in your gtag.js config using a custom map as you did previously with Universal Analytics.  You DO however, still need to register the parameters as custom dimensions. Note that while you will you see your custom event and parameters in the debug and real-time streams - it can take a day or longer for the custom parameters to be available to the Analysis Hub and custom reports. Also be sure to read the help text when creating custom dimensions. In particular the fact that you can type in the name of your custom parameter even if it's not on the list of available parameters yet - e.g., "Choose a parameter or property from the list or enter the name of a parameter or property you'll collect in the future."

Here are the key resources - which I found in various places, followed by a helper script I use to collect custom event data.

  1. General implementation guide for gtag.js (note the section on custom dimensions and metrics). https://support.google.com/analytics/answer/9310895?hl=en
  2. gtag.js API reference - https://developers.google.com/gtagjs/reference/api
  3. gtag.js Parameter reference - which shows that event_callback and event_timeout work as before (for example if you were previously using dataLayer.push) - https://developers.google.com/gtagjs/reference/parameter

Here's my basic gtag.js configuration...

1<!-- Global site tag (gtag.js) - Google Analytics -->
2<script async src="https://www.googletagmanager.com/gtag/js?id=G-YOURPROPERTYID"></script>
3<script>
4 window.dataLayer = window.dataLayer || [];
5 function gtag(){dataLayer.push(arguments);}
6 gtag('js', new Date());
7 gtag('set', {'cookie_flags': 'SameSite=None;Secure'});
8 gtag('config', 'G-YOURPROPERTYID');
9</script>

And here's a general purpose event and parameter collection script, with both callback and timeout settings if required. If the click occurs on an anchor element that has target="_blank" there's no need to preventDefault or use the callback since the script and event parameter collection will have time to complete on the current page.

1(function () {
2 'use strict';
3
4 const handleGAClickEvent = function (event) {
5 if (typeof gtag !== 'undefined') {
6
7 // Get the element the event listner is bound to
8 const element = event.currentTarget;
9
10 // Check if the target is an anchor element, and if so prepare
11 // extra variables
12 let callback;
13 if (element instanceof HTMLAnchorElement) {
14 const target = element.getAttribute('target');
15 // Get the href - checking for possible SVG/XML links via xlink:href
16 const href = element.getAttribute('href') || element.getAttribute('xlink:href');
17 // Only define a callback and preventDefault if the element is an
18 // anchor element and target is NOT _blank.
19 if (!target || target !== '_blank') {
20 // preventDefault and the callback will allow event data
21 // collection to complete before the window location is set
22 // (i.e. before navigation away from the current page)
23 event.preventDefault();
24 callback = () => window.location.href = href;
25 }
26 }
27
28 // Get the event name
29 let gaEventName = null;
30 for(const data in element.dataset) {
31 if(data === 'gaEvent') {
32 gaEventName = element.dataset[data];
33 }
34 }
35
36 // Get the event parameters and record the event
37 if(gaEventName) {
38 let gaParameters = {};
39 for(const data in element.dataset) {
40 if(data.startsWith('ga') && data !== 'gaEvent') {
41 let parameterName = `${gaEventName}_${data.substring(2).toLowerCase()}`;
42 gaParameters[parameterName] = element.dataset[data];
43 }
44 }
45
46 try {
47 // https://developers.google.com/gtagjs/reference/api#event
48 // https://developers.google.com/gtagjs/reference/parameter
49 gtag('event', gaEventName, {
50 ...gaParameters,
51 'event_callback': callback,
52 'event_timeout': 1500,
53 'debug_mode': true
54 });
55 } catch (exception) {
56 console.error('Error in ga4-analytics.js:');
57 console.error(exception);
58 }
59 }
60 } else {
61 console.error('Error in ga4-analytics.js: gtag not found.')
62 }
63 }
64
65 // Get all elements that have information for a Google Analytics event
66 // in data-ga atttibutes
67 const elements = document.querySelectorAll('[data-ga-event]');
68 for(const element of elements) {
69 element.addEventListener("click", handleGAClickEvent, false);
70 };
71})();
72
73

Here's an example link decorated with the required attributes for a custom 'download' event, with category, label, and url as parameters.

1<a data-ga-event="download" data-ga-category="publication downloads" data-ga-label="Project Report 2021" data-ga-url="/resources/0000098-0001-en.pdf" href="/resources/0000098-0001-en.pdf" title="0000098-0001-en.pdf" type="application/pdf; length=560790" target="_blank" rel="noopener">
2...
3</a>