@dotcms/analytics 1.2.0-next.9 → 1.2.1-next.1

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.
Files changed (44) hide show
  1. package/README.md +261 -15
  2. package/lib/core/dot-analytics.content.js +84 -0
  3. package/lib/core/plugin/click/dot-analytics.click-tracker.d.ts +108 -0
  4. package/lib/core/plugin/click/dot-analytics.click-tracker.js +144 -0
  5. package/lib/core/plugin/click/dot-analytics.click.plugin.d.ts +36 -0
  6. package/lib/core/plugin/click/dot-analytics.click.plugin.js +27 -0
  7. package/lib/core/plugin/click/dot-analytics.click.utils.d.ts +12 -0
  8. package/lib/core/plugin/click/dot-analytics.click.utils.js +55 -0
  9. package/lib/core/plugin/enricher/dot-analytics.enricher.plugin.d.ts +1 -1
  10. package/lib/core/plugin/enricher/dot-analytics.enricher.plugin.js +14 -14
  11. package/lib/core/{shared/dot-content-analytics.activity-tracker.d.ts → plugin/identity/dot-analytics.identity.activity-tracker.d.ts} +2 -17
  12. package/lib/core/{shared/dot-content-analytics.activity-tracker.js → plugin/identity/dot-analytics.identity.activity-tracker.js} +17 -37
  13. package/lib/core/plugin/identity/dot-analytics.identity.plugin.js +7 -7
  14. package/lib/core/plugin/identity/dot-analytics.identity.utils.d.ts +0 -16
  15. package/lib/core/{shared/dot-content-analytics.impression-tracker.d.ts → plugin/impression/dot-analytics.impression-tracker.d.ts} +2 -2
  16. package/lib/core/{shared/dot-content-analytics.impression-tracker.js → plugin/impression/dot-analytics.impression-tracker.js} +41 -57
  17. package/lib/core/plugin/impression/dot-analytics.impression.plugin.d.ts +4 -2
  18. package/lib/core/plugin/impression/dot-analytics.impression.plugin.js +13 -21
  19. package/lib/core/plugin/impression/dot-analytics.impression.utils.d.ts +0 -25
  20. package/lib/core/plugin/impression/dot-analytics.impression.utils.js +15 -38
  21. package/lib/core/plugin/{dot-analytics.plugin.d.ts → main/dot-analytics.plugin.d.ts} +2 -1
  22. package/lib/core/plugin/main/dot-analytics.plugin.js +129 -0
  23. package/lib/core/shared/constants/{dot-content-analytics.constants.d.ts → dot-analytics.constants.d.ts} +16 -0
  24. package/lib/core/shared/constants/dot-analytics.constants.js +53 -0
  25. package/lib/core/shared/constants/index.d.ts +1 -1
  26. package/lib/core/shared/dot-analytics.logger.d.ts +85 -0
  27. package/lib/core/shared/dot-analytics.logger.js +90 -0
  28. package/lib/core/shared/{dot-content-analytics.http.d.ts → http/dot-analytics.http.d.ts} +1 -1
  29. package/lib/core/shared/http/dot-analytics.http.js +34 -0
  30. package/lib/core/shared/models/event.model.d.ts +69 -2
  31. package/lib/core/shared/models/library.model.d.ts +31 -5
  32. package/lib/core/shared/queue/dot-analytics.queue.utils.js +44 -37
  33. package/lib/core/shared/{dot-content-analytics.utils.d.ts → utils/dot-analytics.utils.d.ts} +72 -4
  34. package/lib/core/shared/utils/dot-analytics.utils.js +202 -0
  35. package/lib/react/hook/useContentAnalytics.js +17 -11
  36. package/lib/react/hook/useRouterTracker.js +4 -4
  37. package/lib/react/internal/utils.js +1 -1
  38. package/package.json +7 -6
  39. package/lib/core/dot-content-analytics.js +0 -56
  40. package/lib/core/plugin/dot-analytics.plugin.js +0 -97
  41. package/lib/core/shared/constants/dot-content-analytics.constants.js +0 -48
  42. package/lib/core/shared/dot-content-analytics.http.js +0 -36
  43. package/lib/core/shared/dot-content-analytics.utils.js +0 -147
  44. /package/lib/core/{dot-content-analytics.d.ts → dot-analytics.content.d.ts} +0 -0
