@v-tilt/browser 1.11.0 → 1.12.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.
Files changed (90) hide show
  1. package/dist/all-external-dependencies.js +1 -1
  2. package/dist/all-external-dependencies.js.map +1 -1
  3. package/dist/array.full.js +1 -1
  4. package/dist/array.full.js.map +1 -1
  5. package/dist/array.js +1 -1
  6. package/dist/array.js.map +1 -1
  7. package/dist/array.no-external.js +1 -1
  8. package/dist/array.no-external.js.map +1 -1
  9. package/dist/autocapture-types.d.ts +17 -0
  10. package/dist/autocapture-utils.d.ts +24 -1
  11. package/dist/autocapture.d.ts +94 -5
  12. package/dist/chat.js +1 -1
  13. package/dist/chat.js.map +1 -1
  14. package/dist/config.d.ts +8 -1
  15. package/dist/constants.d.ts +19 -13
  16. package/dist/core/capture.d.ts +15 -5
  17. package/dist/core/config-utils.d.ts +15 -0
  18. package/dist/core/consent.d.ts +62 -0
  19. package/dist/core/event-buffer.d.ts +60 -0
  20. package/dist/core/fb-cookies.d.ts +32 -0
  21. package/dist/core/feature-manager.d.ts +61 -69
  22. package/dist/core/fifo-queue.d.ts +23 -0
  23. package/dist/core/identity.d.ts +23 -33
  24. package/dist/core/index.d.ts +7 -1
  25. package/dist/core/page-lifecycle.d.ts +41 -0
  26. package/dist/core/remote-config.d.ts +14 -17
  27. package/dist/extensions/chat/bubble-drag.d.ts +30 -0
  28. package/dist/extensions/chat/chat-api.d.ts +15 -0
  29. package/dist/extensions/chat/chat-styles.d.ts +27 -0
  30. package/dist/extensions/chat/chat-wrapper.d.ts +20 -145
  31. package/dist/extensions/chat/chat.d.ts +129 -12
  32. package/dist/extensions/chat/message-content-styles.d.ts +1 -0
  33. package/dist/extensions/chat/message-html.d.ts +6 -0
  34. package/dist/extensions/chat/message-markdown.d.ts +8 -0
  35. package/dist/extensions/chat/normalize-send-content.d.ts +24 -0
  36. package/dist/extensions/chat/types.d.ts +19 -57
  37. package/dist/extensions/chat/widget-registry.d.ts +53 -0
  38. package/dist/extensions/chat/widgets/collect-email.d.ts +6 -0
  39. package/dist/extensions/chat/widgets/escalate-to-human.d.ts +6 -0
  40. package/dist/extensions/ga4-proxy.d.ts +59 -0
  41. package/dist/extensions/google-tag-gateway/consent-bridge.d.ts +27 -0
  42. package/dist/extensions/google-tag-gateway/enhanced-conversions.d.ts +35 -0
  43. package/dist/extensions/google-tag-gateway/event-bridge.d.ts +74 -0
  44. package/dist/extensions/google-tag-gateway/google-tag-gateway.d.ts +95 -0
  45. package/dist/extensions/google-tag-gateway/gtag-loader.d.ts +85 -0
  46. package/dist/extensions/google-tag-gateway/index.d.ts +7 -0
  47. package/dist/extensions/google-tag-gateway/normalize.d.ts +28 -0
  48. package/dist/extensions/google-tag-gateway/public-api.d.ts +23 -0
  49. package/dist/extensions/history-autocapture.d.ts +2 -2
  50. package/dist/extensions/replay/index.d.ts +1 -1
  51. package/dist/extensions/replay/session-recording-utils.d.ts +13 -43
  52. package/dist/extensions/replay/session-recording-wrapper.d.ts +10 -66
  53. package/dist/extensions/replay/session-recording.d.ts +53 -1
  54. package/dist/extensions/replay/types.d.ts +6 -1
  55. package/dist/extensions/web-vitals/web-vitals-manager.d.ts +14 -43
  56. package/dist/external-scripts-loader.js +1 -1
  57. package/dist/external-scripts-loader.js.map +1 -1
  58. package/dist/feature.d.ts +54 -172
  59. package/dist/main.js +1 -1
  60. package/dist/main.js.map +1 -1
  61. package/dist/module.d.ts +728 -753
  62. package/dist/module.js +1 -1
  63. package/dist/module.js.map +1 -1
  64. package/dist/module.no-external.d.ts +728 -753
  65. package/dist/module.no-external.js +1 -1
  66. package/dist/module.no-external.js.map +1 -1
  67. package/dist/rate-limiter.d.ts +0 -1
  68. package/dist/recorder.js +1 -1
  69. package/dist/recorder.js.map +1 -1
  70. package/dist/request.d.ts +34 -20
  71. package/dist/scroll-depth-tracker.d.ts +42 -0
  72. package/dist/server.d.ts +114 -0
  73. package/dist/server.js +1 -1
  74. package/dist/server.js.map +1 -1
  75. package/dist/session.d.ts +12 -0
  76. package/dist/types.d.ts +204 -9
  77. package/dist/user-manager.d.ts +26 -52
  78. package/dist/utils/base64.d.ts +30 -0
  79. package/dist/utils/bot-detection.d.ts +28 -0
  80. package/dist/utils/endpoint-url.d.ts +36 -0
  81. package/dist/utils/event-emitter.d.ts +1 -0
  82. package/dist/utils/globals.d.ts +71 -2
  83. package/dist/utils/index.d.ts +20 -5
  84. package/dist/utils/logger.d.ts +66 -0
  85. package/dist/utils/request-utils.d.ts +5 -0
  86. package/dist/utils/safewrap.d.ts +6 -1
  87. package/dist/utils/transport-health.d.ts +55 -0
  88. package/dist/vtilt.d.ts +85 -25
  89. package/dist/web-vitals.js.map +1 -1
  90. package/package.json +9 -4
