@coralogix/browser 3.9.0 → 3.10.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.
package/CHANGELOG.md CHANGED
@@ -1,3 +1,9 @@
1
+ ## 3.10.0 (2026-05-25)
2
+
3
+ ### 🚀 Features
4
+
5
+ - Improve user interaction instrumentation with richer element metadata
6
+
1
7
  ## 3.9.0 (2026-05-19)
2
8
 
3
9
  ### 🚀 Features
package/README.md CHANGED
@@ -559,6 +559,28 @@ Examples of masked elements:
559
559
 
560
560
  ```
561
561
 
562
+ ### Action Attributes
563
+
564
+ The SDK uses various strategies to name click actions. For more control, define a `data-cx-action-name` attribute on clickable elements (or any of their parents) to set the action name.
565
+
566
+ ```html
567
+ <button data-cx-action-name="add-to-cart">
568
+ Add to Cart
569
+ </button>
570
+
571
+ <form data-cx-action-name="checkout-form">
572
+ <input type="text" placeholder="Card number" />
573
+ <button type="submit">Complete Purchase</button>
574
+ </form>
575
+
576
+ <nav data-cx-action-name="main-navigation">
577
+ <a href="/products">Products</a>
578
+ <a href="/pricing">Pricing</a>
579
+ </nav>
580
+ ```
581
+
582
+ > **Note:** The `data-cx-action-name` attribute is never masked, even when the element has a mask class applied. This ensures your custom action names are always captured for tracking purposes.
583
+
562
584
  ### Label Providers
563
585
 
564
586
  Provide labels based on url or event
package/index.esm2.js CHANGED
@@ -2124,6 +2124,43 @@ function addEventListeners(eventTarget, eventNames, listener, _a) {
2124
2124
 
2125
2125
  var PARENT_SEARCH_DEPTH = 5;
2126
2126
  var CLICKABLE_ELEMENTS = ['BUTTON', 'LABEL', 'A', 'INPUT', 'OPTION'];
2127
+ function getAttributeFromAncestors(element, attr, depth) {
2128
+ if (depth === void 0) { depth = PARENT_SEARCH_DEPTH; }
2129
+ if (!element || depth <= 0)
2130
+ return '';
2131
+ var value = element.getAttribute(attr);
2132
+ if (value)
2133
+ return value;
2134
+ return getAttributeFromAncestors(element.parentElement, attr, depth - 1);
2135
+ }
2136
+ function extractActionName(el) {
2137
+ return getAttributeFromAncestors(el, CX_ACTION_NAME_ATTRIBUTE);
2138
+ }
2139
+ function extractAriaLabel(el) {
2140
+ return getAttributeFromAncestors(el, ARIA_LABEL_ATTRIBUTE);
2141
+ }
2142
+ function extractTestId(el) {
2143
+ return (el === null || el === void 0 ? void 0 : el.getAttribute(DATA_TEST_ATTRIBUTE)) || '';
2144
+ }
2145
+ function extractResolvedName(_a) {
2146
+ var element = _a.element, config = _a.config, actionName = _a.actionName, ariaLabel = _a.ariaLabel;
2147
+ if (!element)
2148
+ return '';
2149
+ if (actionName)
2150
+ return actionName;
2151
+ if (isElementMasked(element, config))
2152
+ return MASKED_TEXT;
2153
+ return ariaLabel || getPlaceholder(element) || getInnerText(element) || '';
2154
+ }
2155
+ function getPlaceholder(element) {
2156
+ if (element instanceof HTMLInputElement || element instanceof HTMLTextAreaElement) {
2157
+ return element.placeholder || '';
2158
+ }
2159
+ return '';
2160
+ }
2161
+ function getInnerText(element) {
2162
+ return element instanceof HTMLElement ? element.innerText || '' : '';
2163
+ }
2127
2164
  function extractMaskedOrTextContent(element, config) {
2128
2165
  if (!element)
2129
2166
  return '';
@@ -2132,14 +2169,6 @@ function extractMaskedOrTextContent(element, config) {
2132
2169
  return '';
2133
2170
  return getMaskedOrTextualContent(clickableElement, config);
2134
2171
  }
2135
- function findClickableElement(element, maxDepth) {
2136
- if (!element || maxDepth <= 0) {
2137
- return null;
2138
- }
2139
- if (CLICKABLE_ELEMENTS.includes(element.nodeName))
2140
- return element;
2141
- return findClickableElement(element.parentElement, maxDepth - 1);
2142
- }
2143
2172
  function getMaskedOrTextualContent(element, config) {
2144
2173
  if (shouldMaskElement(element, config.maskInputTypes, config.maskClass) ||
2145
2174
  isParentMasked(element, config.maskClass, PARENT_SEARCH_DEPTH)) {
@@ -2151,22 +2180,15 @@ function getMaskedOrTextualContent(element, config) {
2151
2180
  }
2152
2181
  return getTextualContent(element);
2153
2182
  }
2154
- function isParentMasked(element, maskClass, maxDepth) {
2155
- if (maxDepth === void 0) { maxDepth = PARENT_SEARCH_DEPTH; }
2156
- if (!element || maxDepth <= 0) {
2157
- return false;
2158
- }
2159
- if (isMaskedByClass(element.className, maskClass)) {
2160
- return true;
2183
+ function getTextualContent(element) {
2184
+ if (element instanceof HTMLInputElement) {
2185
+ return element.value || '';
2161
2186
  }
2162
- return isParentMasked(element.parentElement, maskClass, maxDepth - 1);
2187
+ return 'innerText' in element ? element.innerText : '';
2163
2188
  }
2164
- function findMaskedChildren(element, config) {
2165
- if (!element.children)
2166
- return null;
2167
- return Array.from(element.children).find(function (child) {
2168
- return shouldMaskElement(child, config.maskInputTypes, config.maskClass);
2169
- });
2189
+ function isElementMasked(element, config) {
2190
+ return (shouldMaskElement(element, config.maskInputTypes, config.maskClass) ||
2191
+ isParentMasked(element, config.maskClass, PARENT_SEARCH_DEPTH));
2170
2192
  }
2171
2193
  function shouldMaskElement(element, maskInputTypes, maskClass) {
2172
2194
  if (!element)
@@ -2190,11 +2212,30 @@ function isMaskedByClass(className, maskClass) {
2190
2212
  }
2191
2213
  return className.includes(maskClass);
2192
2214
  }
2193
- function getTextualContent(element) {
2194
- if (element instanceof HTMLInputElement) {
2195
- return element.value || '';
2215
+ function isParentMasked(element, maskClass, maxDepth) {
2216
+ if (maxDepth === void 0) { maxDepth = PARENT_SEARCH_DEPTH; }
2217
+ if (!element || maxDepth <= 0) {
2218
+ return false;
2196
2219
  }
2197
- return 'innerText' in element ? element.innerText : '';
2220
+ if (isMaskedByClass(element.className, maskClass)) {
2221
+ return true;
2222
+ }
2223
+ return isParentMasked(element.parentElement, maskClass, maxDepth - 1);
2224
+ }
2225
+ function findMaskedChildren(element, config) {
2226
+ if (!element.children)
2227
+ return null;
2228
+ return Array.from(element.children).find(function (child) {
2229
+ return shouldMaskElement(child, config.maskInputTypes, config.maskClass);
2230
+ });
2231
+ }
2232
+ function findClickableElement(element, maxDepth) {
2233
+ if (!element || maxDepth <= 0) {
2234
+ return null;
2235
+ }
2236
+ if (CLICKABLE_ELEMENTS.includes(element.nodeName))
2237
+ return element;
2238
+ return findClickableElement(element.parentElement, maxDepth - 1);
2198
2239
  }
2199
2240
 
2200
2241
  var _a$3;
@@ -2225,10 +2266,19 @@ var CoralogixUserInteractionInstrumentation = (function (_super) {
2225
2266
  var eventTarget = e.target;
2226
2267
  var config = getSdkConfig();
2227
2268
  var id = eventTarget.id, type = eventTarget.type, className = eventTarget.className, nodeName = eventTarget.nodeName;
2228
- var elementText = extractMaskedOrTextContent(eventTarget, config);
2229
2269
  span.setAttribute(CoralogixAttributes.EVENT_TYPE, CoralogixEventType.USER_INTERACTION);
2230
2270
  span.setAttribute(CoralogixAttributes.INTERACTION_EVENT_NAME, e.type);
2231
2271
  if (eventTarget && eventTarget instanceof HTMLElement) {
2272
+ var elementText = extractMaskedOrTextContent(eventTarget, config);
2273
+ var cxActionName = extractActionName(eventTarget);
2274
+ var ariaLabel = extractAriaLabel(eventTarget);
2275
+ var testId = extractTestId(eventTarget);
2276
+ var resolvedName = extractResolvedName({
2277
+ element: eventTarget,
2278
+ config: config,
2279
+ actionName: cxActionName,
2280
+ ariaLabel: ariaLabel,
2281
+ });
2232
2282
  [
2233
2283
  [CoralogixAttributes.ELEMENT_ID, id],
2234
2284
  [CoralogixAttributes.ELEMENT_CLASSES, className],
@@ -2238,6 +2288,13 @@ var CoralogixUserInteractionInstrumentation = (function (_super) {
2238
2288
  elementText === null || elementText === void 0 ? void 0 : elementText.slice(0, MAX_INTERACTION_ELEMENT_SIZE),
2239
2289
  ],
2240
2290
  [CoralogixAttributes.TARGET_ELEMENT, nodeName],
2291
+ [
2292
+ CoralogixAttributes.RESOLVED_NAME,
2293
+ resolvedName === null || resolvedName === void 0 ? void 0 : resolvedName.slice(0, MAX_INTERACTION_ELEMENT_SIZE),
2294
+ ],
2295
+ [CoralogixAttributes.CX_ACTION_NAME, cxActionName],
2296
+ [CoralogixAttributes.ARIA_LABEL, ariaLabel],
2297
+ [CoralogixAttributes.TEST_ID, testId],
2241
2298
  ].forEach(function (_a) {
2242
2299
  var _b = __read$1(_a, 2), key = _b[0], value = _b[1];
2243
2300
  span.setAttribute(key, value);
@@ -2656,6 +2713,9 @@ var NETWORK_URL_LABEL_PROVIDERS_KEY = 'NETWORK_URL_LABEL_PROVIDERS';
2656
2713
  var RUM_INTERNAL_DATA_KEY = 'rumInternalData';
2657
2714
  var MASKED_TEXT = '***';
2658
2715
  var MASK_CLASS_DEFAULT = 'cx-mask';
2716
+ var CX_ACTION_NAME_ATTRIBUTE = 'data-cx-action-name';
2717
+ var ARIA_LABEL_ATTRIBUTE = 'aria-label';
2718
+ var DATA_TEST_ATTRIBUTE = 'data-test';
2659
2719
  var MASK_INPUT_TYPES_DEFAULT = [
2660
2720
  'password',
2661
2721
  'email',
@@ -2796,6 +2856,10 @@ var CoralogixAttributes = {
2796
2856
  ELEMENT_CLASSES: 'element_classes',
2797
2857
  TARGET_ELEMENT: 'target_element',
2798
2858
  TARGET_ELEMENT_TYPE: 'target_element_type',
2859
+ CX_ACTION_NAME: 'cx_action_name',
2860
+ ARIA_LABEL: 'element_aria_label',
2861
+ TEST_ID: 'element_test_id',
2862
+ RESOLVED_NAME: 'element_resolved_name',
2799
2863
  TIMESTAMP: 'timestamp',
2800
2864
  INTERNAL: 'internal',
2801
2865
  PAGE_CONTEXT: 'page_context',
@@ -4376,7 +4440,7 @@ function resolveUrlBlueprinters(urlBlueprinters) {
4376
4440
  return resolvedUrlBlueprinters;
4377
4441
  }
4378
4442
 
4379
- var SDK_VERSION = '3.9.0';
4443
+ var SDK_VERSION = '3.10.0';
4380
4444
 
4381
4445
  function shouldDropEvent(cxRumEvent, options) {
4382
4446
  if (isDocumentErrorWithoutMessage(cxRumEvent)) {
@@ -4701,6 +4765,10 @@ var CoralogixSpanMapProcessor = (function () {
4701
4765
  element_id: spanAttributes[CoralogixAttributes.ELEMENT_ID],
4702
4766
  element_classes: spanAttributes[CoralogixAttributes.ELEMENT_CLASSES],
4703
4767
  target_element_type: spanAttributes[CoralogixAttributes.TARGET_ELEMENT_TYPE],
4768
+ resolved_name: spanAttributes[CoralogixAttributes.RESOLVED_NAME],
4769
+ cx_action_name: spanAttributes[CoralogixAttributes.CX_ACTION_NAME],
4770
+ element_aria_label: spanAttributes[CoralogixAttributes.ARIA_LABEL],
4771
+ element_test_id: spanAttributes[CoralogixAttributes.TEST_ID],
4704
4772
  },
4705
4773
  };
4706
4774
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@coralogix/browser",
3
- "version": "3.9.0",
3
+ "version": "3.10.0",
4
4
  "description": "Official Coralogix SDK for browsers",
5
5
  "license": "Apache-2.0",
6
6
  "author": "Coralogix",
@@ -16,6 +16,9 @@ export declare const NETWORK_URL_LABEL_PROVIDERS_KEY = "NETWORK_URL_LABEL_PROVID
16
16
  export declare const RUM_INTERNAL_DATA_KEY = "rumInternalData";
17
17
  export declare const MASKED_TEXT = "***";
18
18
  export declare const MASK_CLASS_DEFAULT = "cx-mask";
19
+ export declare const CX_ACTION_NAME_ATTRIBUTE = "data-cx-action-name";
20
+ export declare const ARIA_LABEL_ATTRIBUTE = "aria-label";
21
+ export declare const DATA_TEST_ATTRIBUTE = "data-test";
19
22
  export declare const MASK_INPUT_TYPES_DEFAULT: InputType[];
20
23
  export declare const FINGER_PRINT_KEY = "cx-fingerprint";
21
24
  export declare const OPTIONS_DEFAULTS: Partial<CoralogixBrowserSdkConfig>;
@@ -43,6 +46,10 @@ export declare const CoralogixAttributes: {
43
46
  ELEMENT_CLASSES: string;
44
47
  TARGET_ELEMENT: string;
45
48
  TARGET_ELEMENT_TYPE: string;
49
+ CX_ACTION_NAME: string;
50
+ ARIA_LABEL: string;
51
+ TEST_ID: string;
52
+ RESOLVED_NAME: string;
46
53
  TIMESTAMP: string;
47
54
  INTERNAL: string;
48
55
  PAGE_CONTEXT: string;
@@ -1,2 +1,11 @@
1
1
  import { CoralogixBrowserSdkConfig } from '../../types';
2
+ export declare function extractActionName(el: Element | HTMLElement | null): string;
3
+ export declare function extractAriaLabel(el: Element | HTMLElement | null): string;
4
+ export declare function extractTestId(el: Element | HTMLElement | null): string;
5
+ export declare function extractResolvedName({ element, config, actionName, ariaLabel, }: {
6
+ element: Element | HTMLElement | null;
7
+ config: CoralogixBrowserSdkConfig;
8
+ actionName: string;
9
+ ariaLabel: string;
10
+ }): string;
2
11
  export declare function extractMaskedOrTextContent(element: Element | HTMLElement, config: CoralogixBrowserSdkConfig): string;
package/src/types.d.ts CHANGED
@@ -223,6 +223,10 @@ export interface InteractionContext {
223
223
  event_name: string;
224
224
  element_id: string;
225
225
  element_classes: string;
226
+ cx_action_name?: string;
227
+ element_aria_label?: string;
228
+ element_test_id?: string;
229
+ resolved_name: string;
226
230
  }
227
231
  export interface LongTaskContext extends Omit<PerformanceEntry, 'toJSON'> {
228
232
  id: string;
package/src/version.d.ts CHANGED
@@ -1 +1 @@
1
- export declare const SDK_VERSION = "3.9.0";
1
+ export declare const SDK_VERSION = "3.10.0";