posthog-js 1.36.1 → 1.37.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/dist/module.d.ts CHANGED
@@ -135,13 +135,40 @@ interface CaptureResult {
135
135
  timestamp?: Date;
136
136
  }
137
137
  declare type CaptureCallback = (response: any, data: any) => void;
138
+ declare type AutocaptureCompatibleElement = 'a' | 'button' | 'form' | 'input' | 'select' | 'textarea' | 'label';
139
+ declare type DomAutocaptureEvents = 'click' | 'change' | 'submit';
140
+ /**
141
+ * If an array is passed for an allowlist, autocapture events will only be sent for elements matching
142
+ * at least one of the elements in the array. Multiple allowlists can be used
143
+ */
144
+ interface AutocaptureConfig {
145
+ /**
146
+ * List of URLs to allow autocapture on, can be strings to match
147
+ * or regexes e.g. ['https://example.com', 'test.com/.*']
148
+ */
149
+ url_allowlist?: (string | RegExp)[];
150
+ /**
151
+ * List of DOM events to allow autocapture on e.g. ['click', 'change', 'submit']
152
+ */
153
+ dom_event_allowlist?: DomAutocaptureEvents[];
154
+ /**
155
+ * List of DOM elements to allow autocapture on
156
+ * e.g. ['a', 'button', 'form', 'input', 'select', 'textarea', 'label']
157
+ */
158
+ element_allowlist?: AutocaptureCompatibleElement[];
159
+ /**
160
+ * List of CSS selectors to allow autocapture on
161
+ * e.g. ['[ph-capture]']
162
+ */
163
+ css_selector_allowlist?: string[];
164
+ }
138
165
  interface PostHogConfig {
139
166
  api_host: string;
140
167
  api_method: string;
141
168
  api_transport: string;
142
169
  ui_host: string | null;
143
170
  token: string;
144
- autocapture: boolean;
171
+ autocapture: boolean | AutocaptureConfig;
145
172
  rageclick: boolean;
146
173
  cross_subdomain_cookie: boolean;
147
174
  persistence: 'localStorage' | 'cookie' | 'memory' | 'localStorage+cookie';
@@ -908,7 +935,7 @@ declare class PostHog {
908
935
  _jsc: JSC;
909
936
  __captureHooks: ((eventName: string) => void)[];
910
937
  __request_queue: [url: string, data: Record<string, any>, options: XHROptions, callback?: RequestCallback][];
911
- __autocapture_enabled: boolean | undefined;
938
+ __autocapture: boolean | AutocaptureConfig | undefined;
912
939
  decideEndpointWasHit: boolean;
913
940
  SentryIntegration: typeof SentryIntegration;
914
941
  segmentIntegration: () => any;
@@ -1167,8 +1194,8 @@ declare class PostHog {
1167
1194
  * // Automatically capture clicks, form submissions and change events
1168
1195
  * autocapture: true
1169
1196
  *
1170
- * // Capture rage clicks (beta) - useful for session recording
1171
- * rageclick: false
1197
+ * // Capture rage clicks
1198
+ * rageclick: true
1172
1199
  *
1173
1200
  * // transport for sending requests ('XHR' or 'sendBeacon')
1174
1201
  * // NB: sendBeacon should only be used for scenarios such as
@@ -1444,4 +1471,4 @@ declare class PostHog {
1444
1471
 
1445
1472
  declare const posthog: PostHog;
1446
1473
 
1447
- export { AutoCaptureCustomProperty, Breaker, CaptureCallback, CaptureOptions, CaptureResult, Compression, CompressionData, DecideResponse, EventHandler, FeatureFlagsCallback, GDPROptions, JSC, OptInOutCapturingOptions, PersistentStore, PostData, PostHog, PostHogConfig, Properties, Property, QueuedRequestData, RequestCallback, RetryQueueElement, SessionRecordingOptions, SnippetArrayItem, ToolbarParams, ToolbarSource, ToolbarUserIntent, ToolbarVersion, XHROptions, XHRParams, posthog as default, isFeatureEnabledOptions, posthog };
1474
+ export { AutoCaptureCustomProperty, AutocaptureCompatibleElement, AutocaptureConfig, Breaker, CaptureCallback, CaptureOptions, CaptureResult, Compression, CompressionData, DecideResponse, DomAutocaptureEvents, EventHandler, FeatureFlagsCallback, GDPROptions, JSC, OptInOutCapturingOptions, PersistentStore, PostData, PostHog, PostHogConfig, Properties, Property, QueuedRequestData, RequestCallback, RetryQueueElement, SessionRecordingOptions, SnippetArrayItem, ToolbarParams, ToolbarSource, ToolbarUserIntent, ToolbarVersion, XHROptions, XHRParams, posthog as default, isFeatureEnabledOptions, posthog };
package/dist/module.js CHANGED
@@ -921,7 +921,7 @@ var LZString = {
921
921
  }
922
922
  };
923
923
 
924
- var version = "1.36.1";
924
+ var version = "1.37.0";
925
925
 
926
926
  // e.g. Config.DEBUG = Config.DEBUG || instance.get_config('debug')
927
927
 
@@ -1868,20 +1868,64 @@ function isTextNode(el) {
1868
1868
  function isDocumentFragment(el) {
1869
1869
  return !!el && el.nodeType === 11; // Node.DOCUMENT_FRAGMENT_NODE - use integer constant for browser portability
1870
1870
  }
1871
- var usefulElements = ['a', 'button', 'form', 'input', 'select', 'textarea', 'label'];
1871
+ var autocaptureCompatibleElements = ['a', 'button', 'form', 'input', 'select', 'textarea', 'label'];
1872
1872
  /*
1873
1873
  * Check whether a DOM event should be "captured" or if it may contain sentitive data
1874
1874
  * using a variety of heuristics.
1875
1875
  * @param {Element} el - element to check
1876
1876
  * @param {Event} event - event to check
1877
+ * @param {Object} autocaptureConfig - autocapture config
1877
1878
  * @returns {boolean} whether the event should be captured
1878
1879
  */
1879
1880
 
1880
1881
  function shouldCaptureDomEvent(el, event) {
1882
+ var autocaptureConfig = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : undefined;
1883
+
1881
1884
  if (!el || isTag(el, 'html') || !isElementNode(el)) {
1882
1885
  return false;
1883
1886
  }
1884
1887
 
1888
+ if (autocaptureConfig !== null && autocaptureConfig !== void 0 && autocaptureConfig.url_allowlist) {
1889
+ var url = window.location.href;
1890
+ var allowlist = autocaptureConfig.url_allowlist;
1891
+
1892
+ if (allowlist && !allowlist.some(function (regex) {
1893
+ return url.match(regex);
1894
+ })) {
1895
+ return false;
1896
+ }
1897
+ }
1898
+
1899
+ if (autocaptureConfig !== null && autocaptureConfig !== void 0 && autocaptureConfig.dom_event_allowlist) {
1900
+ var _allowlist = autocaptureConfig.dom_event_allowlist;
1901
+
1902
+ if (_allowlist && !_allowlist.some(function (eventType) {
1903
+ return event.type === eventType;
1904
+ })) {
1905
+ return false;
1906
+ }
1907
+ }
1908
+
1909
+ if (autocaptureConfig !== null && autocaptureConfig !== void 0 && autocaptureConfig.element_allowlist) {
1910
+ var _allowlist2 = autocaptureConfig.element_allowlist;
1911
+
1912
+ if (_allowlist2 && !_allowlist2.some(function (elementType) {
1913
+ return el.tagName.toLowerCase() === elementType;
1914
+ })) {
1915
+ return false;
1916
+ }
1917
+ }
1918
+
1919
+ if (autocaptureConfig !== null && autocaptureConfig !== void 0 && autocaptureConfig.css_selector_allowlist) {
1920
+ var _allowlist3 = autocaptureConfig.css_selector_allowlist;
1921
+
1922
+ if (_allowlist3 && !_allowlist3.some(function (selector) {
1923
+ return el.matches(selector);
1924
+ })) {
1925
+ return false;
1926
+ }
1927
+ }
1928
+
1885
1929
  var parentIsUsefulElement = false;
1886
1930
  var targetElementList = [el]; // TODO: remove this var, it's never queried
1887
1931
 
@@ -1899,7 +1943,7 @@ function shouldCaptureDomEvent(el, event) {
1899
1943
  parentNode = curEl.parentNode || false;
1900
1944
  if (!parentNode) break;
1901
1945
 
1902
- if (usefulElements.indexOf(parentNode.tagName.toLowerCase()) > -1) {
1946
+ if (autocaptureCompatibleElements.indexOf(parentNode.tagName.toLowerCase()) > -1) {
1903
1947
  parentIsUsefulElement = true;
1904
1948
  } else {
1905
1949
  var _compStyles = window.getComputedStyle(parentNode);
@@ -1937,7 +1981,7 @@ function shouldCaptureDomEvent(el, event) {
1937
1981
 
1938
1982
  default:
1939
1983
  if (parentIsUsefulElement) return event.type === 'click';
1940
- return event.type === 'click' && (usefulElements.indexOf(tag) > -1 || el.getAttribute('contenteditable') === 'true');
1984
+ return event.type === 'click' && (autocaptureCompatibleElements.indexOf(tag) > -1 || el.getAttribute('contenteditable') === 'true');
1941
1985
  }
1942
1986
  }
1943
1987
  /*
@@ -2141,7 +2185,7 @@ var autocapture = {
2141
2185
  tag_name: tag_name
2142
2186
  };
2143
2187
 
2144
- if (usefulElements.indexOf(tag_name) > -1 && !maskText) {
2188
+ if (autocaptureCompatibleElements.indexOf(tag_name) > -1 && !maskText) {
2145
2189
  props['$el_text'] = getSafeText(elem);
2146
2190
  }
2147
2191
 
@@ -2252,7 +2296,7 @@ var autocapture = {
2252
2296
  (_this$rageclicks = this.rageclicks) === null || _this$rageclicks === void 0 ? void 0 : _this$rageclicks.click(e.clientX, e.clientY, new Date().getTime());
2253
2297
  }
2254
2298
 
2255
- if (target && shouldCaptureDomEvent(target, e)) {
2299
+ if (target && shouldCaptureDomEvent(target, e, this.config)) {
2256
2300
  var targetElementList = [target];
2257
2301
  var curEl = target;
2258
2302
 
@@ -2332,7 +2376,21 @@ var autocapture = {
2332
2376
  },
2333
2377
  _customProperties: [],
2334
2378
  rageclicks: null,
2379
+ config: undefined,
2335
2380
  init: function init(instance) {
2381
+ var _this$config;
2382
+
2383
+ if (typeof instance.__autocapture !== 'boolean') {
2384
+ this.config = instance.__autocapture;
2385
+ } // precompile the regex
2386
+
2387
+
2388
+ if ((_this$config = this.config) !== null && _this$config !== void 0 && _this$config.url_allowlist) {
2389
+ this.config.url_allowlist = this.config.url_allowlist.map(function (url) {
2390
+ return new RegExp(url);
2391
+ });
2392
+ }
2393
+
2336
2394
  this.rageclicks = new RageClick(instance);
2337
2395
  },
2338
2396
  afterDecideResponse: function afterDecideResponse(response, instance) {
@@ -2353,7 +2411,7 @@ var autocapture = {
2353
2411
 
2354
2412
  this._addDomEventHandlers(instance);
2355
2413
  } else {
2356
- instance['__autocapture_enabled'] = false;
2414
+ instance['__autocapture'] = false;
2357
2415
  }
2358
2416
  },
2359
2417
  // this is a mechanism to ramp up CE with no server-side interaction.
@@ -5301,6 +5359,10 @@ function strToU8(str, latin1) {
5301
5359
  return slc(ar, 0, ai);
5302
5360
  }
5303
5361
 
5362
+ /**
5363
+ * If an array is passed for an allowlist, autocapture events will only be sent for elements matching
5364
+ * at least one of the elements in the array. Multiple allowlists can be used
5365
+ */
5304
5366
  exports.Compression = void 0;
5305
5367
 
5306
5368
  (function (Compression) {
@@ -6124,7 +6186,7 @@ var defaultConfig = function defaultConfig() {
6124
6186
  ui_host: null,
6125
6187
  token: '',
6126
6188
  autocapture: true,
6127
- rageclick: false,
6189
+ rageclick: true,
6128
6190
  cross_subdomain_cookie: (document$1 === null || document$1 === void 0 ? void 0 : (_document$location = document$1.location) === null || _document$location === void 0 ? void 0 : (_document$location$ho = _document$location.hostname) === null || _document$location$ho === void 0 ? void 0 : _document$location$ho.indexOf('herokuapp.com')) === -1,
6129
6191
  persistence: 'cookie',
6130
6192
  persistence_name: '',
@@ -6227,17 +6289,18 @@ var create_mplib = function create_mplib(token, config, name) {
6227
6289
  instance.toolbar.maybeLoadToolbar();
6228
6290
  instance.sessionRecording = new SessionRecording(instance);
6229
6291
  instance.sessionRecording.startRecordingIfEnabled();
6230
- instance.__autocapture_enabled = instance.get_config('autocapture');
6292
+ instance.__autocapture = instance.get_config('autocapture');
6231
6293
 
6232
6294
  if (instance.get_config('autocapture')) {
6295
+ instance.__autocapture = instance.get_config('autocapture');
6233
6296
  var num_buckets = 100;
6234
6297
  var num_enabled_buckets = 100;
6235
6298
 
6236
6299
  if (!autocapture.enabledForProject(instance.get_config('token'), num_buckets, num_enabled_buckets)) {
6237
- instance.__autocapture_enabled = false;
6300
+ instance.__autocapture = false;
6238
6301
  logger.log('Not in active bucket: disabling Automatic Event Collection.');
6239
6302
  } else if (!autocapture.isBrowserSupported()) {
6240
- instance.__autocapture_enabled = false;
6303
+ instance.__autocapture = false;
6241
6304
  logger.log('Disabling Automatic Event Collection because this browser is not supported');
6242
6305
  } else {
6243
6306
  autocapture.init(instance);
@@ -6283,7 +6346,7 @@ var PostHog = /*#__PURE__*/function () {
6283
6346
  this.__captureHooks = [];
6284
6347
  this.__request_queue = [];
6285
6348
  this.__loaded = false;
6286
- this.__autocapture_enabled = undefined;
6349
+ this.__autocapture = undefined;
6287
6350
 
6288
6351
  this._jsc = function () {};
6289
6352
 
@@ -7289,8 +7352,8 @@ var PostHog = /*#__PURE__*/function () {
7289
7352
  * // Automatically capture clicks, form submissions and change events
7290
7353
  * autocapture: true
7291
7354
  *
7292
- * // Capture rage clicks (beta) - useful for session recording
7293
- * rageclick: false
7355
+ * // Capture rage clicks
7356
+ * rageclick: true
7294
7357
  *
7295
7358
  * // transport for sending requests ('XHR' or 'sendBeacon')
7296
7359
  * // NB: sendBeacon should only be used for scenarios such as