@@ -0,0 +1,36 @@
1
+ import { AnalyticsInstance } from 'analytics';
2
+ import { DotCMSAnalyticsConfig } from '../../shared/models';
3
+ /**
4
+ * Click Plugin for DotAnalytics
5
+ * Handles automatic tracking of clicks on content elements.
6
+ *
7
+ * This plugin initializes the click tracker which:
8
+ * - Uses MutationObserver to detect contentlet containers
9
+ * - Attaches click listeners to each .dotcms-analytics-contentlet element
10
+ * - Filters for clicks on <a> or <button> elements inside tracked contentlets
11
+ * - Extracts contentlet data and element metadata
12
+ * - Throttles clicks to prevent duplicates
13
+ * - Fires 'content_click' events via subscription callback
14
+ *
15
+ * Note: This plugin is only registered if config.clicks is enabled.
16
+ * See getEnhancedTrackingPlugins() for conditional loading logic.
17
+ *
18
+ * @param {DotCMSAnalyticsConfig} config - Configuration with clicks settings
19
+ * @returns {Object} Plugin object with lifecycle methods
20
+ */
21
+ export declare const dotAnalyticsClickPlugin: (config: DotCMSAnalyticsConfig) => {
22
+ name: string;
23
+ /**
24
+ * Initialize click tracking
25
+ * Called when Analytics.js initializes the plugin with instance context
26
+ * @param instance - Analytics.js instance with track method
27
+ */
28
+ initialize: ({ instance }: {
29
+ instance: AnalyticsInstance;
30
+ }) => Promise<void>;
31
+ /**
32
+ * Setup cleanup handlers when plugin is loaded
33
+ * Called after Analytics.js completes plugin loading
34
+ */
35
+ loaded: () => boolean;
36
+ };
@@ -0,0 +1,27 @@
1
+ import { DotCMSClickTracker as o } from "./dot-analytics.click-tracker.js";
2
+ import { createPluginLogger as u, isBrowser as a, setupPluginCleanup as s } from "../../shared/utils/dot-analytics.utils.js";
3
+ const g = (n) => {
4
+ let i = null, l = null;
5
+ const e = u("Click", n);
6
+ return {
7
+ name: "dot-analytics-click",
8
+ /**
9
+ * Initialize click tracking
10
+ * Called when Analytics.js initializes the plugin with instance context
11
+ * @param instance - Analytics.js instance with track method
12
+ */
13
+ initialize: ({ instance: r }) => (i = new o(n), l = i.onClick((c, t) => {
14
+ r.track(c, t);
15
+ }), i.initialize(), e.info("Click tracking plugin initialized"), Promise.resolve()),
16
+ /**
17
+ * Setup cleanup handlers when plugin is loaded
18
+ * Called after Analytics.js completes plugin loading
19
+ */
20
+ loaded: () => (a() && i && s(() => {
21
+ l && (l.unsubscribe(), l = null), i && (i.cleanup(), i = null, e.info("Click tracking cleaned up on page unload"));
22
+ }), !0)
23
+ };
24
+ };
25
+ export {
26
+ g as dotAnalyticsClickPlugin
27
+ };
@@ -0,0 +1,12 @@
1
+ import { DotCMSContentClickPayload } from '../../shared/models';
2
+ import { createPluginLogger } from '../../shared/utils/dot-analytics.utils';
3
+ /**
4
+ * Handles click events on elements within a contentlet.
5
+ * The contentlet element is already known since we attach listeners to contentlets.
6
+ *
7
+ * @param event - The mouse event
8
+ * @param contentletElement - The contentlet container element
9
+ * @param trackCallback - Callback to execute if the click is valid
10
+ * @param logger - Logger instance for debug messages
11
+ */
12
+ export declare const handleContentletClick: (event: MouseEvent, contentletElement: HTMLElement, trackCallback: (eventName: string, payload: DotCMSContentClickPayload) => void, logger: ReturnType<typeof createPluginLogger>) => void;
@@ -0,0 +1,55 @@
1
+ import { CLICKABLE_ELEMENTS_SELECTOR as l, CLICK_EVENT_TYPE as m } from "../../shared/constants/dot-analytics.constants.js";
2
+ import { extractContentletData as p } from "../../shared/utils/dot-analytics.utils.js";
3
+ import { getViewportMetrics as b } from "../impression/dot-analytics.impression.utils.js";
4
+ const _ = (r, o, c, e) => {
5
+ const a = r.target;
6
+ e.debug("Click detected on:", a);
7
+ const t = a.closest(l);
8
+ if (!t) {
9
+ e.debug("No <a> or <button> found in click path");
10
+ return;
11
+ }
12
+ if (!o.contains(t)) {
13
+ e.debug("Click was outside contentlet boundary");
14
+ return;
15
+ }
16
+ e.debug("Found clickable element:", t);
17
+ const n = p(o);
18
+ if (!n.identifier) {
19
+ e.debug("Contentlet has no identifier");
20
+ return;
21
+ }
22
+ e.debug("Contentlet data:", n);
23
+ const d = b(o), s = [];
24
+ for (const i of t.attributes)
25
+ !i.name.startsWith("data-dot-analytics") && i.name !== "class" && i.name !== "id" && i.name !== "href" && s.push(`${i.name}:${i.value}`);
26
+ const f = parseInt(o.dataset.dotAnalyticsDomIndex || "-1", 10), u = {
27
+ content: {
28
+ identifier: n.identifier,
29
+ inode: n.inode,
30
+ title: n.title,
31
+ content_type: n.contentType
32
+ },
33
+ position: {
34
+ viewport_offset_pct: d.offsetPercentage,
35
+ dom_index: f
36
+ },
37
+ element: {
38
+ text: (t.innerText || t.textContent || "").trim().substring(0, 100),
39
+ // Limit length
40
+ type: t.tagName.toLowerCase(),
41
+ id: t.id || "",
42
+ // Required by backend, empty string if not present
43
+ class: t.className || "",
44
+ // Required by backend, empty string if not present
45
+ href: t.getAttribute("href") || "",
46
+ // Path as written in HTML (relative), empty string for buttons
47
+ attributes: s
48
+ // Additional attributes (data-*, aria-*, target, etc.)
49
+ }
50
+ };
51
+ c(m, u);
52
+ };
53
+ export {
54
+ _ as handleContentletClick
55
+ };
@@ -21,7 +21,7 @@ export declare const dotAnalyticsEnricherPlugin: () => {
21
21
  }) => EnrichedAnalyticsPayload;
