google-analytics-ga4
Version:
This is package for google analytics GA4 .You can import it to any node project and use it .React , Vue, Anguler etc
526 lines (525 loc) • 22.8 kB
JavaScript
;
var __assign = (this && this.__assign) || function () {
__assign = Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
var __rest = (this && this.__rest) || function (s, e) {
var t = {};
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
t[p] = s[p];
if (s != null && typeof Object.getOwnPropertySymbols === "function")
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
t[p[i]] = s[p[i]];
}
return t;
};
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
if (ar || !(i in from)) {
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
ar[i] = from[i];
}
}
return to.concat(ar || Array.prototype.slice.call(from));
};
exports.__esModule = true;
exports.GA4 = void 0;
var gtag_1 = require("./gtag");
var format_1 = require("./format");
/*
Links
https://developers.google.com/gtagjs/reference/api
https://developers.google.com/tag-platform/gtagjs/reference
*/
/**
* @typedef GaOptions
* @type {Object}
* @property {boolean} [cookieUpdate=true]
* @property {number} [cookieExpires=63072000] Default two years
* @property {string} [cookieDomain="auto"]
* @property {string} [cookieFlags]
* @property {string} [userId]
* @property {string} [clientId]
* @property {boolean} [anonymizeIp]
* @property {string} [contentGroup1]
* @property {string} [contentGroup2]
* @property {string} [contentGroup3]
* @property {string} [contentGroup4]
* @property {string} [contentGroup5]
* @property {boolean} [allowAdFeatures=true]
* @property {boolean} [allowAdPersonalizationSignals]
* @property {boolean} [nonInteraction]
* @property {string} [page]
*/
/**
* @typedef UaEventOptions
* @type {Object}
* @property {string} action
* @property {string} category
* @property {string} [label]
* @property {number} [value]
* @property {boolean} [nonInteraction]
* @property {('beacon'|'xhr'|'image')} [transport]
*/
/**
* @typedef InitOptions
* @type {Object}
* @property {string} trackingId
* @property {GaOptions|any} [gaOptions]
* @property {Object} [gtagOptions] New parameter
*/
var GA4 = /** @class */ (function () {
function GA4() {
var _this = this;
this.reset = function () {
_this.isInitialized = false;
_this._testMode = false;
_this._currentMeasurementId;
_this._hasLoadedGA = false;
_this._isQueuing = false;
_this._queueGtag = [];
};
this._gtag = function () {
var args = [];
for (var _i = 0; _i < arguments.length; _i++) {
args[_i] = arguments[_i];
}
if (!_this._testMode) {
if (_this._isQueuing) {
_this._queueGtag.push(args);
}
else {
gtag_1["default"].apply(void 0, args);
}
}
else {
_this._queueGtag.push(args);
}
};
this._loadGA = function (GA_MEASUREMENT_ID, nonce) {
if (typeof window === "undefined" || typeof document === "undefined") {
return;
}
if (!_this._hasLoadedGA) {
// Global Site Tag (gtag.js) - Google Analytics
var script = document.createElement("script");
script.async = true;
script.src = "https://www.googletagmanager.com/gtag/js?id=".concat(GA_MEASUREMENT_ID);
if (nonce) {
script.setAttribute("nonce", nonce);
}
document.body.appendChild(script);
window.dataLayer = window.dataLayer || [];
window.gtag = function gtag() {
window.dataLayer.push(arguments);
};
_this._hasLoadedGA = true;
}
};
this._toGtagOptions = function (gaOptions) {
if (!gaOptions) {
return;
}
var mapFields = {
// Old https://developers.google.com/analytics/devguides/collection/analyticsjs/field-reference#cookieUpdate
// New https://developers.google.com/analytics/devguides/collection/gtagjs/cookies-user-id#cookie_update
cookieUpdate: "cookie_update",
cookieExpires: "cookie_expires",
cookieDomain: "cookie_domain",
cookieFlags: "cookie_flags",
userId: "user_id",
clientId: "client_id",
anonymizeIp: "anonymize_ip",
// https://support.google.com/analytics/answer/2853546?hl=en#zippy=%2Cin-this-article
contentGroup1: "content_group1",
contentGroup2: "content_group2",
contentGroup3: "content_group3",
contentGroup4: "content_group4",
contentGroup5: "content_group5",
// https://support.google.com/analytics/answer/9050852?hl=en
allowAdFeatures: "allow_google_signals",
allowAdPersonalizationSignals: "allow_ad_personalization_signals",
nonInteraction: "non_interaction",
page: "page_path",
hitCallback: "event_callback"
};
var gtagOptions = Object.entries(gaOptions).reduce(function (prev, _a) {
var key = _a[0], value = _a[1];
if (mapFields[key]) {
prev[mapFields[key]] = value;
}
else {
prev[key] = value;
}
return prev;
}, {});
return gtagOptions;
};
/**
*
* @param {InitOptions[]|string} GA_MEASUREMENT_ID
* @param {Object} [options]
* @param {boolean} [options.legacyDimensionMetric=true]
* @param {string} [options.nonce]
* @param {boolean} [options.testMode=false]
* @param {GaOptions|any} [options.gaOptions]
* @param {Object} [options.gtagOptions] New parameter
*/
this.initialize = function (GA_MEASUREMENT_ID, options) {
if (options === void 0) { options = {}; }
if (!GA_MEASUREMENT_ID) {
throw new Error("Require GA_MEASUREMENT_ID");
}
var initConfigs = typeof GA_MEASUREMENT_ID === "string"
? [{ trackingId: GA_MEASUREMENT_ID }]
: GA_MEASUREMENT_ID;
_this._currentMeasurementId = initConfigs[0].trackingId;
var gaOptions = options.gaOptions, gtagOptions = options.gtagOptions, _a = options.legacyDimensionMetric, legacyDimensionMetric = _a === void 0 ? true : _a, nonce = options.nonce, _b = options.testMode, testMode = _b === void 0 ? false : _b;
_this._testMode = testMode;
if (!testMode) {
_this._loadGA(_this._currentMeasurementId, nonce);
}
if (!_this.isInitialized) {
_this._gtag("js", new Date());
initConfigs.forEach(function (config) {
var mergedGtagOptions = _this._appendCustomMap(__assign(__assign(__assign({
// https://developers.google.com/analytics/devguides/collection/gtagjs/pages#disable_pageview_measurement
send_page_view: false }, _this._toGtagOptions(__assign(__assign({}, gaOptions), config.gaOptions))), gtagOptions), config.gtagOptions), legacyDimensionMetric);
_this._gtag("config", config.trackingId, mergedGtagOptions);
});
}
_this.isInitialized = true;
if (!testMode) {
var queues = __spreadArray([], _this._queueGtag, true);
_this._queueGtag = [];
_this._isQueuing = false;
while (queues.length) {
var queue = queues.shift();
_this._gtag.apply(_this, queue);
if (queue[0] === "get") {
_this._isQueuing = true;
}
}
}
};
this.set = function (fieldsObject) {
if (!fieldsObject) {
console.warn("`fieldsObject` is required in .set()");
return;
}
if (typeof fieldsObject !== "object") {
console.warn("Expected `fieldsObject` arg to be an Object");
return;
}
if (Object.keys(fieldsObject).length === 0) {
console.warn("empty `fieldsObject` given to .set()");
}
_this._gaCommand("set", fieldsObject);
};
this._gaCommandSendEvent = function (eventCategory, eventAction, eventLabel, eventValue, fieldsObject) {
_this._gtag("event", eventAction, __assign(__assign({ event_category: eventCategory, event_label: eventLabel, value: eventValue }, (fieldsObject && { non_interaction: fieldsObject.nonInteraction })), _this._toGtagOptions(fieldsObject)));
};
this._gaCommandSendEventParameters = function () {
var args = [];
for (var _i = 0; _i < arguments.length; _i++) {
args[_i] = arguments[_i];
}
if (typeof args[0] === "string") {
_this._gaCommandSendEvent.apply(null, args.slice(1));
}
else {
var _a = args[0], eventCategory = _a.eventCategory, eventAction = _a.eventAction, eventLabel = _a.eventLabel, eventValue = _a.eventValue,
// eslint-disable-next-line no-unused-vars
hitType = _a.hitType, rest = __rest(_a, ["eventCategory", "eventAction", "eventLabel", "eventValue", "hitType"]);
_this._gaCommandSendEvent(eventCategory, eventAction, eventLabel, eventValue, rest);
}
};
this._gaCommandSendTiming = function (timingCategory, timingVar, timingValue, timingLabel) {
_this._gtag("event", "timing_complete", {
name: timingVar,
value: timingValue,
event_category: timingCategory,
event_label: timingLabel
});
};
this._gaCommandSendPageview = function (page, fieldsObject) {
if (fieldsObject && Object.keys(fieldsObject).length) {
var _a = _this._toGtagOptions(fieldsObject), title = _a.title, location_1 = _a.location, rest = __rest(_a, ["title", "location"]);
_this._gtag("event", "page_view", __assign(__assign(__assign(__assign({}, (page && { page_path: page })), (title && { page_title: title })), (location_1 && { page_location: location_1 })), rest));
}
else if (page) {
_this._gtag("event", "page_view", { page_path: page });
}
else {
_this._gtag("event", "page_view");
}
};
this._gaCommandSendPageviewParameters = function () {
var args = [];
for (var _i = 0; _i < arguments.length; _i++) {
args[_i] = arguments[_i];
}
if (typeof args[0] === "string") {
_this._gaCommandSendPageview.apply(null, args.slice(1));
}
else {
var _a = args[0], page = _a.page,
// eslint-disable-next-line no-unused-vars
hitType = _a.hitType, rest = __rest(_a, ["page", "hitType"]);
_this._gaCommandSendPageview(page, rest);
}
};
// https://developers.google.com/analytics/devguides/collection/analyticsjs/command-queue-reference#send
this._gaCommandSend = function () {
var args = [];
for (var _i = 0; _i < arguments.length; _i++) {
args[_i] = arguments[_i];
}
var hitType = typeof args[0] === "string" ? args[0] : args[0].hitType;
switch (hitType) {
case "event":
_this._gaCommandSendEventParameters.apply(_this, args);
break;
case "pageview":
_this._gaCommandSendPageviewParameters.apply(_this, args);
break;
case "timing":
_this._gaCommandSendTiming.apply(null, args.slice(1));
break;
case "screenview":
case "transaction":
case "item":
case "social":
case "exception":
console.warn("Unsupported send command: ".concat(hitType));
break;
default:
console.warn("Send command doesn't exist: ".concat(hitType));
}
};
this._gaCommandSet = function () {
var _a;
var args = [];
for (var _i = 0; _i < arguments.length; _i++) {
args[_i] = arguments[_i];
}
if (typeof args[0] === "string") {
args[0] = (_a = {}, _a[args[0]] = args[1], _a);
}
_this._gtag("set", _this._toGtagOptions(args[0]));
};
this._gaCommand = function (command) {
var args = [];
for (var _i = 1; _i < arguments.length; _i++) {
args[_i - 1] = arguments[_i];
}
switch (command) {
case "send":
_this._gaCommandSend.apply(_this, args);
break;
case "set":
_this._gaCommandSet.apply(_this, args);
break;
default:
console.warn("Command doesn't exist: ".concat(command));
}
};
this.ga = function () {
var args = [];
for (var _i = 0; _i < arguments.length; _i++) {
args[_i] = arguments[_i];
}
if (typeof args[0] === "string") {
_this._gaCommand.apply(null, args);
}
else {
var readyCallback_1 = args[0];
_this._gtag("get", _this._currentMeasurementId, "client_id", function (clientId) {
_this._isQueuing = false;
var queues = _this._queueGtag;
readyCallback_1({
get: function (property) {
return property === "clientId"
? clientId
: property === "trackingId"
? _this._currentMeasurementId
: property === "apiVersion"
? "1"
: undefined;
}
});
while (queues.length) {
var queue = queues.shift();
_this._gtag.apply(_this, queue);
}
});
_this._isQueuing = true;
}
return _this.ga;
};
/**
* @param {UaEventOptions|string} optionsOrName
* @param {Object} [params]
*/
this.event = function (optionsOrName, params) {
if (typeof optionsOrName === "string") {
_this._gtag("event", optionsOrName, _this._toGtagOptions(params));
}
else {
var action = optionsOrName.action, category = optionsOrName.category, label = optionsOrName.label, value = optionsOrName.value, nonInteraction = optionsOrName.nonInteraction, transport = optionsOrName.transport, rest_1 = __rest(optionsOrName, ["action", "category", "label", "value", "nonInteraction", "transport"]);
if (!category || !action) {
console.warn("args.category AND args.action are required in event()");
return;
}
// Required Fields
var fieldObject_1 = {
hitType: "event",
eventCategory: (0, format_1["default"])(category),
eventAction: (0, format_1["default"])(action)
};
// Optional Fields
if (label) {
fieldObject_1.eventLabel = (0, format_1["default"])(label);
}
if (typeof value !== "undefined") {
if (typeof value !== "number") {
console.warn("Expected `args.value` arg to be a Number.");
}
else {
fieldObject_1.eventValue = value;
}
}
if (typeof nonInteraction !== "undefined") {
if (typeof nonInteraction !== "boolean") {
console.warn("`args.nonInteraction` must be a boolean.");
}
else {
fieldObject_1.nonInteraction = nonInteraction;
}
}
if (typeof transport !== "undefined") {
if (typeof transport !== "string") {
console.warn("`args.transport` must be a string.");
}
else {
if (["beacon", "xhr", "image"].indexOf(transport) === -1) {
console.warn("`args.transport` must be either one of these values: `beacon`, `xhr` or `image`");
}
fieldObject_1.transport = transport;
}
}
Object.keys(rest_1)
.filter(function (key) { return key.substr(0, "dimension".length) === "dimension"; })
.forEach(function (key) {
fieldObject_1[key] = rest_1[key];
});
Object.keys(rest_1)
.filter(function (key) { return key.substr(0, "metric".length) === "metric"; })
.forEach(function (key) {
fieldObject_1[key] = rest_1[key];
});
_this._gaCommand("send", fieldObject_1);
}
};
this.send = function (fieldObject) {
_this._gaCommand("send", fieldObject);
};
/**
* @since v1.0.2
* @param {string} [path="location.href"]
* @param {string[]} [_] unsupported
* @param {string} [title="location.pathname"]
* @deprecated Use `.send("pageview")` instead
*/
this.pageview = function (path, _, title) {
var pathTrim = path === null || path === void 0 ? void 0 : path.trim();
if (pathTrim === "") {
console.warn("path cannot be an empty string in .pageview()");
return;
}
_this._gaCommand("send", "pageview", pathTrim, { title: title });
};
this.reset();
}
GA4.prototype.gtag = function () {
var args = [];
for (var _i = 0; _i < arguments.length; _i++) {
args[_i] = arguments[_i];
}
this._gtag.apply(this, args);
};
GA4.prototype._appendCustomMap = function (options, legacyDimensionMetric) {
if (legacyDimensionMetric === void 0) { legacyDimensionMetric = true; }
if (!legacyDimensionMetric) {
return options;
}
if (!options.custom_map) {
options.custom_map = {};
}
for (var i = 1; i <= 200; i++) {
if (!options.custom_map["dimension".concat(i)]) {
options.custom_map["dimension".concat(i)] = "dimension".concat(i);
}
if (!options.custom_map["metric".concat(i)]) {
options.custom_map["metric".concat(i)] = "metric".concat(i);
}
}
return options;
};
/**
* @since v1.0.6
* @param {Object} options
* @param {string} options.label
* @param {function} hitCallback
* @deprecated Use `enhanced measurement` feature in Google Analytics.
*/
GA4.prototype.outboundLink = function (_a, hitCallback) {
var label = _a.label;
if (typeof hitCallback !== "function") {
console.warn("hitCallback function is required");
return;
}
if (!label) {
console.warn("args.label is required in outboundLink()");
return;
}
// Required Fields
var fieldObject = {
hitType: "event",
eventCategory: "Outbound",
eventAction: "Click",
eventLabel: (0, format_1["default"])(label)
};
var safetyCallbackCalled = false;
var safetyCallback = function () {
// This prevents a delayed response from GA
// causing hitCallback from being fired twice
safetyCallbackCalled = true;
hitCallback();
};
// Using a timeout to ensure the execution of critical application code
// in the case when the GA server might be down
// or an ad blocker prevents sending the data
// register safety net timeout:
var t = setTimeout(safetyCallback, 250);
var clearableCallbackForGA = function () {
clearTimeout(t);
if (!safetyCallbackCalled) {
hitCallback();
}
};
fieldObject.hitCallback = clearableCallbackForGA;
this._gaCommand("send", fieldObject);
};
return GA4;
}());
exports.GA4 = GA4;
exports["default"] = new GA4();