package/dist/request.d.ts CHANGED
@@ -6,26 +6,38 @@
6
6
  * - Multiple transport methods (fetch, XHR, sendBeacon)
7
7
  * - Automatic fallback between transports
8
8
  *
9
- * Based on PostHog's request.ts pattern
9
+ * Compression transport split (important — see `utils/base64.ts`):
10
+ *
11
+ * - fetch / XHR → binary `Blob` of gzip bytes, body uses `compression=gzip-js`
12
+ * - sendBeacon → base64 *text* of the same gzip bytes, body uses
13
+ * `compression=base64`
14
+ *
15
+ * `sendBeacon` with a binary `Blob` is unreliable on `pagehide` / tab
16
+ * discard: the browser queues the beacon synchronously but serializes the
17
+ * body *after* JS is torn down, and the underlying `ArrayBuffer` can be
18
+ * detached/GC'd by then. The wire body lands empty or truncated while the
19
+ * URL we already committed still carries `compression=gzip-js`, and the
20
+ * server's `gunzipSync` throws `Z_BUF_ERROR`. Switching the beacon to a
21
+ * base64 string body means `Blob([string])` owns its own UTF-8 copy, which
22
+ * survives unload reliably.
23
+ *
24
+ * Based on PostHog's request.ts pattern.
10
25
  */
11
26
  /**
12
- * Compression methods supported by the SDK
27
+ * Compression methods supported by the SDK. The user-facing config only
28
+ * accepts `GZipJS` / `None`; the request layer internally picks `Base64`
29
+ * for the sendBeacon transport (see file header).
13
30
  */
14
31
  export declare enum Compression {
15
32
  GZipJS = "gzip-js",
33
+ Base64 = "base64",
16
34
  None = "none"
17
35
  }
18
- /**
19
- * Response from a request
20
- */
21
36
  export interface RequestResponse {
22
37
  statusCode: number;
23
38
  text?: string;
24
39
  json?: any;
25
40
  }