22
22
  /**
23
23
  * TRACK EVENT ENRICHMENT - Runs after identity context injection
24
- * Adds page data and timestamp for predefined events.
24
+ * Adds page data and timestamp for predefined content events.
25
25
  * For custom events, only adds timestamp.
26
26
  *
27
27
  * @returns {EnrichedTrackPayload} Enriched payload ready for event structuring
@@ -1,5 +1,5 @@
1
- import { DotCMSPredefinedEventType as n } from "../../shared/constants/dot-content-analytics.constants.js";
2
- import { getLocalTime as i, enrichPagePayloadOptimized as o } from "../../shared/dot-content-analytics.utils.js";
1
+ import { DotCMSPredefinedEventType as r } from "../../shared/constants/dot-analytics.constants.js";
2
+ import { getLocalTime as i, enrichPagePayloadOptimized as o } from "../../shared/utils/dot-analytics.utils.js";
3
3
  const l = () => ({
4
4
  name: "enrich-dot-analytics",
5
5
  /**
@@ -8,34 +8,34 @@ const l = () => ({
8
8
  * @returns {EnrichedAnalyticsPayload} Enriched payload ready for event creation
9
9
  */
10
10
  "page:dot-analytics": ({
11
- payload: t
11
+ payload: e
12
12
  }) => {
13
- const e = o(t);
14
- if (!e.page)
13
+ const t = o(e);
14
+ if (!t.page)
15
15
  throw new Error("DotCMS Analytics: Missing required page data");
16
- return e;
16
+ return t;
17
17
  },
18
18
  /**
19
19
  * TRACK EVENT ENRICHMENT - Runs after identity context injection
20
- * Adds page data and timestamp for predefined events.
20
+ * Adds page data and timestamp for predefined content events.
21
21
  * For custom events, only adds timestamp.
22
22
  *
23
23
  * @returns {EnrichedTrackPayload} Enriched payload ready for event structuring
24
24
  */
25
25
  "track:dot-analytics": ({
26
- payload: t
26
+ payload: e
27
27
  }) => {
28
- const { event: e } = t, r = i();
29
- return e === n.CONTENT_IMPRESSION ? {
30
- ...t,
28
+ const { event: t } = e, n = i();
29
+ return t === r.CONTENT_IMPRESSION || t === r.CONTENT_CLICK || t === r.CONVERSION ? {
30
+ ...e,
31
31
  page: {
32
32
  title: document.title,
33
33
  url: window.location.href
34
34
  },
35
- local_time: r
35
+ local_time: n
36
36
  } : {
37
- ...t,
38
- local_time: r
37
+ ...e,
38
+ local_time: n
39
39
  };
40
40
  }
41
41
  });
