onerway-analytics 1.0.2 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -24,7 +24,7 @@ var OnrwayAnalytics = (() => {
24
24
  API_KEY_MAP: () => API_KEY_MAP,
25
25
  Analytics: () => Analytics,
26
26
  DEFAULT_CONFIG: () => DEFAULT_CONFIG,
27
- GAManager: () => GAManager,
27
+ GTMManager: () => GTMManager,
28
28
  SDK_VERSION: () => SDK_VERSION,
29
29
  STORAGE_KEYS: () => STORAGE_KEYS,
30
30
  Sender: () => Sender,
@@ -454,16 +454,17 @@ var OnrwayAnalytics = (() => {
454
454
  function collectMarketing() {
455
455
  if (!isBrowser()) return {};
456
456
  let utm = {};
457
- const storedUtm = safeLocalStorageGet(STORAGE_KEYS.UTM_PARAMS);
458
- if (storedUtm) {
459
- try {
460
- utm = JSON.parse(storedUtm);
461
- } catch {
462
- }
457
+ const freshUtm = parseUTMParams();
458
+ if (Object.keys(freshUtm).length > 0) {
459
+ utm = freshUtm;
460
+ safeLocalStorageSet(STORAGE_KEYS.UTM_PARAMS, JSON.stringify(utm));
463
461
  } else {
464
- utm = parseUTMParams();
465
- if (Object.keys(utm).length > 0) {
466
- safeLocalStorageSet(STORAGE_KEYS.UTM_PARAMS, JSON.stringify(utm));
462
+ const storedUtm = safeLocalStorageGet(STORAGE_KEYS.UTM_PARAMS);
463
+ if (storedUtm) {
464
+ try {
465
+ utm = JSON.parse(storedUtm);
466
+ } catch {
467
+ }
467
468
  }
468
469
  }
469
470
  let landingPage = safeLocalStorageGet(STORAGE_KEYS.LANDING_PAGE);
@@ -643,34 +644,41 @@ var OnrwayAnalytics = (() => {
643
644
  });
644
645
  }
645
646
 
646
- // src/core/ga-loader.ts
647
- function loadGtagScript(measurementId) {
648
- return new Promise((resolve, reject) => {
649
- if (document.querySelector(`script[src*="googletagmanager.com/gtag/js"]`)) {
650
- resolve();
651
- return;
652
- }
647
+ // src/core/gtm-loader.ts
648
+ function initGTM(config) {
649
+ if (!config.enabled || !config.containerId) return;
650
+ if (typeof window === "undefined") return;
651
+ const dataLayerName = config.dataLayerName || "dataLayer";
652
+ const w2 = window;
653
+ if (!Array.isArray(w2[dataLayerName])) {
654
+ w2[dataLayerName] = [];
655
+ }
656
+ w2[dataLayerName].push({ "gtm.start": (/* @__PURE__ */ new Date()).getTime(), event: "gtm.js" });
657
+ const existingScript = document.querySelector(
658
+ `script[src*="googletagmanager.com/gtm.js?id=${config.containerId}"]`
659
+ );
660
+ if (!existingScript) {
661
+ const dl = dataLayerName !== "dataLayer" ? `&l=${encodeURIComponent(dataLayerName)}` : "";
653
662
  const script = document.createElement("script");
654
663
  script.async = true;
655
- script.src = `https://www.googletagmanager.com/gtag/js?id=${measurementId}`;
656
- script.onload = () => resolve();
657
- script.onerror = () => reject(new Error("Failed to load gtag.js"));
658
- document.head.appendChild(script);
659
- });
660
- }
661
- async function initGA(config) {
662
- if (!config.enabled || !config.measurementId) return;
663
- if (typeof window === "undefined") return;
664
- window.dataLayer = window.dataLayer || [];
665
- window.gtag = function gtag() {
666
- window.dataLayer.push(arguments);
667
- };
668
- window.gtag("js", /* @__PURE__ */ new Date());
669
- window.gtag("config", config.measurementId, {
670
- send_page_view: config.sendPageView ?? false,
671
- debug_mode: config.debugMode ?? false
672
- });
673
- await loadGtagScript(config.measurementId);
664
+ script.src = `https://www.googletagmanager.com/gtm.js?id=${config.containerId}${dl}`;
665
+ const firstScript = document.getElementsByTagName("script")[0];
666
+ firstScript.parentNode?.insertBefore(script, firstScript);
667
+ }
668
+ if (!document.querySelector(`noscript[data-gtm-id="${config.containerId}"]`)) {
669
+ const noscript = document.createElement("noscript");
670
+ noscript.setAttribute("data-gtm-id", config.containerId);
671
+ const iframe = document.createElement("iframe");
672
+ iframe.src = `https://www.googletagmanager.com/ns.html?id=${config.containerId}`;
673
+ iframe.height = "0";
674
+ iframe.width = "0";
675
+ iframe.style.display = "none";
676
+ iframe.style.visibility = "hidden";
677
+ noscript.appendChild(iframe);
678
+ if (document.body) {
679
+ document.body.insertBefore(noscript, document.body.firstChild);
680
+ }
681
+ }
674
682
  }
675
683
 
676
684
  // node_modules/web-vitals/dist/web-vitals.js
@@ -949,88 +957,43 @@ var OnrwayAnalytics = (() => {
949
957
  }
950
958
  }
951
959
 
952
- // src/core/ga-adapter.ts
953
- function trackToGA(eventName, properties, options) {
954
- if (typeof window === "undefined" || !window.gtag) return;
955
- const params = {
956
- session_id: options.sessionId,
957
- engagement_time_msec: 100,
958
- page_location: options.pageUrl,
959
- page_referrer: options.referrer
960
- };
961
- const { marketing, userId } = options;
962
- if (marketing.utm_source) params.utm_source = marketing.utm_source;
963
- if (marketing.utm_medium) params.utm_medium = marketing.utm_medium;
964
- if (marketing.utm_campaign) params.utm_campaign = marketing.utm_campaign;
965
- if (marketing.utm_term) params.utm_term = marketing.utm_term;
966
- if (marketing.utm_content) params.utm_content = marketing.utm_content;
967
- if (userId) params.user_id = userId;
968
- Object.assign(params, properties);
969
- window.gtag("event", eventName, params);
970
- }
971
- function setGAUserId(userId) {
972
- if (typeof window === "undefined" || !window.gtag) return;
973
- window.gtag("set", { user_id: userId ?? void 0 });
974
- }
975
- function setGAUserProperties(properties) {
976
- if (typeof window === "undefined" || !window.gtag) return;
977
- window.gtag("set", "user_properties", properties);
978
- }
979
-
980
- // src/core/ga-manager.ts
981
- var GAManager = class {
960
+ // src/core/gtm-manager.ts
961
+ var GTMManager = class {
982
962
  constructor() {
983
963
  this._initialized = false;
964
+ this._dataLayerName = "dataLayer";
984
965
  }
985
966
  get ready() {
986
- return this._initialized && typeof window !== "undefined" && typeof window.gtag === "function";
987
- }
988
- get measurementId() {
989
- return this._measurementId;
990
- }
991
- track(eventName, properties) {
992
- if (!this.ready) return;
993
- window.gtag("event", eventName, properties ?? {});
994
- }
995
- setUserId(userId) {
996
- if (!this.ready) return;
997
- window.gtag("set", { user_id: userId ?? void 0 });
967
+ return this._initialized && typeof window !== "undefined";
998
968
  }
999
- setUserProperties(properties) {
1000
- if (!this.ready) return;
1001
- window.gtag("set", "user_properties", properties);
969
+ get containerId() {
970
+ return this._containerId;
1002
971
  }
1003
- set(keyOrParams, value) {
972
+ push(data) {
1004
973
  if (!this.ready) return;
1005
- if (typeof keyOrParams === "string") {
1006
- window.gtag("set", keyOrParams, value);
1007
- } else {
1008
- window.gtag("set", keyOrParams);
974
+ const w2 = window;
975
+ const dl = w2[this._dataLayerName];
976
+ if (Array.isArray(dl)) {
977
+ dl.push(data);
1009
978
  }
1010
979
  }
1011
- config(params) {
1012
- if (!this.ready || !this._measurementId) return;
1013
- window.gtag("config", this._measurementId, params ?? {});
1014
- }
1015
- consent(mode, params) {
1016
- if (!this.ready) return;
1017
- window.gtag("consent", mode, params);
980
+ track(eventName, properties) {
981
+ this.push({ event: eventName, ...properties || {} });
1018
982
  }
1019
- get(key, callback) {
1020
- if (!this.ready || !this._measurementId) return;
1021
- window.gtag("get", this._measurementId, key, callback);
983
+ setUserId(userId) {
984
+ this.push({ userId: userId ?? void 0 });
1022
985
  }
1023
- gtag(...args) {
1024
- if (typeof window === "undefined" || !window.gtag) return;
1025
- window.gtag(...args);
986
+ setUserProperties(properties) {
987
+ this.push(properties);
1026
988
  }
1027
- _init(measurementId) {
1028
- this._measurementId = measurementId;
989
+ _init(containerId, dataLayerName = "dataLayer") {
990
+ this._containerId = containerId;
991
+ this._dataLayerName = dataLayerName;
1029
992
  this._initialized = true;
1030
993
  }
1031
994
  _destroy() {
1032
995
  this._initialized = false;
1033
- this._measurementId = void 0;
996
+ this._containerId = void 0;
1034
997
  }
1035
998
  };
1036
999
 
@@ -1044,11 +1007,8 @@ var OnrwayAnalytics = (() => {
1044
1007
  this.userProps = {};
1045
1008
  this.initialized = false;
1046
1009
  this.retrying = 0;
1047
- this.gaInitialized = false;
1048
- this.gaPendingQueue = [];
1049
- this.gaPendingIdentify = null;
1050
1010
  this.unloadHandler = null;
1051
- this.ga = new GAManager();
1011
+ this.gtm = new GTMManager();
1052
1012
  this.config = {
1053
1013
  debug: false,
1054
1014
  autoTrack: true,
@@ -1064,6 +1024,7 @@ var OnrwayAnalytics = (() => {
1064
1024
  this.clientType = DEFAULT_CONFIG.clientType;
1065
1025
  this.batchPageId = this.generateBatchPageId();
1066
1026
  this.sessionManager = new SessionManager(this.config.sessionTimeout);
1027
+ this.sampled = this.resolveSampling();
1067
1028
  if (isBrowser()) {
1068
1029
  this.recoverFailedEvents();
1069
1030
  }
@@ -1077,28 +1038,10 @@ var OnrwayAnalytics = (() => {
1077
1038
  if (isBrowser() && this.config.performance?.enabled !== false) {
1078
1039
  initPerformanceMonitor(this, this.config.performance);
1079
1040
  }
1080
- if (isBrowser() && this.config.ga?.enabled) {
1081
- this.ga._init(this.config.ga.measurementId);
1082
- initGA(this.config.ga).then(() => {
1083
- this.gaInitialized = true;
1084
- this.log("GA4 initialized with measurementId:", this.config.ga?.measurementId);
1085
- if (this.gaPendingIdentify) {
1086
- setGAUserId(this.gaPendingIdentify.userId);
1087
- if (this.gaPendingIdentify.attributes) {
1088
- setGAUserProperties(this.gaPendingIdentify.attributes);
1089
- }
1090
- this.gaPendingIdentify = null;
1091
- }
1092
- for (const { eventName, properties, options } of this.gaPendingQueue) {
1093
- trackToGA(eventName, properties, options);
1094
- }
1095
- this.gaPendingQueue = [];
1096
- }).catch((error) => {
1097
- this.ga._destroy();
1098
- this.gaPendingIdentify = null;
1099
- this.gaPendingQueue = [];
1100
- this.log("Failed to initialize GA4:", error);
1101
- });
1041
+ if (isBrowser() && this.config.gtm?.enabled) {
1042
+ initGTM(this.config.gtm);
1043
+ this.gtm._init(this.config.gtm.containerId, this.config.gtm.dataLayerName);
1044
+ this.log("GTM initialized with containerId:", this.config.gtm.containerId);
1102
1045
  }
1103
1046
  this.initialized = true;
1104
1047
  this.log("Analytics SDK initialized", {
@@ -1106,7 +1049,7 @@ var OnrwayAnalytics = (() => {
1106
1049
  clientId: this.clientId,
1107
1050
  sessionId: this.sessionManager.getSessionId()
1108
1051
  });
1109
- if (isBrowser()) {
1052
+ if (isBrowser() && this.config.autoTrackPageView !== false) {
1110
1053
  this.trackPageView();
1111
1054
  }
1112
1055
  }
@@ -1115,21 +1058,16 @@ var OnrwayAnalytics = (() => {
1115
1058
  this.log("Invalid event name");
1116
1059
  return;
1117
1060
  }
1061
+ if (!this.sampled) return;
1118
1062
  const normalizedProps = properties && isObject(properties) ? properties : {};
1119
1063
  const isKeyEvent = options?.keyEvent === true || this.isKeyEvent(eventName);
1120
- if (this.config.ga?.enabled) {
1121
- const gaOptions = {
1122
- sessionId: this.sessionManager.getSessionId(),
1123
- pageUrl: isBrowser() ? getPageUrl() : "",
1124
- referrer: isBrowser() ? document.referrer : "",
1125
- marketing: collectMarketing(),
1126
- userId: this.userId
1127
- };
1128
- if (this.gaInitialized) {
1129
- trackToGA(eventName, normalizedProps, gaOptions);
1130
- } else {
1131
- this.gaPendingQueue.push({ eventName, properties: normalizedProps, options: gaOptions });
1132
- }
1064
+ if (this.gtm.ready) {
1065
+ this.gtm.track(eventName, {
1066
+ ...normalizedProps,
1067
+ session_id: this.sessionManager.getSessionId(),
1068
+ page_url: isBrowser() ? getPageUrl() : "",
1069
+ referrer: isBrowser() ? document.referrer : ""
1070
+ });
1133
1071
  }
1134
1072
  if (this.config.disableServer) return;
1135
1073
  const event = {
@@ -1158,13 +1096,11 @@ var OnrwayAnalytics = (() => {
1158
1096
  if (attributes && isObject(attributes)) {
1159
1097
  this.userProps = attributes;
1160
1098
  }
1161
- if (this.gaInitialized) {
1162
- setGAUserId(userId);
1099
+ if (this.gtm.ready) {
1100
+ this.gtm.setUserId(userId);
1163
1101
  if (attributes && isObject(attributes)) {
1164
- setGAUserProperties(attributes);
1102
+ this.gtm.setUserProperties(attributes);
1165
1103
  }
1166
- } else if (this.config.ga?.enabled) {
1167
- this.gaPendingIdentify = { userId, attributes };
1168
1104
  }
1169
1105
  this.log("User identified:", { userId, attributes });
1170
1106
  if (wasAnonymous && this.buffer.length > 0) {
@@ -1185,8 +1121,8 @@ var OnrwayAnalytics = (() => {
1185
1121
  clearTimeout(this.bufferTimer);
1186
1122
  this.bufferTimer = null;
1187
1123
  }
1188
- if (this.gaInitialized) {
1189
- setGAUserId(null);
1124
+ if (this.gtm.ready) {
1125
+ this.gtm.setUserId(null);
1190
1126
  }
1191
1127
  this.log("Analytics reset");
1192
1128
  }
@@ -1211,6 +1147,14 @@ var OnrwayAnalytics = (() => {
1211
1147
  console.log("[Analytics]", ...args);
1212
1148
  }
1213
1149
  }
1150
+ resolveSampling() {
1151
+ const rate = this.config.sampleRate ?? 1;
1152
+ if (rate >= 1) return true;
1153
+ if (rate <= 0) return false;
1154
+ const decision = Math.random() < rate;
1155
+ this.log(`Sampling decision: ${decision ? "included" : "excluded"} (sampleRate=${rate})`);
1156
+ return decision;
1157
+ }
1214
1158
  getOrCreateClientId() {
1215
1159
  if (!isBrowser()) return generateUUID();
1216
1160
  let clientId = safeLocalStorageGet(STORAGE_KEYS.CLIENT_ID);
@@ -1252,8 +1196,9 @@ var OnrwayAnalytics = (() => {
1252
1196
  const merged = {};
1253
1197
  for (const key of Object.keys(defaults)) {
1254
1198
  const k2 = key;
1255
- if (defaults[k2] !== void 0) {
1256
- merged[k2] = defaults[k2];
1199
+ const val = defaults[k2];
1200
+ if (val !== void 0 && val !== "") {
1201
+ merged[k2] = val;
1257
1202
  }
1258
1203
  }
1259
1204
  for (const key of Object.keys(properties)) {
@@ -1338,6 +1283,7 @@ var OnrwayAnalytics = (() => {
1338
1283
  }
1339
1284
  recoverFailedEvents() {
1340
1285
  if (this.config.disableServer) return;
1286
+ if (!this.sampled) return;
1341
1287
  const failedEvents = StorageQueue.recover();
1342
1288
  if (failedEvents.length > 0) {
1343
1289
  this.log(`Recovered ${failedEvents.length} failed events from storage`);