26
- /**
27
- * Options for making a request
28
- */
29
41
  export interface RequestOptions {
30
42
  url: string;
31
43
  data?: any;
@@ -35,20 +47,22 @@ export interface RequestOptions {
35
47
  compression?: Compression;
36
48
  timeout?: number;
37
49
  callback?: (response: RequestResponse) => void;
50
+ /**
51
+ * Project API token. When set, the helper authenticates the request:
52
+ *
53
+ * - `fetch` / `XHR` transports → sent as an `x-api-key` header so the
54
+ * URL stays clean and is less likely to match ad/privacy blocker
55
+ * filter rules that look for `?token=` on known analytics origins.
56
+ * - `sendBeacon` transport → appended as `?token=<token>` because
57
+ * beacon requests cannot carry custom headers.
58
+ *
59
+ * The server accepts both (`x-api-key` is checked before the query
60
+ * parameter), so older SDK versions that still embed the token in the
61
+ * URL continue to work unchanged.
62
+ */
63
+ projectToken?: string;
38
64
  }
39
- /**
40
- * JSON stringify with BigInt support
41
- */
42
65
  export declare const jsonStringify: (data: any) => string;
43
- /**
44
- * Main request function - handles transport selection and dispatching
45
- */
46
66
  export declare const request: (options: RequestOptions) => void;
47
- /**
48
- * Promise-based request wrapper
49
- */
50
67
  export declare const requestAsync: (options: Omit<RequestOptions, "callback">) => Promise<RequestResponse>;
51
- /**
52
- * Check if compression is supported and beneficial
53
- */
54
68
  export declare const shouldCompress: (data: any) => boolean;
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Scroll depth tracking for autocapture milestone and pageleave modes.
3
+ */
4
+ import type { AutocaptureConfig, ScrollDepthConfig } from "./autocapture-types";
5
+ export declare const DEFAULT_SCROLL_DEPTH_THRESHOLDS: readonly [25, 50, 75, 100];
6
+ export type ScrollRoot = Window | Element;
7
+ export interface NormalizedScrollDepth {
8
+ milestones: boolean;
9
+ thresholds: number[];
10
+ pageleave: boolean;
11
+ scroll_root_selector?: string | string[];
12
+ }
13
+ export declare function normalizeScrollDepth(raw: ScrollDepthConfig | undefined): NormalizedScrollDepth | null;
14
+ export declare function scrollDepthModeActive(config: AutocaptureConfig | undefined): boolean;
15
+ export declare function computeScrollDepthPct(root: ScrollRoot | null): number;
16
+ export declare function resolveScrollRoot(selectors: string | string[] | undefined): ScrollRoot | null;
17
+ export type ScrollDepthCaptureFn = (name: string, props: Record<string, unknown>) => void;
18
+ export interface ScrollDepthTrackerOptions {
19
+ milestones: boolean;
20
+ pageleave: boolean;
21
+ thresholds: number[];
22
+ scroll_root_selector?: string | string[];
23
+ capture: ScrollDepthCaptureFn;
24
+ isUrlAllowed: () => boolean;
25
+ onPageview: (cb: () => void) => () => void;
26
+ }
27
+ export declare class ScrollDepthTracker {
28
+ private readonly _options;
29
+ private _maxPctSeen;
30
+ private readonly _firedThresholds;
31
+ private _scrollHandler;
32
+ private _scrollTarget;
33
+ private _rafId;
34
+ private _pageviewUnsub;
35
+ constructor(_options: ScrollDepthTrackerOptions);
36
+ start(): void;
37
+ stop(): void;
38
+ reset(): void;
39
+ getMaxPct(): number;
40
+ private _scheduleScrollUpdate;
41
+ private _onScroll;
42
+ }
package/dist/server.d.ts CHANGED
@@ -8,6 +8,102 @@
8
8
  interface FeatureFlagsConfig {
9
9
  [flagKey: string]: boolean | string;
10
10
  }
11
+ type GoogleConsentValue = "follow_advertising" | "follow_analytics" | "granted" | "denied";
12
+ interface GoogleConsentOverride {
13
+ ad_storage?: GoogleConsentValue;
14
+ ad_user_data?: GoogleConsentValue;
15
+ ad_personalization?: GoogleConsentValue;
16
+ analytics_storage?: GoogleConsentValue;
17
+ }
18
+ interface GoogleAdsConversionMapping {
19
+ event_name: string;
20
+ send_to: string;
21
+ value_param_path?: string;
22
+ currency_param_path?: string;
23
+ default_currency?: string;
24
+ send_transaction_id?: boolean;
25
+ transaction_id_param_path?: string;
26
+ }
27
+ /**
28
+ * How gtag.js is loaded — mirrors the server-side `proxy_mode` destination
29
+ * setting:
30
+ *
31
+ * - `proxied` (default) — route through `api_host/gt/*`. `api_host` is the
32
+ * SDK-level proxy setting; self-hosted customers point it at their own
33
+ * domain (which must implement the `/gt/*` spec).
34
+ * - `direct` — no proxy; gtag.js loads straight from
35
+ * `https://www.googletagmanager.com/gtag/js`.
36
+ */
37
+ type GoogleTagProxyMode = "proxied" | "direct";
38
+ /**
39
+ * Configuration for the Google Tag Gateway SDK feature. Ships under the
40
+ * `googleTag` key of /decide when at least one `ga4_gtag` or `google_ads_gtag` destination is
41
+ * enabled for the project.
42
+ */
43
+ interface GoogleTagClientConfig {
44
+ destinationId: string;
45
+ /**
46
+ * Proxy mode. When absent the SDK falls back to `proxied` so older
47
+ * `/decide` responses and the zero-config default remain compatible.
48
+ */
49
+ proxyMode?: GoogleTagProxyMode;
50
+ tagIds: string[];
51
+ conversions: GoogleAdsConversionMapping[];
52
+ enhancedConversions: boolean;
53
+ conversionLinker: boolean;
54
+ linkerDomains: string[];
55
+ capturePageview: boolean;
56
+ debugMode: boolean;
57
+ consentOverride?: GoogleConsentOverride;
58
+ /**
59
+ * Master switch for forwarding every `vt.capture()` event to GA4 via
60
+ * `gtag('event', name, params)`. Defaults to `true` when absent. When
61
+ * `false`, only events that match an explicit row in `eventMappings` — or
62
+ * an Ads `conversions` mapping — fire; everything else is left to the
63
+ * Google tag's own behavior (page_view, enhanced measurement, etc.).
64
+ */
65
+ autoForward?: boolean;
66
+ /**
67
+ * Whether to fire the direct Ads conversion beacon
68
+ * (`gtag('event', 'conversion', {send_to: 'AW-.../...'})`) for rows in
69
+ * `conversions`. Defaults to `true` when absent. Turn off when GA4 is
70
+ * linked to Google Ads in the Ads account — in that mode the GA4 event
71
+ * (marked as a conversion in GA4) propagates to Ads automatically and
72
+ * the direct beacon would duplicate it. Has no effect when `conversions`
73
+ * is empty.
74
+ */
75
+ sendAdsConversions?: boolean;
76
+ /**
77
+ * Admin-configured event renames and param remappings. Mirrors the
78
+ * generic `event_mappings` configured on the destination. Applied after
79
+ * the filter check and before firing `gtag('event', ...)`.
80
+ */
81
+ eventMappings?: GoogleTagEventMapping[];
82
+ /**
83
+ * Admin-configured include/exclude lists. Mirrors the generic
84
+ * `event_filter` on the destination. Evaluated before any mapping.
85
+ */
86
+ eventFilter?: {
87
+ include?: string[];
88
+ exclude?: string[];
89
+ };
90
+ }
91
+ /**
92
+ * Rename an event and optionally remap payload paths to gtag param paths.
93
+ * Structurally identical to the server-side `EventMapping` type but lives
94
+ * in the browser package to avoid cross-package imports. Source paths use
95
+ * dotted notation into the captured payload (e.g. `order.total`); dest
96
+ * paths use dotted notation into the outgoing gtag `params` object.
97
+ */
98
+ interface GoogleTagEventMapping {
99
+ source: string;
100
+ destination: string;
101
+ param_mappings?: GoogleTagParamMapping[];
102
+ }
103
+ interface GoogleTagParamMapping {
104
+ source: string;
105
+ destination: string;
106
+ }
11
107
  interface RemoteConfig {
12
108
  sessionRecording?: {
13
109
  enabled?: boolean;
@@ -28,6 +124,8 @@ interface RemoteConfig {
28
124
  enabled?: boolean;
29
125
  widgetPosition?: "bottom-right" | "bottom-left";
30
126
  widgetColor?: string;
127
+ bubbleDraggable?: boolean;
128
+ bubbleVisible?: boolean;
31
129
  };
32
130
  chatTracking?: {
33
131
  trackUserMessages?: boolean;
@@ -38,17 +136,33 @@ interface RemoteConfig {
38
136
  capturePageleave?: boolean;
39
137
  capturePerformance?: boolean;
40
138
  autocapture?: boolean;
139
+ scrollDepthMilestones?: boolean;
140
+ scrollDepthPageleave?: boolean;
41
141
  };
42
142
  privacy?: {
43
143
  respectDnt?: boolean;
44
144
  requireConsent?: boolean;
45
145
  ipAnonymization?: boolean;
46
146
  };
147
+ /**
148
+ * Diagnostics — runtime-tunable console verbosity. Applied by the SDK only
149
+ * when the integrator did NOT pass `log_level` / `debug` to `vt.init()`.
150
+ * Set from the dashboard's Default Configuration → Diagnostics tab.
151
+ */
152
+ diagnostics?: {
153
+ defaultLogLevel?: "none" | "error" | "warn" | "info" | "debug";
154
+ };
47
155
  featureFlags?: FeatureFlagsConfig;
48
156
  /** Whether to send elements as chain string (PostHog compatibility) */
49
157
  elementsChainAsString?: boolean;
50
158
  /** Server-side autocapture opt-out */
51
159
  autocapture_opt_out?: boolean;
160
+ /**
161
+ * Google Tag Gateway config (absent when no client Google gtag destination is
162
+ * enabled for the project). Drives the gtag.js proxy loader, Consent Mode
163
+ * v2 bridge, and event → conversion mappings.
164
+ */
165
+ googleTag?: GoogleTagClientConfig;
52
166
  }
53
167
 
54
168
  /**
package/dist/server.js CHANGED
@@ -1,2 +1,2 @@
1
- function t(t,e,o,n,i,r,c){try{var l=t[r](c),u=l.value}catch(t){return void o(t)}l.done?e(u):Promise.resolve(u).then(n,i)}function e(t){return o.apply(this,arguments)}function o(){var e;return e=function*(t){var{apiHost:e,token:o,timeout:n=3e3}=t;if(!e||!o)return console.warn("[vTilt] Missing apiHost or token for fetchRemoteConfig"),null;var i=e+"/api/decide?token="+o;try{var r=new AbortController,c=setTimeout(()=>r.abort(),n),l=yield fetch(i,{method:"GET",headers:{Accept:"application/json"},signal:r.signal,next:{revalidate:60}});return clearTimeout(c),l.ok?yield l.json():(console.warn("[vTilt] Failed to fetch remote config: "+l.status),null)}catch(t){return"AbortError"===t.name?console.warn("[vTilt] Remote config fetch timed out"):console.warn("[vTilt] Failed to fetch remote config:",t),null}},o=function(){var o=this,n=arguments;return new Promise(function(i,r){var c=e.apply(o,n);function l(e){t(c,i,r,l,u,"next",e)}function u(e){t(c,i,r,l,u,"throw",e)}l(void 0)})},o.apply(this,arguments)}function n(t){return t?"window.__VTILT_BOOTSTRAP__="+JSON.stringify({remoteConfig:t})+";":""}export{e as fetchRemoteConfig,n as generateBootstrapScript};
1
+ function e(e,r,n,o,t,i,f){try{var a=e[i](f),u=a.value}catch(e){return void n(e)}a.done?r(u):Promise.resolve(u).then(o,t)}var r={none:0,error:1,warn:2,info:3,debug:4},n="[vTilt]",o=new Set(["none","error","warn","info","debug"]);function t(){return"undefined"!=typeof console}function i(e){var r=e.length>0&&"string"==typeof e[0]?e[0]:"",o=r?e.slice(1):e;return[r?n+":"+r:n,...o]}var f="warn",a=!1;var u=null;function c(){return u||(u={setLevel(e,r){void 0===r&&(r=!1),f=e,r&&(a=!0)},setLevelFromRemote(e){a||e&&o.has(e)&&(f=e)},getLevel:()=>f,isLockedByInit:()=>a,debug(){if(!(r[f]<r.debug)&&t()){for(var e=arguments.length,n=new Array(e),o=0;o<e;o++)n[o]=arguments[o];console.log(...i(n))}},info(){if(!(r[f]<r.info)&&t()){for(var e=arguments.length,n=new Array(e),o=0;o<e;o++)n[o]=arguments[o];console.log(...i(n))}},warn(){if(!(r[f]<r.warn)&&t()){for(var e=arguments.length,n=new Array(e),o=0;o<e;o++)n[o]=arguments[o];console.warn(...i(n))}},error(){if(!(r[f]<r.error)&&t()){for(var e=arguments.length,n=new Array(e),o=0;o<e;o++)n[o]=arguments[o];console.error(...i(n))}}}),u}function l(e){return v.apply(this,arguments)}function v(){var r;return r=function*(e){var{apiHost:r,token:n,timeout:o=3e3}=e;if(!r||!n)return c().warn("server","missing apiHost or token for fetchRemoteConfig"),null;var t=r.replace(/\/+$/gm,"")+"/api/d";try{var i=new AbortController,f=setTimeout(()=>i.abort(),o),a=yield fetch(t,{method:"GET",headers:{Accept:"application/json","x-api-key":n},signal:i.signal,next:{revalidate:60}});return clearTimeout(f),a.ok?yield a.json():(c().warn("server","failed to fetch remote config: "+a.status),null)}catch(e){return"AbortError"===e.name?c().warn("server","remote config fetch timed out"):c().warn("server","failed to fetch remote config:",e),null}},v=function(){var n=this,o=arguments;return new Promise(function(t,i){var f=r.apply(n,o);function a(r){e(f,t,i,a,u,"next",r)}function u(r){e(f,t,i,a,u,"throw",r)}a(void 0)})},v.apply(this,arguments)}function s(e){return e?"window.__VTILT_BOOTSTRAP__="+JSON.stringify({remoteConfig:e})+";":""}export{l as fetchRemoteConfig,s as generateBootstrapScript};
2
2
  //# sourceMappingURL=server.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"server.js","sources":["../src/server.ts"],"sourcesContent":[null],"names":["fetchRemoteConfig","_x","_fetchRemoteConfig","apply","this","arguments","options","apiHost","token","timeout","console","warn","url","controller","AbortController","timeoutId","setTimeout","abort","response","fetch","method","headers","Accept","signal","next","revalidate","clearTimeout","ok","json","status","error","name","generateBootstrapScript","remoteConfig","JSON","stringify"],"mappings":"yHA8CA,SAAsBA,EAAiBC,GAAA,OAAAC,EAAAC,MAAAC,KAAAC,UAAA,CA0CvC,SAAAH,UAFC,SAxCM,UACLI,GAEA,IAAMC,QAAEA,EAAOC,MAAEA,EAAKC,QAAEA,EAAU,KAASH,EAE3C,IAAKC,IAAYC,EAEf,OADAE,QAAQC,KAAK,0DACN,KAGT,IAAMC,EAASL,EAAO,qBAAqBC,EAE3C,IACE,IAAMK,EAAa,IAAIC,gBACjBC,EAAYC,WAAW,IAAMH,EAAWI,QAASR,GAEjDS,QAAiBC,MAAMP,EAAK,CAChCQ,OAAQ,MACRC,QAAS,CAAEC,OAAQ,oBACnBC,OAAQV,EAAWU,OAEnBC,KAAM,CAAEC,WAAY,MAKtB,OAFAC,aAAaX,GAERG,EAASS,SAKAT,EAASU,QAJrBlB,QAAQC,KAAI,0CAA2CO,EAASW,QACzD,KAIX,CAAE,MAAOC,GAMP,MAL8B,eAAzBA,EAAgBC,KACnBrB,QAAQC,KAAK,yCAEbD,QAAQC,KAAK,yCAA0CmB,GAElD,IACT,CACF,EAEA5B,8KAFCA,EAAAC,MAAAC,KAAAC,UAAA,CAgBK,SAAU2B,EACdC,GAEA,OAAKA,EAIL,8BAAqCC,KAAKC,UAAU,CAAEF,iBAAe,IAH5D,EAIX"}
1
+ {"version":3,"file":"server.js","sources":["../src/utils/logger.ts","../src/server.ts"],"sourcesContent":[null,null],"names":["LEVEL_PRIORITY","none","error","warn","info","debug","PREFIX","VALID_LEVELS","Set","hasConsole","console","formatArgs","args","scope","length","rest","slice","currentLevel","lockedByInit","singleton","getLogger","setLevel","level","lockFromInit","setLevelFromRemote","has","getLevel","isLockedByInit","_len","arguments","Array","_key","log","_len2","_key2","_len3","_key3","_len4","_key4","fetchRemoteConfig","_x","_fetchRemoteConfig","apply","this","options","apiHost","token","timeout","url","replace","controller","AbortController","timeoutId","setTimeout","abort","response","fetch","method","headers","Accept","signal","next","revalidate","clearTimeout","ok","json","status","name","generateBootstrapScript","remoteConfig","JSON","stringify"],"mappings":"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"}
package/dist/session.d.ts CHANGED
@@ -10,7 +10,13 @@ import { PersistenceMethod } from "./types";
10
10
  export declare class SessionManager {
11
11
  private storage;
12
12
  private _windowId;
13
+ private _isNewSession;
13
14
  constructor(storageMethod?: PersistenceMethod, cross_subdomain?: boolean);
15
+ /**
16
+ * Hydrate window ID from sessionStorage.
17
+ * Called by VTilt._boot() once the browser environment is ready.
18
+ */
19
+ hydrateFromStorage(): void;
14
20
  /**
15
21
  * Get session ID (always returns a value, generates if needed)
16
22
  */
@@ -24,6 +30,12 @@ export declare class SessionManager {
24
30
  * Reset session ID (generates new session on reset)
25
31
  */
26
32
  resetSessionId(): void;
33
+ /**
34
+ * Returns true if the current session was just started (new session ID generated
35
+ * because the session cookie expired or didn't exist). Resets after first call.
36
+ * Matches GA4's _ss=1 semantics.
37
+ */
38
+ consumeSessionStart(): boolean;
27
39
  /**
28
40
  * Get session ID from storage (raw, can return null)
29
41
  * Cookie Max-Age handles expiration automatically
package/dist/types.d.ts CHANGED
@@ -5,10 +5,15 @@
5
5
  * Following PostHog's patterns where applicable.
6
6
  */
7
7
  import type { PersonProfilesMode } from "./constants";
8
+ import type { BubbleConfig } from "./utils/globals";
8
9
  export interface VTiltConfig {
9
10
  /** Project identifier (required) */
10
11
  token: string;
11
- /** API host for tracking (default: https://api.vtilt.io) */
12
+ /**
13
+ * API host for all SDK requests (events, config, recordings, chat).
14
+ * Set this to your own domain when using a reverse proxy.
15
+ * If not set, SDK uses relative URLs (same-origin).
16
+ */
12
17
  api_host?: string;
13
18
  /** UI host for dashboard links */
14
19
  ui_host?: string | null;
@@ -18,10 +23,6 @@ export interface VTiltConfig {
18
23
  * If not set, falls back to {api_host}/dist/{script}.js
19
24
  */
20
25
  script_host?: string;
21
- /** Proxy domain for tracking requests */
22
- proxy?: string;
23
- /** Full proxy URL for tracking requests */
24
- proxyUrl?: string;
25
26
  /** Instance name (for multiple instances) */
26
27
  name?: string;
27
28
  /** Domain to track (auto-detected if not provided) - used in event properties */
@@ -75,8 +76,25 @@ export interface VTiltConfig {
75
76
  mask_all_element_attributes?: boolean;
76
77
  /** Respect Do Not Track browser setting */
77
78
  respect_dnt?: boolean;
79
+ /**
80
+ * When false (default), events are not sent when the browser looks like a bot
81
+ * (known crawler user agents, `navigator.webdriver`, or blocked CH brands).
82
+ * Set to true to disable bot filtering (PostHog: `opt_out_useragent_filter`).
83
+ */
84
+ opt_out_useragent_filter?: boolean;
85
+ /**
86
+ * Extra user-agent substrings to treat as bots (case-insensitive), merged with
87
+ * the built-in list aligned with PostHog (PostHog: `custom_blocked_useragents`).
88
+ */
89
+ custom_blocked_useragents?: string[];
78
90
  /** Opt users out by default */
79
91
  opt_out_capturing_by_default?: boolean;
92
+ /**
93
+ * When true, non-essential events are blocked until setConsent() is called.
94
+ * Essential events ($identify, $alias, $set) are always allowed.
95
+ * Use with vt.setConsent({ analytics: true, marketing: true, advertising: true }).
96
+ */
97
+ require_consent?: boolean;
80
98
  /** Session recording configuration */
81
99
  session_recording?: SessionRecordingOptions;
82
100
  /** Disable session recording (convenience flag) */
@@ -85,6 +103,46 @@ export interface VTiltConfig {
85
103
  chat?: ChatWidgetConfig;
86
104
  /** Disable chat (convenience flag) */
87
105
  disable_chat?: boolean;
106
+ /**
107
+ * Google Tag Gateway feature config (merged `ga4_gtag` + `google_ads_gtag`
108
+ * rows). Property name is the stable SDK config key; populated from `/decide`
109
+ * or set for SSR/tests.
110
+ */
111
+ google_tag?: GoogleTagClientConfig;
112
+ /** Disable the Google Tag Gateway feature (convenience flag) */
113
+ disable_google_tag?: boolean;
114
+ /**
115
+ * Console log level for SDK output prefixed with `[vTilt]`.
116
+ *
117
+ * Levels (each includes the levels above it):
118
+ * - 'none' — silence everything (escape hatch for shared kiosks etc.)
119
+ * - 'error' — SDK errors only
120
+ * - 'warn' — errors + warnings (default)
121
+ * - 'info' — + lifecycle events (init, autocapture started, replay started)
122
+ * - 'debug' — + per-event trace (every captured event, autocapture skips, requests)
123
+ *
124
+ * Default is 'warn' so SDK errors and warnings always surface without opt-in
125
+ * (matches Amplitude/PostHog/Sentry).
126
+ *
127
+ * NOT to be confused with the per-event `$debug` flag — that is a separate
128
+ * marker on the event payload itself, controlled by `debug: true` (below)
129
+ * or the `?vtilt_debug=1` URL parameter, and consumed by the Debug View in
130
+ * the dashboard. See the public docs for details.
131
+ *
132
+ * Setting `log_level` (or `debug: true`) at init time pins the level — it
133
+ * cannot be overridden by remote config / Default Configuration. Leave it
134
+ * unset to let project admins control verbosity from the dashboard.
135
+ */
136
+ log_level?: "none" | "error" | "warn" | "info" | "debug";
137
+ /**
138
+ * PostHog-style shorthand: when true, equivalent to `log_level: 'debug'`.
139
+ * Ignored if `log_level` is also set.
140
+ *
141
+ * Setting this to true ALSO marks every captured event with `$debug: true`
142
+ * so the dashboard's Debug View highlights it. The `?vtilt_debug=1` URL
143
+ * parameter sets the event flag without raising the console log level.
144
+ */
145
+ debug?: boolean;
88
146
  /** Global attributes added to all events */
89
147
  globalAttributes?: Record<string, string>;
90
148
  /** Bootstrap data for initialization (server-side rendering) */
@@ -99,6 +157,8 @@ export interface VTiltConfig {
99
157
  before_send?: (event: CaptureResult) => CaptureResult | null;
100
158
  /** Loaded callback */
101
159
  loaded?: (vtilt: any) => void;
160
+ /** @internal Set by RemoteConfigManager after a fresh /decide response (or fetch failure). */
161
+ __remote_config_loaded?: boolean;
102
162
  }
103
163
  export interface EventPayload {
104
164
  [key: string]: any;
@@ -167,9 +227,13 @@ export interface UserIdentity {
167
227
  export interface UserProperties {
168
228
  [key: string]: any;
169
229
  }
170
- export interface AliasEvent {
171
- distinct_id: string;
172
- original: string;
230
+ /** Batched identity state change — applied atomically with a single save. */
231
+ export interface IdentityUpdate {
232
+ distinct_id?: string;
233
+ user_state?: "anonymous" | "identified";
234
+ device_id?: string;
235
+ properties_set?: Properties;
236
+ properties_set_once?: Properties;
173
237
  }
174
238
  /** Supported Web Vitals metrics */
175
239
  export type SupportedWebVitalsMetric = "LCP" | "CLS" | "FCP" | "INP" | "TTFB";
@@ -307,6 +371,16 @@ export interface AutocaptureOptions {
307
371
  * @default false
308
372
  */
309
373
  capture_element_values?: boolean;
374
+ /**
375
+ * Scroll depth autocapture — two independently opt-in modes (both default off).
376
+ */
377
+ scroll_depth?: {
378
+ milestones?: boolean | {
379
+ thresholds?: number[];
380
+ };
381
+ pageleave?: boolean;
382
+ scroll_root_selector?: string | string[];
383
+ };
310
384
  }
311
385
  /** Mask options for input elements in session recording */
312
386
  export interface SessionRecordingMaskInputOptions {
@@ -353,6 +427,11 @@ export interface SessionRecordingOptions {
353
427
  blockClass?: string;
354
428
  /** Block selector for elements to hide */
355
429
  blockSelector?: string;
430
+ /**
431
+ * When `true`, skip built-in `blockSelector` entries for common invisible
432
+ * template nodes (screen-reader-only, Webflow CMS placeholders, etc.).
433
+ */
434
+ skipDefaultInvisibleBlocking?: boolean;
356
435
  /** Ignore class for input masking (default: 'vt-ignore-input') */
357
436
  ignoreClass?: string;
358
437
  /** Mask text class (default: 'vt-mask') */
@@ -373,7 +452,7 @@ export interface SessionRecordingOptions {
373
452
  recordHeaders?: boolean;
374
453
  /** Record body in network requests */
375
454
  recordBody?: boolean;
376
- /** Compress events before sending (default: true) */
455
+ /** Gzip-compress the request body before sending (default: true) */
377
456
  compressEvents?: boolean;
378
457
  /** Internal: Mutation throttler refill rate */
379
458
  __mutationThrottlerRefillRate?: number;
@@ -402,6 +481,104 @@ export interface ChatWidgetConfig {
402
481
  offlineMessage?: string;
403
482
  /** Collect email when offline */
404
483
  collectEmailOffline?: boolean;
484
+ /** Bubble appearance and behavior */
485
+ bubble?: BubbleConfig;
486
+ }
487
+ export type GoogleConsentValue = "follow_advertising" | "follow_analytics" | "granted" | "denied";
488
+ export interface GoogleConsentOverride {
489
+ ad_storage?: GoogleConsentValue;
490
+ ad_user_data?: GoogleConsentValue;
491
+ ad_personalization?: GoogleConsentValue;
492
+ analytics_storage?: GoogleConsentValue;
493
+ }
494
+ export interface GoogleAdsConversionMapping {
495
+ event_name: string;
496
+ send_to: string;
497
+ value_param_path?: string;
498
+ currency_param_path?: string;
499
+ default_currency?: string;
500
+ send_transaction_id?: boolean;
501
+ transaction_id_param_path?: string;
502
+ }
503
+ /**
504
+ * How gtag.js is loaded — mirrors the server-side `proxy_mode` destination
505
+ * setting:
506
+ *
507
+ * - `proxied` (default) — route through `api_host/gt/*`. `api_host` is the
508
+ * SDK-level proxy setting; self-hosted customers point it at their own
509
+ * domain (which must implement the `/gt/*` spec).
510
+ * - `direct` — no proxy; gtag.js loads straight from
511
+ * `https://www.googletagmanager.com/gtag/js`.
512
+ */
513
+ export type GoogleTagProxyMode = "proxied" | "direct";
514
+ /**
515
+ * Configuration for the Google Tag Gateway SDK feature. Ships under the
516
+ * `googleTag` key of /decide when at least one `ga4_gtag` or `google_ads_gtag` destination is
517
+ * enabled for the project.
518
+ */
519
+ export interface GoogleTagClientConfig {
520
+ destinationId: string;
521
+ /**
522
+ * Proxy mode. When absent the SDK falls back to `proxied` so older
523
+ * `/decide` responses and the zero-config default remain compatible.
524
+ */
525
+ proxyMode?: GoogleTagProxyMode;
526
+ tagIds: string[];
527
+ conversions: GoogleAdsConversionMapping[];
528
+ enhancedConversions: boolean;
529
+ conversionLinker: boolean;
530
+ linkerDomains: string[];
531
+ capturePageview: boolean;
532
+ debugMode: boolean;
533
+ consentOverride?: GoogleConsentOverride;
534
+ /**
535
+ * Master switch for forwarding every `vt.capture()` event to GA4 via
536
+ * `gtag('event', name, params)`. Defaults to `true` when absent. When
537
+ * `false`, only events that match an explicit row in `eventMappings` — or
538
+ * an Ads `conversions` mapping — fire; everything else is left to the
539
+ * Google tag's own behavior (page_view, enhanced measurement, etc.).
540
+ */
541
+ autoForward?: boolean;
542
+ /**
543
+ * Whether to fire the direct Ads conversion beacon
544
+ * (`gtag('event', 'conversion', {send_to: 'AW-.../...'})`) for rows in
545
+ * `conversions`. Defaults to `true` when absent. Turn off when GA4 is
546
+ * linked to Google Ads in the Ads account — in that mode the GA4 event
547
+ * (marked as a conversion in GA4) propagates to Ads automatically and
548
+ * the direct beacon would duplicate it. Has no effect when `conversions`
549
+ * is empty.
550
+ */
551
+ sendAdsConversions?: boolean;
552
+ /**
553
+ * Admin-configured event renames and param remappings. Mirrors the
554
+ * generic `event_mappings` configured on the destination. Applied after
555
+ * the filter check and before firing `gtag('event', ...)`.
556
+ */
557
+ eventMappings?: GoogleTagEventMapping[];
558
+ /**
559
+ * Admin-configured include/exclude lists. Mirrors the generic
560
+ * `event_filter` on the destination. Evaluated before any mapping.
561
+ */
562
+ eventFilter?: {
563
+ include?: string[];
564
+ exclude?: string[];
565
+ };
566
+ }
567
+ /**
568
+ * Rename an event and optionally remap payload paths to gtag param paths.
569
+ * Structurally identical to the server-side `EventMapping` type but lives
570
+ * in the browser package to avoid cross-package imports. Source paths use
571
+ * dotted notation into the captured payload (e.g. `order.total`); dest
572
+ * paths use dotted notation into the outgoing gtag `params` object.
573
+ */
574
+ export interface GoogleTagEventMapping {
575
+ source: string;
576
+ destination: string;
577
+ param_mappings?: GoogleTagParamMapping[];
578
+ }
579
+ export interface GoogleTagParamMapping {
580
+ source: string;
581
+ destination: string;
405
582
  }
406
583
  export interface RemoteConfig {
407
584
  sessionRecording?: {
@@ -423,6 +600,8 @@ export interface RemoteConfig {
423
600
  enabled?: boolean;
424
601
  widgetPosition?: "bottom-right" | "bottom-left";
425
602
  widgetColor?: string;
603
+ bubbleDraggable?: boolean;
604
+ bubbleVisible?: boolean;
426
605
  };
427
606
  chatTracking?: {
428
607
  trackUserMessages?: boolean;
@@ -433,15 +612,31 @@ export interface RemoteConfig {
433
612
  capturePageleave?: boolean;
434
613
  capturePerformance?: boolean;
435
614
  autocapture?: boolean;
615
+ scrollDepthMilestones?: boolean;
616
+ scrollDepthPageleave?: boolean;
436
617
  };
437
618
  privacy?: {
438
619
  respectDnt?: boolean;
439
620
  requireConsent?: boolean;
440
621
  ipAnonymization?: boolean;
441
622
  };
623
+ /**
624
+ * Diagnostics — runtime-tunable console verbosity. Applied by the SDK only
625
+ * when the integrator did NOT pass `log_level` / `debug` to `vt.init()`.
626
+ * Set from the dashboard's Default Configuration → Diagnostics tab.
627
+ */
628
+ diagnostics?: {
629
+ defaultLogLevel?: "none" | "error" | "warn" | "info" | "debug";
630
+ };
442
631
  featureFlags?: FeatureFlagsConfig;
443
632
  /** Whether to send elements as chain string (PostHog compatibility) */
444
633
  elementsChainAsString?: boolean;
445
634
  /** Server-side autocapture opt-out */
446
635
  autocapture_opt_out?: boolean;
636
+ /**
637
+ * Google Tag Gateway config (absent when no client Google gtag destination is
638
+ * enabled for the project). Drives the gtag.js proxy loader, Consent Mode
639
+ * v2 bridge, and event → conversion mappings.
640
+ */
641
+ googleTag?: GoogleTagClientConfig;
447
642
  }