@visual-framework/vf-analytics-google
Advanced tools
Comparing version 1.0.4 to 1.1.0-rc.0
@@ -0,1 +1,5 @@ | ||
### 1.1.0-rc.0 | ||
* Adds gtag (GA4) support. | ||
### 1.0.4 | ||
@@ -2,0 +6,0 @@ |
{ | ||
"version": "1.0.4", | ||
"version": "1.1.0-rc.0", | ||
"name": "@visual-framework/vf-analytics-google", | ||
@@ -23,3 +23,3 @@ "description": "vf-analytics-google component", | ||
], | ||
"gitHead": "6059bda1bd78e57943b66be03c3f0208399d0afd" | ||
"gitHead": "c4365e2c15b7c6c6a6459564d78da5d7a7868248" | ||
} |
@@ -11,2 +11,15 @@ # Google Analytics Enhancements component | ||
### GA4 | ||
As of 1.1.0-rc.0 this contains gtag and GA4 support. The basics of vf-analytics-google are plug-and-play, but to get the full value out if you need to add (currently) 4 "custom definitions": | ||
1. `event_category` | ||
2. `event_type` | ||
3. `page_container` | ||
4. `vf_analytics` | ||
[You can see a screenshot of the configuration here](https://user-images.githubusercontent.com/928100/193329800-4c750a70-1d77-4623-ba00-87db4d608511.png) and here is Google's documentation on [adding the custom dimensions to your GA4 property](https://support.google.com/analytics/answer/10075209?hl=en#new-custom-dimension) (this step is not needed in a UA property). | ||
For more info see issue [#1428](https://github.com/visual-framework/vf-core/issues/1428) | ||
### User actions | ||
@@ -35,7 +48,11 @@ | ||
How to add dimension to your property? | ||
For GA4 users, be sure to set this when using `vfGaIndicateLoaded()`: | ||
- https://developers.google.com/analytics/devguides/collection/analyticsjs/custom-dims-mets | ||
- https://support.google.com/analytics/answer/2709829?hl=en | ||
```js | ||
vfGa4MeasurementId: "G-YOUR-GA4-ID-if_using_gtag" | ||
``` | ||
And [add the custom dimension to your property](https://support.google.com/analytics/answer/10075209?hl=en#new-custom-dimension). | ||
### Page region tracking | ||
@@ -55,2 +72,10 @@ | ||
### Not intended for use with Google Tag Manager | ||
You should not use `vf-analytics-google` with Google Tag Manager. The combination makes `vf-analytics-google` unreliable and often leads to race conditions where the gtag tracking may fail to work. This is not an issue with this code, rather it is consistent with most of my reading on best practice. It is summed up well at https://measureschool.com/google-tag-manager-vs-global-site-tag/ | ||
> Both these tools utilize some common resources that can lead to conflict in some cases. For example, the data layer is one such resource that is used by both tools. Therefore, it is important to be careful while adding both of them together. You will also need to test the implementation of tools by checking whether the correct data is sent to these tools. Overall, the process is doable but complicated. That’s why I would recommend not to install them together on the same page. | ||
That is: if you want to use Google Tag Manager, you should use that for your events. If you want to use gtag.js + custom JS, then vf-google-analytics is good for you. This code will provide particular value if you need a consistent way to collect event data across many websites, which is what we're after. | ||
### Verbose logging | ||
@@ -71,2 +96,3 @@ | ||
vfGaTrackPageLoad: true, | ||
vfGa4MeasurementId: "G-YOUR-GA4-ID-if_using_gtag" | ||
vfGaTrackNetwork: { | ||
@@ -81,3 +107,4 @@ serviceProvider: 'dimension2', | ||
`vfGaIndicateLoaded()` is the primary function and awaits and checks to see if Google Analytics client side JS has loaded. If it does, sets `<body data-vf-google-analytics-loaded='true'>` | ||
In parallel, you need to load and initialize the Google Analytics script you use (analytics.js or gtag.js). | ||
`vfGaIndicateLoaded()` is the primary function and awaits and checks to see if Google Analytics script has loaded. If it does, sets `<body data-vf-google-analytics-loaded='true'>` | ||
@@ -84,0 +111,0 @@ #### Options |
@@ -41,2 +41,3 @@ // vf-analytics-google | ||
* @param {binary} [vfGaTrackOptions.vfGaTrackPageLoad=true] If true, the function will track the initial page view. Set this to false if you track the page view in your HTML. | ||
* @param {string} [vfGaTrackOptions.vfGa4MeasurementId] The GA4 site measurement ID. | ||
* @param {number} [numberOfGaChecksLimit=2] | ||
@@ -66,3 +67,3 @@ * @param {number} [checkTimeout=900] | ||
// debug | ||
// console.log('checking',numberOfGaChecks,numberOfGaChecksLimit) | ||
vfGaLogMessage('checking ' + numberOfGaChecks + ", limit: " + numberOfGaChecksLimit) | ||
@@ -74,8 +75,21 @@ numberOfGaChecks++; | ||
// unset our check | ||
vfGaIndicateUnloaded(); | ||
if (el.getAttribute("data-vf-google-analytics-loaded") != "true") { | ||
vfGaIndicateUnloaded(); | ||
} | ||
if (ga && ga.loaded) { | ||
el.setAttribute("data-vf-google-analytics-loaded", "true"); | ||
vfGaInit(vfGaTrackOptions); | ||
// check to see if gtag is loaded, and then if UA is loaded, and if neither, check once more (to a limit) | ||
if (typeof gtag !== "undefined") { | ||
vfGaLogMessage('ga4 found'); | ||
if (el.getAttribute("data-vf-google-analytics-loaded") != "true") { | ||
el.setAttribute("data-vf-google-analytics-loaded", "true"); | ||
vfGaInit(vfGaTrackOptions); | ||
} | ||
} else if (ga && ga.loaded) { | ||
vfGaLogMessage('ua found'); | ||
if (el.getAttribute("data-vf-google-analytics-loaded") != "true") { | ||
el.setAttribute("data-vf-google-analytics-loaded", "true"); | ||
vfGaInit(vfGaTrackOptions); | ||
} | ||
} else { | ||
vfGaLogMessage('GA tracking code not ready, scheduling another check'); | ||
if (numberOfGaChecks <= numberOfGaChecksLimit) { | ||
@@ -88,2 +102,3 @@ setTimeout(function () { | ||
} catch (err) { | ||
vfGaLogMessage('error in vfGaIndicateLoaded'); | ||
if (numberOfGaChecks <= numberOfGaChecksLimit) { | ||
@@ -123,4 +138,6 @@ setTimeout(function () { | ||
* @param {binary} [vfGaTrackOptions.vfGaTrackPageLoad=true] If true, the function will track the initial page view. Set this to false if you track the page view in your HTML. | ||
* @param {string} [vfGaTrackOptions.vfGa4MeasurementId] The GA4 site measurement ID. | ||
*/ | ||
function vfGaInit(vfGaTrackOptions) { | ||
vfGaLogMessage('initing vfGaInit') | ||
/* eslint-disable no-redeclare*/ | ||
@@ -130,4 +147,3 @@ var vfGaTrackOptions = vfGaTrackOptions || {}; | ||
if (vfGaTrackOptions.vfGaTrackPageLoad == null) vfGaTrackOptions.vfGaTrackPageLoad = true; | ||
// Need help | ||
// Need help? | ||
// How to add dimension to your property | ||
@@ -137,5 +153,18 @@ // https://developers.google.com/analytics/devguides/collection/analyticsjs/custom-dims-mets | ||
if (typeof gtag === "undefined") { | ||
// if the site is still using legacy GA, set a dummy gtag function so we don't have to add a bunch of if statements | ||
vfGaLogMessage('GA4 dummy function has been set.'); | ||
window.gtag = function() {}; | ||
} | ||
if (typeof ga === "undefined") { | ||
// if the site is still using legacy GA, set a dummy gtag function so we don't have to add a bunch of if statements | ||
vfGaLogMessage('GA UA dummy function has been set.'); | ||
window.ga = function() {}; | ||
} | ||
// standard google analytics bootstrap | ||
// @todo: add conditional | ||
ga("set", "anonymizeIp", true); | ||
// For Gtag you should do this in your tracking snippet | ||
// https://developers.google.com/analytics/devguides/collection/gtagjs/ip-anonymization | ||
@@ -154,2 +183,5 @@ // Use the more robust "beacon" logging, when available | ||
ga("set", dimension, pageTypeName); | ||
gtag('config', vfGaTrackOptions.vfGa4MeasurementId, { | ||
'custom_map': { dimension: pageTypeName } | ||
}); | ||
} | ||
@@ -160,4 +192,6 @@ | ||
// - view the directions in README.md | ||
// note: this feature may be broken out as a seperate dependency if the code size needs to grow further | ||
if (vfGaTrackOptions.vfGaTrackNetwork != null) { | ||
// note: this feature may be broken out as a separate dependency if the code size needs to grow further | ||
// note: the VF has not yet added support for this using gtag | ||
// https://ipmeta.io/instructions/google-analytics-4 | ||
if (vfGaTrackOptions.vfGaTrackNetwork != null && ga) { | ||
// a copy of https://ipmeta.io/plugin.js | ||
@@ -200,3 +234,5 @@ // included here to simplify usage and reduce external requests | ||
if (vfGaTrackOptions.vfGaTrackPageLoad) { | ||
vfGaLogMessage('sending page view'); | ||
ga("send", "pageview"); | ||
gtag("event", "page_view"); | ||
} | ||
@@ -210,2 +246,3 @@ | ||
vfGaLogMessage('prepare vfGaLinkTrackingInit'); | ||
vfGaLinkTrackingInit(); | ||
@@ -218,6 +255,8 @@ } | ||
function vfGaLinkTrackingInit() { | ||
vfGaLogMessage('vfGaLinkTrackingInit'); | ||
document.body.addEventListener("mousedown", function (evt) { | ||
// Debug event type clicked | ||
// console.log(evt.target.tagName, evt.target); | ||
vfGaLogMessage(evt.target.tagName); | ||
vfGaLogMessage(evt.target); | ||
@@ -228,3 +267,3 @@ // we only track clicks on interactive elements (links, buttons, forms) | ||
let clickedElementTag = evt.target.tagName.toLowerCase(); | ||
let actionElements = ["a", "button", "label", "input", "select", "textarea", "details"]; | ||
let actionElements = ["a", "button", "label", "input", "select", "textarea", "details", "area"]; | ||
if (actionElements.indexOf(clickedElementTag) > -1) { | ||
@@ -320,2 +359,8 @@ vfGaTrackInteraction(evt.target); | ||
if (typeof gtag === "undefined") { | ||
// if the site is still using legacy GA, set a dummy gtag function so we don't have to add a bunch of if statements | ||
window.gtag = function() {}; | ||
vfGaLogMessage('GA4 dummy function has been set.'); | ||
} | ||
if (customEventName.length > 0) { | ||
@@ -356,3 +401,3 @@ linkName = customEventName; | ||
// special things for gloabl search box | ||
// special things for global search box | ||
// if (parentContainer == 'Global search') { | ||
@@ -399,2 +444,10 @@ // linkName = 'query: ' + jQuery('#global-search input#query').value; | ||
ga && ga("send", "event", "Email", "Region / " + parentContainer, mailLink); | ||
gtag && gtag("event", "Region / " + parentContainer, { | ||
"vf_analytics": "true", | ||
"page_container": parentContainer, | ||
"event_label": mailLink, | ||
"event_category": "UI", | ||
"event_type": "Email", | ||
"email_address": mailLink | ||
}); | ||
vfGaLogMessage("Email", "Region / " + parentContainer, mailLink, lastGaEventTime, actedOnItem); | ||
@@ -406,2 +459,11 @@ } else if (href && href.match(filetypes)) { | ||
ga && ga("send", "event", "Download", "Type / " + extension + " / " + parentContainer, filePath); | ||
gtag && gtag("event", "Type / " + extension + " / " + parentContainer, { | ||
"vf_analytics": "true", | ||
"page_container": parentContainer, | ||
"event_label": filePath, | ||
"file_extension": extension, | ||
"event_category": "UI", | ||
"event_type": "Download", | ||
"link_url": filePath | ||
}); | ||
vfGaLogMessage("Download", "Type / " + extension + " / " + parentContainer, filePath, lastGaEventTime, actedOnItem); | ||
@@ -417,2 +479,10 @@ } | ||
ga && ga("send", "event", "External links", "External link / " + linkName + " / " + parentContainer, href); | ||
gtag && gtag("event", "External link / " + parentContainer, { | ||
"vf_analytics": "true", | ||
"page_container": parentContainer, | ||
"event_category": "UI", | ||
"event_type": "External link or button", | ||
"link_text": linkName, | ||
"link_url": href | ||
}); | ||
vfGaLogMessage("External links", "External link / " + linkName + " / " + parentContainer, href, lastGaEventTime, actedOnItem); | ||
@@ -454,7 +524,25 @@ } | ||
ga && ga("send", "event", "UI", "UI Element / " + parentContainer, linkName); | ||
vfGaLogMessage("UI", "UI Element / " + parentContainer, linkName, lastGaEventTime, actedOnItem); | ||
gtag && gtag("event", "UI Element / " + parentContainer, { | ||
"vf_analytics": "true", | ||
"page_container": parentContainer, | ||
"event_label": linkName, | ||
"event_category": "UI", | ||
"event_type": "Webform", | ||
"link_text": linkName | ||
}); | ||
vfGaLogMessage("UI Form", "UI Element / " + parentContainer, linkName, lastGaEventTime, actedOnItem); | ||
} else { | ||
// generic catch all | ||
vfGaLogMessage("vfGaTrackInteraction: generic catch all") | ||
ga && ga("send", "event", "UI", "UI Element / " + parentContainer, linkName); | ||
vfGaLogMessage("UI", "UI Element / " + parentContainer, linkName, lastGaEventTime, actedOnItem); | ||
gtag && gtag("event", "UI Element / " + parentContainer, { | ||
"vf_analytics": "true", | ||
"page_container": parentContainer, | ||
"event_label": linkName, | ||
"event_category": "UI", | ||
"event_type": "Link, button, image or similar", | ||
"link_text": linkName, | ||
"link_url": href | ||
}); | ||
vfGaLogMessage("UI Catch all", "UI Element / " + parentContainer, linkName, lastGaEventTime, actedOnItem); | ||
} | ||
@@ -481,5 +569,10 @@ } | ||
/* eslint-disable */ | ||
console.log("%c Verbose analytics on ", "color: #FFF; background: #111; font-size: .75rem;"); | ||
console.log("clicked on: %o ", actedOnItem); | ||
console.log("sent to GA: ", "event ->", eventCategory + " ->", eventAction + " ->", eventLabel, "; at: ", lastGaEventTime); | ||
if (eventAction == undefined) { | ||
// It's a simple message debug | ||
console.log("Verbose analytics: %o ", eventCategory); | ||
} else { | ||
console.log("%c Verbose analytics on ", "color: #FFF; background: #111; font-size: .75rem;"); | ||
console.log("clicked on: %o ", actedOnItem); | ||
console.log("sent to GA: ", "event ->", eventCategory + " ->", eventAction + " ->", eventLabel, "; at: ", lastGaEventTime); | ||
} | ||
/* eslint-enable */ | ||
@@ -486,0 +579,0 @@ } |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
55260
641
159
2
1