@@ -1,5 +1,5 @@
1
- import { ANALYTICS_WINDOWS_ACTIVE_KEY, ANALYTICS_WINDOWS_CLEANUP_KEY } from '../../../../../uve/src/internal.ts';
2
- import { DotCMSAnalyticsConfig } from './models';
1
+ import { ANALYTICS_WINDOWS_ACTIVE_KEY, ANALYTICS_WINDOWS_CLEANUP_KEY } from '../../../../../../uve/src/internal.ts';
2
+ import { DotCMSAnalyticsConfig } from '../../shared/models';
3
3
  declare global {
4
4
  interface Window {
5
5
  [ANALYTICS_WINDOWS_CLEANUP_KEY]?: () => void;
@@ -10,13 +10,6 @@ declare global {
10
10
  * Updates session activity with throttling
11
11
  */
12
12
  export declare const updateSessionActivity: () => void;
13
- /**
14
- * Gets session information for debugging
15
- */
16
- export declare const getSessionInfo: () => {
17
- lastActivity: number;
18
- isActive: boolean;
19
- };
20
13
  /**
21
14
  * Initializes activity tracking
22
15
  */
@@ -25,11 +18,3 @@ export declare const initializeActivityTracking: (config: DotCMSAnalyticsConfig)
25
18
  * Cleans up activity tracking listeners and resets analytics state
26
19
  */
27
20
  export declare const cleanupActivityTracking: () => void;
28
- /**
29
- * Checks if user has been inactive
30
- */
31
- export declare const isUserInactive: () => boolean;
32
- /**
33
- * Gets last activity time
34
- */
35
- export declare const getLastActivity: () => number;
@@ -1,6 +1,6 @@
1
- import { ANALYTICS_WINDOWS_ACTIVE_KEY as o, ANALYTICS_WINDOWS_CLEANUP_KEY as r } from "../../../uve/src/internal/constants.js";
2
- import { DEFAULT_SESSION_TIMEOUT_MINUTES as c, ACTIVITY_EVENTS as v } from "./constants/dot-content-analytics.constants.js";
3
- class l {
1
+ import { ANALYTICS_WINDOWS_ACTIVE_KEY as a, ANALYTICS_WINDOWS_CLEANUP_KEY as o } from "../../../../uve/src/internal/constants.js";
2
+ import { DEFAULT_SESSION_TIMEOUT_MINUTES as r, ACTIVITY_EVENTS as l } from "../../shared/constants/dot-analytics.constants.js";
3
+ class v {
4
4
  constructor() {
5
5
  this.activityListeners = [], this.lastActivityTime = Date.now(), this.inactivityTimer = null, this.isThrottled = !1, this.config = null, this.ACTIVITY_THROTTLE_MS = 1e3;
6
6
  }
@@ -12,24 +12,11 @@ class l {
12
12
  this.lastActivityTime = Date.now(), this.inactivityTimer && clearTimeout(this.inactivityTimer), this.inactivityTimer = setTimeout(
13
13
  () => {
14
14
  var i;
15
- (i = this.config) != null && i.debug && console.warn("DotCMS Analytics: User became inactive after timeout"), this.inactivityTimer = null;
15
+ (i = this.config) != null && i.debug && console.warn("DotCMS Analytics [Activity]: User became inactive after timeout"), this.inactivityTimer = null;
16
16
  },
17
- c * 60 * 1e3
17
+ r * 60 * 1e3
18
18
  );
19
19
  }
20
- /**
21
- * Checks if user has been inactive
22
- */
23
- isUserInactive() {
24
- const i = c * 60 * 1e3;
25
- return Date.now() - this.lastActivityTime > i;
26
- }
27
- /**
28
- * Gets last activity time
29
- */
30
- getLastActivity() {
31
- return this.lastActivityTime;
32
- }
33
20
  /**
34
21
  * Updates session activity with throttling
35
22
  */
@@ -45,17 +32,19 @@ class l {
45
32
  if (this.cleanup(), this.config = i, typeof window > "u")
46
33
  return;
47
34
  const s = () => this.updateSessionActivity();
48
- v.forEach((a) => {
49
- window.addEventListener(a, s, { passive: !0 }), this.activityListeners.push(
50
- () => window.removeEventListener(a, s)
35
+ l.forEach((c) => {
36
+ window.addEventListener(c, s, { passive: !0 }), this.activityListeners.push(
37
+ () => window.removeEventListener(c, s)
51
38
  );
52
39
  });
53
40
  const n = () => {
54
- document.visibilityState === "visible" && (this.updateSessionActivity(), i.debug && console.warn("DotCMS Analytics: User returned to tab, session reactivated"));
41
+ document.visibilityState === "visible" && (this.updateSessionActivity(), i.debug && console.warn(
42
+ "DotCMS Analytics [Activity]: User returned to tab, session reactivated"
43
+ ));
55
44
  };
56
45
  document.addEventListener("visibilitychange", n), this.activityListeners.push(
57
46
  () => document.removeEventListener("visibilitychange", n)
58
- ), this.updateActivityTime(), i.debug && console.warn("DotCMS Analytics: Activity tracking initialized");
47
+ ), this.updateActivityTime(), i.debug && console.warn("DotCMS Analytics [Activity]: Activity tracking initialized");
59
48
  }
60
49
  /**
61
50
  * Cleans up all activity tracking listeners
@@ -63,25 +52,16 @@ class l {
63
52
  cleanup() {
64
53
  this.activityListeners.forEach((i) => i()), this.activityListeners = [], this.inactivityTimer && (clearTimeout(this.inactivityTimer), this.inactivityTimer = null), this.config = null;
65
54
  }
66
- /**
67
- * Gets session information for debugging
68
- */
69
- getSessionInfo() {
70
- return {
71
- lastActivity: this.getLastActivity(),
72
- isActive: !this.isUserInactive()
73
- };
74
- }
75
55
  }
76
- const t = new l(), u = () => {
56
+ const t = new v(), d = () => {
77
57
  t.updateSessionActivity();
78
- }, d = (e) => {
58
+ }, u = (e) => {
79
59
  t.initialize(e);
80
60
  }, y = () => {
81
- t.cleanup(), typeof window < "u" && (window[o] = !1, window[r] = void 0, window.dispatchEvent(new CustomEvent("dotcms:analytics:cleanup")));
61
+ t.cleanup(), typeof window < "u" && (window[a] = !1, window[o] = void 0, window.dispatchEvent(new CustomEvent("dotcms:analytics:cleanup")));
82
62
  };
83
63
  export {
84
64
  y as cleanupActivityTracking,
85
- d as initializeActivityTracking,
86
- u as updateSessionActivity
65
+ u as initializeActivityTracking,
66
+ d as updateSessionActivity
87
67
  };
@@ -1,5 +1,5 @@
1
- import { getAnalyticsContext as n } from "../../shared/dot-content-analytics.utils.js";
2
- import { cleanupActivityTracking as r, updateSessionActivity as o, initializeActivityTracking as a } from "../../shared/dot-content-analytics.activity-tracker.js";
1
+ import { cleanupActivityTracking as n, updateSessionActivity as r, initializeActivityTracking as a } from "./dot-analytics.identity.activity-tracker.js";
2
+ import { getAnalyticsContext as o } from "../../shared/utils/dot-analytics.utils.js";
3
3
  const s = (t) => ({
4
4
  name: "dot-analytics-identity",
5
5
  /**
@@ -12,8 +12,8 @@ const s = (t) => ({
12
12
  * This runs BEFORE the enricher plugin
13
13
  */
14
14
  pageStart: ({ payload: e }) => {
15
- o();
16
- const i = n(t);
15
+ r();
16
+ const i = o(t);
17
17
  return {
18
18
  ...e,
19
19
  context: i
@@ -24,8 +24,8 @@ const s = (t) => ({
24
24
  * This runs BEFORE the enricher plugin
25
25
  */
26
26
  trackStart: ({ payload: e }) => {
27
- o();
28
- const i = n(t);
27
+ r();
28
+ const i = o(t);
29
29
  return {
30
30
  ...e,
31
31
  context: i
@@ -35,7 +35,7 @@ const s = (t) => ({
35
35
  * Clean up on plugin unload
36
36
  * Sets up cleanup handlers for activity tracking
37
37
  */
38
- loaded: () => (typeof window < "u" && (window.addEventListener("beforeunload", r), window.addEventListener("pagehide", r)), !0)
38
+ loaded: () => (typeof window < "u" && (window.addEventListener("beforeunload", n), window.addEventListener("pagehide", n)), !0)
39
39
  });
40
40
  export {
41
41
  s as dotAnalyticsIdentityPlugin
@@ -1,20 +1,4 @@
1
1
  import { DotCMSEventUtmData } from '../../shared/models';
2
- /**
3
- * Updates activity timestamp
4
- */
5
- export declare const updateActivityTime: () => void;
6
- /**
7
- * Checks if user has been inactive
8
- */
9
- export declare const isUserInactive: () => boolean;
10
- /**
11
- * Checks if a new day has started since session creation
12
- */
13
- export declare const hasPassedMidnight: (sessionStartTime: number) => boolean;
14
- /**
15
- * Gets the last activity time
16
- */
17
- export declare const getLastActivityTime: () => number;
18
2
  /**
19
3
  * Compares UTM parameters to detect campaign changes.
20
4
  * Only checks significant parameters: source, medium, and campaign.
@@ -1,4 +1,4 @@
1
- import { DotCMSAnalyticsConfig, DotCMSContentImpressionPayload } from './models';
1
+ import { DotCMSAnalyticsConfig, DotCMSContentImpressionPayload } from '../../shared/models';
2
2
  /** Callback function for impression events */
3
3
  export type ImpressionCallback = (eventName: string, payload: DotCMSContentImpressionPayload) => void;
4
4
  /** Subscription object with unsubscribe method */
@@ -17,7 +17,7 @@ export declare class DotCMSImpressionTracker {
17
17
  private impressionConfig;
18
18
  private currentPagePath;
19
19
  private subscribers;
20
- private debug;
20
+ private logger;
21
21
  constructor(config: DotCMSAnalyticsConfig);
22
22
  /**
23
23
  * Subscribe to impression events
@@ -1,10 +1,11 @@
1
- import { getUVEState as d } from "../../../uve/src/lib/core/core.utils.js";
2
- import "../../../uve/src/internal/constants.js";
3
- import { DEFAULT_IMPRESSION_CONFIG as l, ANALYTICS_CONTENTLET_CLASS as a, IMPRESSION_EVENT_TYPE as h, DEFAULT_IMPRESSION_MUTATION_OBSERVER_DEBOUNCE_MS as u } from "./constants/dot-content-analytics.constants.js";
4
- import { extractContentletIdentifier as c, createDebounce as m, extractContentletData as p, getViewportMetrics as b, isElementMeetingVisibilityThreshold as f } from "../plugin/impression/dot-analytics.impression.utils.js";
5
- class I {
1
+ import { getUVEState as m } from "../../../../uve/src/lib/core/core.utils.js";
2
+ import "../../../../uve/src/internal/constants.js";
3
+ import { getViewportMetrics as d, isElementMeetingVisibilityThreshold as u } from "./dot-analytics.impression.utils.js";
4
+ import { DEFAULT_IMPRESSION_CONFIG as l, IMPRESSION_EVENT_TYPE as g } from "../../shared/constants/dot-analytics.constants.js";
5
+ import { createPluginLogger as p, isBrowser as a, INITIAL_SCAN_DELAY_MS as f, findContentlets as b, extractContentletIdentifier as c, createContentletObserver as v, extractContentletData as I } from "../../shared/utils/dot-analytics.utils.js";
6
+ class E {
6
7
  constructor(e) {
7
- this.observer = null, this.mutationObserver = null, this.elementImpressionStates = /* @__PURE__ */ new Map(), this.sessionTrackedImpressions = /* @__PURE__ */ new Set(), this.currentPagePath = "", this.subscribers = /* @__PURE__ */ new Set(), this.debug = e.debug ?? !1, this.impressionConfig = this.resolveImpressionConfig(e.impressions);
8
+ this.observer = null, this.mutationObserver = null, this.elementImpressionStates = /* @__PURE__ */ new Map(), this.sessionTrackedImpressions = /* @__PURE__ */ new Set(), this.currentPagePath = "", this.subscribers = /* @__PURE__ */ new Set(), this.logger = p("Impression", e), this.impressionConfig = this.resolveImpressionConfig(e.impressions);
8
9
  }
9
10
  /**
10
11
  * Subscribe to impression events
@@ -24,7 +25,7 @@ class I {
24
25
  try {
25
26
  t(e, i);
26
27
  } catch (s) {
27
- this.debug && console.error("DotCMS Analytics: Error in impression subscriber:", s);
28
+ this.logger.error("Error in impression subscriber:", s);
28
29
  }
29
30
  });
30
31
  }
@@ -37,15 +38,14 @@ class I {
37
38
  }
38
39
  /** Initializes tracking: sets up observers, finds contentlets, handles visibility/navigation */
39
40
  initialize() {
40
- if (!(typeof window > "u" || typeof document > "u")) {
41
- if (d()) {
42
- this.debug && console.warn("DotCMS Analytics: Impression tracking disabled in editor mode");
41
+ if (a()) {
42
+ if (m()) {
43
+ this.logger.warn("Impression tracking disabled in editor mode");
43
44
  return;
44
45
  }
45
- this.initializeIntersectionObserver(), this.findAndObserveContentletElements(), this.initializeDynamicContentDetector(), this.initializePageVisibilityHandler(), this.initializePageNavigationHandler(), this.debug && console.warn(
46
- "DotCMS Analytics: Impression tracking initialized with config:",
47
- this.impressionConfig
48
- );
46
+ this.initializeIntersectionObserver(), typeof window < "u" && setTimeout(() => {
47
+ this.logger.debug("Running initial scan after timeout..."), this.findAndObserveContentletElements();
48
+ }, f), this.initializeDynamicContentDetector(), this.initializePageVisibilityHandler(), this.initializePageNavigationHandler(), this.logger.info("Impression tracking initialized with config:", this.impressionConfig);
49
49
  }
50
50
  }
51
51
  /** Sets up IntersectionObserver with configured visibility threshold */
@@ -63,11 +63,9 @@ class I {
63
63
  /** Finds contentlets in DOM, validates them, and starts observing (respects maxNodes limit) */
64
64
  findAndObserveContentletElements() {
65
65
  if (!this.observer) return;
66
- const e = document.querySelectorAll(
67
- `.${a}`
68
- );
66
+ const e = b();
69
67
  if (e.length === 0) {
70
- this.debug && console.warn("DotCMS Analytics: No contentlets found to track");
68
+ this.logger.warn("No contentlets found to track");
71
69
  return;
72
70
  }
73
71
  const i = Math.min(e.length, this.impressionConfig.maxNodes);
@@ -77,45 +75,33 @@ class I {
77
75
  if (r) {
78
76
  const o = this.shouldSkipElement(n);
79
77
  if (o) {
80
- this.debug && console.warn(
81
- `DotCMS Analytics: Skipping element ${r} (${o})`
82
- );
78
+ this.logger.debug(`Skipping element ${r} (${o})`);
83
79
  continue;
84
80
  }
85
- this.elementImpressionStates.has(r) || (this.observer.observe(n), this.elementImpressionStates.set(r, {
81
+ this.elementImpressionStates.has(r) || (n.dataset.dotAnalyticsDomIndex || (n.dataset.dotAnalyticsDomIndex = String(s)), this.observer.observe(n), this.elementImpressionStates.set(r, {
86
82
  timer: null,
87
83
  visibleSince: null,
88
84
  tracked: this.hasBeenTrackedInSession(r),
89
85
  element: n
90
- }), t++, this.debug && (n.dataset.dotAnalyticsObserved = "true", n.style.outline = "2px solid red", n.style.outlineOffset = "-2px", n.style.transition = "outline-color 0.5s ease-in-out"));
86
+ }), t++);
91
87
  }
92
88
  }
93
- this.debug && (console.warn(`DotCMS Analytics: Observing ${t} contentlets`), e.length > i && console.warn(
94
- `DotCMS Analytics: ${e.length - i} contentlets not tracked (maxNodes limit: ${this.impressionConfig.maxNodes})`
95
- ));
89
+ this.logger.info(`Observing ${t} contentlets`), e.length > i && this.logger.warn(
90
+ `${e.length - i} contentlets not tracked (maxNodes limit: ${this.impressionConfig.maxNodes})`
91
+ );
96
92
  }
97
93
  /** Watches for new contentlets added to DOM (debounced for performance) */
98
94
  initializeDynamicContentDetector() {
99
- if (typeof window > "u" || typeof document > "u")
100
- return;
101
- const e = m(() => {
95
+ a() && (this.mutationObserver = v(() => {
102
96
  this.findAndObserveContentletElements();
103
- }, u);
104
- this.mutationObserver = new MutationObserver(() => {
105
- e();
106
- }), this.mutationObserver.observe(document.body, {
107
- childList: !0,
108
- subtree: !0
109
- }), this.debug && console.warn(
110
- "DotCMS Analytics: MutationObserver enabled for dynamic content detection"
111
- );
97
+ }), this.logger.info("MutationObserver enabled for dynamic content detection"));
112
98
  }
113
99
  /** Cancels all timers when page is hidden (prevents false impressions) */
114
100
  initializePageVisibilityHandler() {
115
101
  document.addEventListener("visibilitychange", () => {
116
102
  document.visibilityState === "hidden" && (this.elementImpressionStates.forEach((e) => {
117
103
  e.timer !== null && (window.clearTimeout(e.timer), e.timer = null, e.visibleSince = null);
118
- }), this.debug && console.warn("DotCMS Analytics: Page hidden, all impression timers cancelled"));
104
+ }), this.logger.warn("Page hidden, all impression timers cancelled"));
119
105
  });
120
106
  }
121
107
  /** Resets tracking on SPA navigation (listens to pushState, replaceState, popstate) */
@@ -123,8 +109,8 @@ class I {
123
109
  this.currentPagePath = window.location.pathname;
124
110
  const e = () => {
125
111
  const s = window.location.pathname;
126
- s !== this.currentPagePath && (this.debug && console.warn(
127
- `DotCMS Analytics: Navigation detected (${this.currentPagePath} → ${s}), resetting impression tracking`
112
+ s !== this.currentPagePath && (this.logger.warn(
113
+ `Navigation detected (${this.currentPagePath} → ${s}), resetting impression tracking`
128
114
  ), this.currentPagePath = s, this.sessionTrackedImpressions.clear(), this.elementImpressionStates.forEach((n) => {
129
115
  n.timer !== null && (window.clearTimeout(n.timer), n.timer = null, n.visibleSince = null);
130
116
  }), this.elementImpressionStates.clear());
@@ -135,7 +121,7 @@ class I {
135
121
  i.apply(this, s), e();
136
122
  }, history.replaceState = function(...s) {
137
123
  t.apply(this, s), e();
138
- }, setInterval(e, 1e3);
124
+ };
139
125
  }
140
126
  /** Handles visibility changes: starts timer on enter, cancels on exit */
141
127
  processIntersectionChanges(e) {
@@ -148,23 +134,23 @@ class I {
148
134
  startImpressionDwellTimer(e, i) {
149
135
  const t = this.elementImpressionStates.get(e);
150
136
  t && (t.tracked || this.hasBeenTrackedInSession(e) || t.timer === null && document.visibilityState === "visible" && (t.visibleSince = Date.now(), t.element = i, t.timer = window.setTimeout(() => {
151
- this.isElementStillVisible(i) ? this.trackAndSendImpression(e, i) : (this.debug && console.warn(
152
- `DotCMS Analytics: Dwell timer expired for ${e} but element no longer visible, skipping impression`
137
+ this.isElementStillVisible(i) ? this.trackAndSendImpression(e, i) : (this.logger.warn(
138
+ `Dwell timer expired for ${e} but element no longer visible, skipping impression`
153
139
  ), t.timer = null, t.visibleSince = null);
154
- }, this.impressionConfig.dwellMs), this.debug && console.warn(
155
- `DotCMS Analytics: Started dwell timer for ${e} (${this.impressionConfig.dwellMs}ms)`
140
+ }, this.impressionConfig.dwellMs), this.logger.debug(
141
+ `Started dwell timer for ${e} (${this.impressionConfig.dwellMs}ms)`
156
142
  )));
157
143
  }
158
144
  /** Cancels active dwell timer (element left viewport before dwell time) */
159
145
  cancelImpressionDwellTimer(e) {
160
146
  const i = this.elementImpressionStates.get(e);
161
- !i || i.timer === null || (window.clearTimeout(i.timer), i.timer = null, i.visibleSince = null, this.debug && console.warn(`DotCMS Analytics: Cancelled dwell timer for ${e}`));
147
+ !i || i.timer === null || (window.clearTimeout(i.timer), i.timer = null, i.visibleSince = null, this.logger.debug(`Cancelled dwell timer for ${e}`));
162
148
  }
163
149
  /** Fires impression event with content & position data (page data added by enricher plugin) */
164
150
  trackAndSendImpression(e, i) {
165
151
  const t = this.elementImpressionStates.get(e);
166
152
  if (!t) return;
167
- const s = t.visibleSince ? Date.now() - t.visibleSince : 0, n = p(i), r = b(i), o = {
153
+ const s = t.visibleSince ? Date.now() - t.visibleSince : 0, n = I(i), r = d(i), o = parseInt(i.dataset.dotAnalyticsDomIndex || "-1", 10), h = {
168
154
  content: {
169
155
  identifier: n.identifier,
170
156
  inode: n.inode,
@@ -173,15 +159,13 @@ class I {
173
159
  },
174
160
  position: {
175
161
  viewport_offset_pct: r.offsetPercentage,
176
- dom_index: Array.from(
177
- document.querySelectorAll(`.${a}`)
178
- ).indexOf(i)
162
+ dom_index: o
179
163
  }
180
164
  };
181
- this.notifySubscribers(h, o), this.markImpressionAsTracked(e), t.timer = null, t.visibleSince = null, t.tracked = !0, this.observer && this.observer.unobserve(i), this.debug && (i.style.outline = "2px solid green", i.style.outlineOffset = "-2px", console.warn(
182
- `DotCMS Analytics: Fired impression for ${e} (dwell: ${s}ms) - element unobserved`,
165
+ this.notifySubscribers(g, h), this.markImpressionAsTracked(e), t.timer = null, t.visibleSince = null, t.tracked = !0, this.observer && this.observer.unobserve(i), this.logger.info(
166
+ `Fired impression for ${e} (dwell: ${s}ms) - element unobserved`,
183
167
  n
184
- ));
168
+ );
185
169
  }
186
170
  /** Returns skip reason if element is hidden/too small, null if trackable */
187
171
  shouldSkipElement(e) {
@@ -193,7 +177,7 @@ class I {
193
177
  }
194
178
  /** Post-dwell check: verifies element still meets visibility threshold */
195
179
  isElementStillVisible(e) {
196
- return document.visibilityState !== "visible" ? !1 : f(
180
+ return document.visibilityState !== "visible" ? !1 : u(
197
181
  e,
198
182
  this.impressionConfig.visibilityThreshold
199
183
  );
@@ -210,9 +194,9 @@ class I {
210
194
  cleanup() {
211
195
  this.observer && (this.observer.disconnect(), this.observer = null), this.mutationObserver && (this.mutationObserver.disconnect(), this.mutationObserver = null), this.elementImpressionStates.forEach((e) => {
212
196
  e.timer !== null && window.clearTimeout(e.timer);
213
- }), this.elementImpressionStates.clear(), this.subscribers.clear(), this.debug && console.warn("DotCMS Analytics: Impression tracking cleaned up");
197
+ }), this.elementImpressionStates.clear(), this.subscribers.clear(), this.logger.info("Impression tracking cleaned up");
214
198
  }
215
199
  }
216
200
  export {
217
- I as DotCMSImpressionTracker
201
+ E as DotCMSImpressionTracker
218
202
  };
@@ -3,7 +3,6 @@ import { DotCMSAnalyticsConfig } from '../../shared/models';
3
3
  /**
4
4
  * Impression Plugin for DotAnalytics
5
5
  * Handles automatic tracking of content visibility and impressions.
6
- * Only activates when config.impressions is enabled (true or config object).
7
6
  *
8
7
  * This plugin initializes the impression tracker which:
9
8
  * - Uses IntersectionObserver to detect when contentlets are visible
@@ -17,13 +16,16 @@ import { DotCMSAnalyticsConfig } from '../../shared/models';
17
16
  * 3. Main Plugin - Sends to queue/server
18
17
  * 4. Impression Plugin - Runs independently, fires events via instance.track()
19
18
  *
19
+ * Note: This plugin is only registered if config.impressions is enabled.
20
+ * See getEnhancedTrackingPlugins() for conditional loading logic.
21
+ *
20
22
  * @param {DotCMSAnalyticsConfig} config - Configuration with impressions settings
21
23
  * @returns {Object} Plugin object with lifecycle methods
22
24
  */
23
25
  export declare const dotAnalyticsImpressionPlugin: (config: DotCMSAnalyticsConfig) => {
24
26
  name: string;
25
27
  /**
26
- * Initialize impression tracking if enabled
28
+ * Initialize impression tracking
27
29
  * Called when Analytics.js initializes the plugin with instance context
28
30
  * @param instance - Analytics.js instance with track method
29
31
  */