@v-tilt/browser 1.12.0 → 1.13.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 (109) hide show
  1. package/dist/all-external-dependencies.js.map +1 -1
  2. package/dist/array.chat.js +2 -0
  3. package/dist/array.chat.js.map +1 -0
  4. package/dist/array.chat.no-external.js +2 -0
  5. package/dist/array.chat.no-external.js.map +1 -0
  6. package/dist/array.full.chat.js +2 -0
  7. package/dist/array.full.chat.js.map +1 -0
  8. package/dist/array.full.chat.no-external.js +2 -0
  9. package/dist/array.full.chat.no-external.js.map +1 -0
  10. package/dist/array.full.js +1 -1
  11. package/dist/array.full.js.map +1 -1
  12. package/dist/array.full.no-external.js +2 -0
  13. package/dist/array.full.no-external.js.map +1 -0
  14. package/dist/array.js +1 -1
  15. package/dist/array.js.map +1 -1
  16. package/dist/array.no-external.js +1 -1
  17. package/dist/array.no-external.js.map +1 -1
  18. package/dist/chat.js +1 -1
  19. package/dist/chat.js.map +1 -1
  20. package/dist/entrypoints/all-external-dependencies.d.ts +10 -3
  21. package/dist/entrypoints/array.chat.d.ts +10 -0
  22. package/dist/entrypoints/array.chat.no-external.d.ts +6 -0
  23. package/dist/entrypoints/array.full.chat.d.ts +13 -0
  24. package/dist/entrypoints/array.full.chat.no-external.d.ts +7 -0
  25. package/dist/entrypoints/array.full.d.ts +5 -9
  26. package/dist/entrypoints/array.full.no-external.d.ts +12 -0
  27. package/dist/entrypoints/module.chat.es.d.ts +7 -0
  28. package/dist/entrypoints/module.full.chat.es.d.ts +12 -0
  29. package/dist/entrypoints/module.full.es.d.ts +12 -0
  30. package/dist/entrypoints/module.no-external.es.d.ts +1 -0
  31. package/dist/extensions/chat/bubble-drag.d.ts +20 -5
  32. package/dist/extensions/chat/chat-wrapper.d.ts +8 -2
  33. package/dist/extensions/chat/chat.d.ts +21 -221
  34. package/dist/extensions/chat/controller/__tests__/fakes/ably-realtime-fake.d.ts +84 -0
  35. package/dist/extensions/chat/controller/ably-client.d.ts +160 -0
  36. package/dist/extensions/chat/controller/ably-handlers.d.ts +95 -0
  37. package/dist/extensions/chat/controller/ably-token.d.ts +67 -0
  38. package/dist/extensions/chat/controller/chat-controller.d.ts +194 -0
  39. package/dist/extensions/chat/controller/message-delivery-status.d.ts +6 -0
  40. package/dist/extensions/chat/controller/message-order.d.ts +12 -0
  41. package/dist/extensions/chat/controller/message-stream.d.ts +49 -0
  42. package/dist/extensions/chat/lib/bubble-offset.d.ts +18 -0
  43. package/dist/extensions/chat/lib/merge-chat-config.d.ts +3 -0
  44. package/dist/extensions/chat/normalize-send-content.d.ts +2 -0
  45. package/dist/extensions/chat/outbox/message-delivery.d.ts +17 -0
  46. package/dist/extensions/chat/outbox/message-outbox.d.ts +57 -0
  47. package/dist/extensions/chat/store/chat-store.d.ts +122 -0
  48. package/dist/extensions/chat/types.d.ts +1 -19
  49. package/dist/extensions/chat/ui/ChannelItem.d.ts +12 -0
  50. package/dist/extensions/chat/ui/ChannelListView.d.ts +14 -0
  51. package/dist/extensions/chat/ui/ChatBubble.d.ts +14 -0
  52. package/dist/extensions/chat/ui/ChatHeader.d.ts +13 -0
  53. package/dist/extensions/chat/ui/ChatPanel.d.ts +14 -0
  54. package/dist/extensions/chat/ui/ChatRoot.d.ts +31 -0
  55. package/dist/extensions/chat/ui/ClosedBanner.d.ts +7 -0
  56. package/dist/extensions/chat/ui/ConnectionBanner.d.ts +32 -0
  57. package/dist/extensions/chat/ui/ConversationView.d.ts +14 -0
  58. package/dist/extensions/chat/ui/MessageBubble.d.ts +25 -0
  59. package/dist/extensions/chat/ui/MessageInput.d.ts +14 -0
  60. package/dist/extensions/chat/ui/MessageList.d.ts +19 -0
  61. package/dist/extensions/chat/ui/NewMessagesPill.d.ts +13 -0
  62. package/dist/extensions/chat/ui/Skeletons.d.ts +14 -0
  63. package/dist/extensions/chat/ui/TypingBubble.d.ts +23 -0
  64. package/dist/extensions/chat/ui/TypingIndicator.d.ts +12 -0
  65. package/dist/extensions/chat/ui/WidgetSlot.d.ts +20 -0
  66. package/dist/extensions/chat/ui/hooks/use-auto-mark-read.d.ts +18 -0
  67. package/dist/extensions/chat/ui/hooks/use-scroll-preservation.d.ts +33 -0
  68. package/dist/extensions/chat/ui/icons.d.ts +18 -0
  69. package/dist/extensions/chat/ui/message-render.d.ts +18 -0
  70. package/dist/extensions/chat/ui/shadow-styles.d.ts +13 -0
  71. package/dist/extensions/chat/ui/utils/mobile-body-scroll-lock.d.ts +14 -0
  72. package/dist/extensions/chat/widget-registry.d.ts +21 -5
  73. package/dist/extensions/chat/widgets/collect-email.d.ts +4 -2
  74. package/dist/extensions/chat/widgets/escalate-to-human.d.ts +2 -1
  75. package/dist/external-scripts-loader.js +1 -1
  76. package/dist/external-scripts-loader.js.map +1 -1
  77. package/dist/feature.d.ts +1 -0
  78. package/dist/lib/merge-vtilt-config.d.ts +9 -0
  79. package/dist/main.js +1 -1
  80. package/dist/main.js.map +1 -1
  81. package/dist/module.chat.d.ts +1788 -0
  82. package/dist/module.chat.js +2 -0
  83. package/dist/module.chat.js.map +1 -0
  84. package/dist/module.d.ts +48 -3
  85. package/dist/module.full.chat.d.ts +1792 -0
  86. package/dist/module.full.chat.js +2 -0
  87. package/dist/module.full.chat.js.map +1 -0
  88. package/dist/module.full.d.ts +1793 -0
  89. package/dist/module.full.js +2 -0
  90. package/dist/module.full.js.map +1 -0
  91. package/dist/module.js +1 -1
  92. package/dist/module.js.map +1 -1
  93. package/dist/module.no-external.d.ts +48 -3
  94. package/dist/module.no-external.js +1 -1
  95. package/dist/module.no-external.js.map +1 -1
  96. package/dist/recorder.js.map +1 -1
  97. package/dist/snippet-stub-methods.d.ts +14 -0
  98. package/dist/utils/globals.d.ts +53 -27
  99. package/dist/utils/index.d.ts +8 -0
  100. package/dist/vtilt.d.ts +6 -1
  101. package/dist/web-vitals.js.map +1 -1
  102. package/package.json +4 -1
  103. package/dist/extensions/chat/chat-styles.d.ts +0 -27
  104. package/dist/extensions/chat/message-content-styles.d.ts +0 -1
  105. package/dist/extensions/chat/message-html.d.ts +0 -6
  106. package/dist/extensions/chat/message-markdown.d.ts +0 -8
  107. package/dist/extensions/ga4-proxy.d.ts +0 -59
  108. package/dist/utils/type-utils.d.ts +0 -4
  109. package/dist/web-vitals.d.ts +0 -81
@@ -0,0 +1,1793 @@
1
+ /**
2
+ * First argument to `vt.sendChatMessage()` / {@link LazyLoadedChatInterface.sendMessage}.
3
+ *
4
+ * Plain strings stay plain text for backward compatibility. Use `{ markdown: '...' }`,
5
+ * `{ html: '...' }`, or `options.format` for rich content.
6
+ */
7
+ type SendChatMessageContent = string | {
8
+ text: string;
9
+ } | {
10
+ markdown: string;
11
+ } | {
12
+ html: string;
13
+ };
14
+ /**
15
+ * Options for `vt.sendChatMessage()` / {@link LazyLoadedChatInterface.sendMessage}.
16
+ */
17
+ interface SendChatMessageOptions {
18
+ /**
19
+ * Target conversation: `'new'` creates a channel, a UUID selects an existing one,
20
+ * omit to use the active conversation (must already be in conversation view).
21
+ */
22
+ channel?: "new" | string;
23
+ /**
24
+ * Open the widget panel before sending. Default: true. Pass `open: false` to send without opening.
25
+ */
26
+ open?: boolean;
27
+ /**
28
+ * Applies when the first argument is a plain string. Default: `text`.
29
+ * `markdown` and `html` use the same sanitized rendering as AI/agent messages.
30
+ */
31
+ format?: "text" | "markdown" | "html";
32
+ /**
33
+ * Marks the message as automatically injected by your site (form submit, CTA,
34
+ * etc.) rather than typed by the visitor in the widget. Stored on the message
35
+ * as `message_source` metadata so the AI can respond appropriately — e.g.
36
+ * `source: "landing_form"`. Slug-like: letters, numbers, `_`, `-`, max 64 chars.
37
+ */
38
+ source?: string;
39
+ }
40
+ /**
41
+ * Pixel inset of the chat bubble from the viewport edges.
42
+ * Use to clear host floating buttons, cookie banners, or mobile tab bars.
43
+ */
44
+ interface BubbleOffset {
45
+ /** Distance from the bottom edge (default: 20) */
46
+ bottom?: number;
47
+ /** Distance from the right edge when `position` is `bottom-right` (default: 20) */
48
+ right?: number;
49
+ /** Distance from the left edge when `position` is `bottom-left` (default: 20) */
50
+ left?: number;
51
+ }
52
+ /**
53
+ * Chat bubble appearance and behavior configuration
54
+ */
55
+ interface BubbleConfig {
56
+ /** Allow user to drag the bubble to reposition (default: false) */
57
+ draggable?: boolean;
58
+ /** Show the bubble on load (default: true). Set to false to control via vt.chat.show() */
59
+ visible?: boolean;
60
+ /**
61
+ * Viewport inset in pixels. Prefer this over custom CSS so positioning
62
+ * survives widget UI updates. Pass `null` in `vt.updateConfig({ chat: { bubble: { offset: null } } })` to reset
63
+ * to SDK defaults (20px).
64
+ */
65
+ offset?: BubbleOffset | null;
66
+ }
67
+
68
+ /**
69
+ * Person profiles configuration mode
70
+ * - 'always': Always create person profiles (default)
71
+ * - 'identified_only': Only create profiles when user is identified
72
+ * - 'never': Never create person profiles (events only)
73
+ */
74
+ type PersonProfilesMode = "always" | "identified_only" | "never";
75
+
76
+ /**
77
+ * VTilt Types
78
+ *
79
+ * Type definitions for the VTilt tracking SDK.
80
+ * Following PostHog's patterns where applicable.
81
+ */
82
+
83
+ interface VTiltConfig {
84
+ /** Project identifier (required) */
85
+ token: string;
86
+ /**
87
+ * API host for all SDK requests (events, config, recordings, chat).
88
+ * Set this to your own domain when using a reverse proxy.
89
+ * If not set, SDK uses relative URLs (same-origin).
90
+ */
91
+ api_host?: string;
92
+ /** UI host for dashboard links */
93
+ ui_host?: string | null;
94
+ /**
95
+ * CDN host for loading extension scripts (recorder.js, etc.)
96
+ * If set, scripts load from {script_host}/{script}.js (no /dist/)
97
+ * If not set, falls back to {api_host}/dist/{script}.js
98
+ */
99
+ script_host?: string;
100
+ /** Instance name (for multiple instances) */
101
+ name?: string;
102
+ /** Domain to track (auto-detected if not provided) - used in event properties */
103
+ domain?: string;
104
+ /** Storage method for session data */
105
+ storage?: PersistenceMethod;
106
+ /** Persistence method for user data */
107
+ persistence?: PersistenceMethod;
108
+ /** Persistence name prefix */
109
+ persistence_name?: string;
110
+ /**
111
+ * Enable cross-subdomain cookies.
112
+ * When true, cookies are shared across subdomains (e.g., app.example.com and www.example.com).
113
+ * Auto-detects false for platforms like herokuapp.com, vercel.app, netlify.app.
114
+ * @default true (except for excluded platforms)
115
+ */
116
+ cross_subdomain_cookie?: boolean;
117
+ /**
118
+ * Person profiles mode:
119
+ * - 'always': Always create person profiles (default)
120
+ * - 'identified_only': Only create when user is identified
121
+ * - 'never': Never create person profiles
122
+ */
123
+ person_profiles?: PersonProfilesMode;
124
+ /**
125
+ * Enable autocapture for automatic DOM event tracking.
126
+ * Can be a boolean or an object with detailed configuration.
127
+ * When true, captures clicks, form submissions, and input changes.
128
+ */
129
+ autocapture?: boolean | AutocaptureOptions;
130
+ /**
131
+ * Enable web vitals tracking.
132
+ * Can be a boolean or an object with detailed configuration.
133
+ */
134
+ capture_performance?: boolean | CapturePerformanceConfig;
135
+ /** Enable page view tracking */
136
+ capture_pageview?: boolean | "auto";
137
+ /** Enable page leave tracking */
138
+ capture_pageleave?: boolean | "if_capture_pageview";
139
+ /** Enable rage click detection (rapid clicks in same area) */
140
+ rageclick?: boolean;
141
+ /** Disable compression */
142
+ disable_compression?: boolean;
143
+ /** Whether to stringify payload before sending */
144
+ stringifyPayload?: boolean;
145
+ /** Properties to exclude from events */
146
+ property_denylist?: string[];
147
+ /** Mask text in autocapture */
148
+ mask_all_text?: boolean;
149
+ /** Mask all element attributes */
150
+ mask_all_element_attributes?: boolean;
151
+ /** Respect Do Not Track browser setting */
152
+ respect_dnt?: boolean;
153
+ /**
154
+ * When false (default), events are not sent when the browser looks like a bot
155
+ * (known crawler user agents, `navigator.webdriver`, or blocked CH brands).
156
+ * Set to true to disable bot filtering (PostHog: `opt_out_useragent_filter`).
157
+ */
158
+ opt_out_useragent_filter?: boolean;
159
+ /**
160
+ * Extra user-agent substrings to treat as bots (case-insensitive), merged with
161
+ * the built-in list aligned with PostHog (PostHog: `custom_blocked_useragents`).
162
+ */
163
+ custom_blocked_useragents?: string[];
164
+ /** Opt users out by default */
165
+ opt_out_capturing_by_default?: boolean;
166
+ /**
167
+ * When true, non-essential events are blocked until setConsent() is called.
168
+ * Essential events ($identify, $alias, $set) are always allowed.
169
+ * Use with vt.setConsent({ analytics: true, marketing: true, advertising: true }).
170
+ */
171
+ require_consent?: boolean;
172
+ /** Session recording configuration */
173
+ session_recording?: SessionRecordingOptions;
174
+ /** Disable session recording (convenience flag) */
175
+ disable_session_recording?: boolean;
176
+ /** Chat widget configuration */
177
+ chat?: ChatWidgetConfig;
178
+ /** Disable chat (convenience flag) */
179
+ disable_chat?: boolean;
180
+ /**
181
+ * Google Tag Gateway feature config (merged `ga4_gtag` + `google_ads_gtag`
182
+ * rows). Property name is the stable SDK config key; populated from `/decide`
183
+ * or set for SSR/tests.
184
+ */
185
+ google_tag?: GoogleTagClientConfig;
186
+ /** Disable the Google Tag Gateway feature (convenience flag) */
187
+ disable_google_tag?: boolean;
188
+ /**
189
+ * Console log level for SDK output prefixed with `[vTilt]`.
190
+ *
191
+ * Levels (each includes the levels above it):
192
+ * - 'none' — silence everything (escape hatch for shared kiosks etc.)
193
+ * - 'error' — SDK errors only
194
+ * - 'warn' — errors + warnings (default)
195
+ * - 'info' — + lifecycle events (init, autocapture started, replay started)
196
+ * - 'debug' — + per-event trace (every captured event, autocapture skips, requests)
197
+ *
198
+ * Default is 'warn' so SDK errors and warnings always surface without opt-in
199
+ * (matches Amplitude/PostHog/Sentry).
200
+ *
201
+ * NOT to be confused with the per-event `$debug` flag — that is a separate
202
+ * marker on the event payload itself, controlled by `debug: true` (below)
203
+ * or the `?vtilt_debug=1` URL parameter, and consumed by the Debug View in
204
+ * the dashboard. See the public docs for details.
205
+ *
206
+ * Setting `log_level` (or `debug: true`) at init time pins the level — it
207
+ * cannot be overridden by remote config / Default Configuration. Leave it
208
+ * unset to let project admins control verbosity from the dashboard.
209
+ */
210
+ log_level?: "none" | "error" | "warn" | "info" | "debug";
211
+ /**
212
+ * PostHog-style shorthand: when true, equivalent to `log_level: 'debug'`.
213
+ * Ignored if `log_level` is also set.
214
+ *
215
+ * Setting this to true ALSO marks every captured event with `$debug: true`
216
+ * so the dashboard's Debug View highlights it. The `?vtilt_debug=1` URL
217
+ * parameter sets the event flag without raising the console log level.
218
+ */
219
+ debug?: boolean;
220
+ /** Global attributes added to all events */
221
+ globalAttributes?: Record<string, string>;
222
+ /** Bootstrap data for initialization (server-side rendering) */
223
+ bootstrap?: {
224
+ distinctID?: string;
225
+ isIdentifiedID?: boolean;
226
+ featureFlags?: Record<string, boolean | string>;
227
+ /** Remote config from /decide endpoint - use this for SSR to avoid async fetch delay */
228
+ remoteConfig?: RemoteConfig;
229
+ };
230
+ /** Before send hook for modifying events */
231
+ before_send?: (event: CaptureResult) => CaptureResult | null;
232
+ /** Loaded callback */
233
+ loaded?: (vtilt: any) => void;
234
+ /** @internal Set by RemoteConfigManager after a fresh /decide response (or fetch failure). */
235
+ __remote_config_loaded?: boolean;
236
+ }
237
+ interface EventPayload {
238
+ [key: string]: any;
239
+ }
240
+ interface CaptureResult {
241
+ uuid: string;
242
+ event: string;
243
+ properties: Properties;
244
+ $set?: Properties;
245
+ $set_once?: Properties;
246
+ timestamp?: string;
247
+ }
248
+ interface CaptureOptions {
249
+ /** Override timestamp */
250
+ timestamp?: Date;
251
+ /** Properties to $set on person */
252
+ $set?: Properties;
253
+ /** Properties to $set_once on person */
254
+ $set_once?: Properties;
255
+ /** Send immediately (skip batching) */
256
+ send_instantly?: boolean;
257
+ }
258
+ interface TrackingEvent {
259
+ timestamp: string;
260
+ event: string;
261
+ distinct_id: string;
262
+ anonymous_id?: string;
263
+ payload: EventPayload;
264
+ }
265
+ type Property = string | number | boolean | null | undefined | Date | any[] | Record<string, any>;
266
+ interface Properties {
267
+ [key: string]: Property;
268
+ }
269
+ interface PropertyOperations {
270
+ $set?: Properties;
271
+ $set_once?: Properties;
272
+ $unset?: string[];
273
+ }
274
+ interface SessionData {
275
+ value: string;
276
+ expiry: number;
277
+ }
278
+ /**
279
+ * Persistence method for user/session data
280
+ * Following PostHog's approach:
281
+ * - 'localStorage+cookie': Stores limited data in cookies, rest in localStorage (default)
282
+ * - 'cookie': Stores all data in cookies
283
+ * - 'localStorage': Stores all data in localStorage
284
+ * - 'sessionStorage': Stores all data in sessionStorage
285
+ * - 'memory': Stores all data in memory only (no persistence)
286
+ */
287
+ type PersistenceMethod = "localStorage+cookie" | "cookie" | "localStorage" | "sessionStorage" | "memory";
288
+ /** User identity state */
289
+ interface UserIdentity {
290
+ /** Current distinct ID (null if anonymous) */
291
+ distinct_id: string | null;
292
+ /** Anonymous ID (always present) */
293
+ anonymous_id: string;
294
+ /** Device ID (persists across sessions) */
295
+ device_id: string;
296
+ /** User properties */
297
+ properties: Properties;
298
+ /** Identity state */
299
+ user_state: "anonymous" | "identified";
300
+ }
301
+ interface UserProperties {
302
+ [key: string]: any;
303
+ }
304
+ /** Batched identity state change — applied atomically with a single save. */
305
+ interface IdentityUpdate {
306
+ distinct_id?: string;
307
+ user_state?: "anonymous" | "identified";
308
+ device_id?: string;
309
+ properties_set?: Properties;
310
+ properties_set_once?: Properties;
311
+ }
312
+ /** Supported Web Vitals metrics */
313
+ type SupportedWebVitalsMetric = "LCP" | "CLS" | "FCP" | "INP" | "TTFB";
314
+ /** All supported Web Vitals metrics */
315
+ declare const ALL_WEB_VITALS_METRICS: SupportedWebVitalsMetric[];
316
+ /** Default Web Vitals metrics (matches PostHog defaults) */
317
+ declare const DEFAULT_WEB_VITALS_METRICS: SupportedWebVitalsMetric[];
318
+ /**
319
+ * Web Vitals capture configuration
320
+ */
321
+ interface CapturePerformanceConfig {
322
+ /** Enable or disable web vitals capture */
323
+ web_vitals?: boolean;
324
+ /** Which metrics to capture (default: LCP, CLS, FCP, INP) */
325
+ web_vitals_allowed_metrics?: SupportedWebVitalsMetric[];
326
+ /** Delay before flushing metrics in ms (default: 5000) */
327
+ web_vitals_delayed_flush_ms?: number;
328
+ /**
329
+ * Maximum allowed metric value in ms (default: 900000 = 15 minutes)
330
+ * Values above this are considered anomalies and ignored.
331
+ * Set to 0 to disable this check.
332
+ */
333
+ __web_vitals_max_value?: number;
334
+ }
335
+ interface WebVitalMetric {
336
+ name: string;
337
+ value: number;
338
+ delta: number;
339
+ rating: "good" | "needs-improvement" | "poor";
340
+ id: string;
341
+ navigationType: string;
342
+ /** Timestamp when the metric was captured (added internally) */
343
+ timestamp?: number;
344
+ /** Attribution data from web-vitals library */
345
+ attribution?: Record<string, unknown>;
346
+ }
347
+ interface GeolocationData {
348
+ country?: string;
349
+ locale?: string;
350
+ }
351
+ interface GroupsConfig {
352
+ [groupType: string]: string;
353
+ }
354
+ interface FeatureFlagsConfig {
355
+ [flagKey: string]: boolean | string;
356
+ }
357
+ type SessionIdChangedCallback = (newSessionId: string, previousSessionId: string | null, changeInfo: {
358
+ reason: "timeout" | "new_session" | "reset";
359
+ }) => void;
360
+ interface RequestOptions {
361
+ method?: "POST" | "GET";
362
+ headers?: Record<string, string>;
363
+ timeout?: number;
364
+ retry?: boolean;
365
+ }
366
+ /**
367
+ * Autocapture configuration options
368
+ * Controls automatic DOM event tracking (clicks, form submissions, input changes)
369
+ */
370
+ interface AutocaptureOptions {
371
+ /**
372
+ * Enable autocapture (default: true when autocapture config is present)
373
+ */
374
+ enabled?: boolean;
375
+ /**
376
+ * URL patterns to allow autocapture on (default: all URLs)
377
+ * Supports strings (exact match) and RegExp patterns
378
+ */
379
+ url_allowlist?: (string | RegExp)[];
380
+ /**
381
+ * URL patterns to exclude from autocapture
382
+ * Supports strings (exact match) and RegExp patterns
383
+ */
384
+ url_ignorelist?: (string | RegExp)[];
385
+ /**
386
+ * DOM events to capture (default: ['click', 'change', 'submit'])
387
+ */
388
+ dom_event_allowlist?: ("click" | "change" | "submit")[];
389
+ /**
390
+ * Element tags to capture (default: ['a', 'button', 'form', 'input', 'select', 'textarea', 'label'])
391
+ */
392
+ element_allowlist?: string[];
393
+ /**
394
+ * CSS selectors to allow for capture (elements matching these are always captured)
395
+ * Example: ['[data-track]', '.track-click']
396
+ */
397
+ css_selector_allowlist?: string[];
398
+ /**
399
+ * CSS selectors to exclude from autocapture.
400
+ * If any element in the tree matches, the event is NOT captured.
401
+ *
402
+ * By default, common cookie consent banner patterns are excluded:
403
+ * - Elements with 'cookie', 'consent', 'gdpr', 'privacy' in id/class
404
+ * - Known consent management platforms (CookieBot, OneTrust, Iubenda, etc.)
405
+ *
406
+ * Set to empty array [] to disable default filtering.
407
+ *
408
+ * Example: ['#my-custom-banner', '[data-no-track]']
409
+ */
410
+ css_selector_ignorelist?: string[];
411
+ /**
412
+ * Element attributes to exclude from capture
413
+ * Example: ['data-secret', 'aria-label']
414
+ */
415
+ element_attribute_ignorelist?: string[];
416
+ /**
417
+ * Capture text content from copy/cut events (default: false)
418
+ */
419
+ capture_copied_text?: boolean;
420
+ /**
421
+ * Mask all text content in captured elements (use placeholder).
422
+ * Overrides VTiltConfig.mask_all_text for autocapture specifically.
423
+ */
424
+ mask_all_text?: boolean;
425
+ /**
426
+ * Mask all element attributes (only safe attributes or none).
427
+ * Overrides VTiltConfig.mask_all_element_attributes for autocapture specifically.
428
+ */
429
+ mask_all_element_attributes?: boolean;
430
+ /**
431
+ * Capture form field values on change events (default: false)
432
+ *
433
+ * When enabled, captures $el_value and $selected_text properties:
434
+ * - $el_value: The programmatic value (input.value, option.value, checkbox checked state)
435
+ * - $selected_text: Human-readable selection (option text, checkbox label)
436
+ *
437
+ * Protected by multiple privacy layers:
438
+ * - Password and hidden inputs are never captured
439
+ * - Fields with sensitive names (cc, pass, ssn, etc.) are skipped
440
+ * - Credit card and SSN patterns in values are filtered out
441
+ * - Elements with vt-sensitive or vt-no-capture classes are excluded
442
+ *
443
+ * Use case: Tracking search keywords, filter selections, etc.
444
+ *
445
+ * @default false
446
+ */
447
+ capture_element_values?: boolean;
448
+ /**
449
+ * Scroll depth autocapture — two independently opt-in modes (both default off).
450
+ */
451
+ scroll_depth?: {
452
+ milestones?: boolean | {
453
+ thresholds?: number[];
454
+ };
455
+ pageleave?: boolean;
456
+ scroll_root_selector?: string | string[];
457
+ };
458
+ }
459
+ /** Mask options for input elements in session recording */
460
+ interface SessionRecordingMaskInputOptions {
461
+ color?: boolean;
462
+ date?: boolean;
463
+ "datetime-local"?: boolean;
464
+ email?: boolean;
465
+ month?: boolean;
466
+ number?: boolean;
467
+ range?: boolean;
468
+ search?: boolean;
469
+ tel?: boolean;
470
+ text?: boolean;
471
+ time?: boolean;
472
+ url?: boolean;
473
+ week?: boolean;
474
+ textarea?: boolean;
475
+ select?: boolean;
476
+ password?: boolean;
477
+ }
478
+ /** Session recording configuration */
479
+ interface SessionRecordingOptions {
480
+ /** Enable session recording */
481
+ enabled?: boolean;
482
+ /** Sample rate (0-1, where 1 = 100%) */
483
+ sampleRate?: number;
484
+ /** Minimum session duration in ms before sending */
485
+ minimumDurationMs?: number;
486
+ /** Session idle threshold in ms (default: 5 minutes) */
487
+ sessionIdleThresholdMs?: number;
488
+ /** Full snapshot interval in ms (default: 5 minutes) */
489
+ fullSnapshotIntervalMs?: number;
490
+ /** Enable console log capture */
491
+ captureConsole?: boolean;
492
+ /** Enable network request capture */
493
+ captureNetwork?: boolean;
494
+ /** Canvas recording settings */
495
+ captureCanvas?: {
496
+ recordCanvas?: boolean;
497
+ canvasFps?: number;
498
+ canvasQuality?: number;
499
+ };
500
+ /** Block class for elements to hide (default: 'vt-no-capture') */
501
+ blockClass?: string;
502
+ /** Block selector for elements to hide */
503
+ blockSelector?: string;
504
+ /**
505
+ * When `true`, skip built-in `blockSelector` entries for common invisible
506
+ * template nodes (screen-reader-only, Webflow CMS placeholders, etc.).
507
+ */
508
+ skipDefaultInvisibleBlocking?: boolean;
509
+ /** Ignore class for input masking (default: 'vt-ignore-input') */
510
+ ignoreClass?: string;
511
+ /** Mask text class (default: 'vt-mask') */
512
+ maskTextClass?: string;
513
+ /** Mask text selector */
514
+ maskTextSelector?: string;
515
+ /** Mask all inputs (default: true) */
516
+ maskAllInputs?: boolean;
517
+ /** Mask input options */
518
+ maskInputOptions?: SessionRecordingMaskInputOptions;
519
+ /** Masking configuration */
520
+ masking?: {
521
+ maskAllInputs?: boolean;
522
+ maskTextSelector?: string;
523
+ blockSelector?: string;
524
+ };
525
+ /** Record headers in network requests */
526
+ recordHeaders?: boolean;
527
+ /** Record body in network requests */
528
+ recordBody?: boolean;
529
+ /** Gzip-compress the request body before sending (default: true) */
530
+ compressEvents?: boolean;
531
+ /** Internal: Mutation throttler refill rate */
532
+ __mutationThrottlerRefillRate?: number;
533
+ /** Internal: Mutation throttler bucket size */
534
+ __mutationThrottlerBucketSize?: number;
535
+ }
536
+ /** Chat widget configuration */
537
+ interface ChatWidgetConfig {
538
+ /** Enable/disable chat widget (default: auto from dashboard) */
539
+ enabled?: boolean;
540
+ /** Auto-fetch settings from dashboard (default: true) */
541
+ autoConfig?: boolean;
542
+ /** Widget position (default: 'bottom-right') */
543
+ position?: "bottom-right" | "bottom-left";
544
+ /** Widget header/greeting message */
545
+ greeting?: string;
546
+ /** Widget primary color */
547
+ color?: string;
548
+ /** Start in AI mode (default: true) */
549
+ aiMode?: boolean;
550
+ /** AI greeting message (first message from AI) */
551
+ aiGreeting?: string;
552
+ /** Preload widget script on idle vs on-demand */
553
+ preload?: boolean;
554
+ /** Offline message shown when business is unavailable */
555
+ offlineMessage?: string;
556
+ /** Collect email when offline */
557
+ collectEmailOffline?: boolean;
558
+ /** Bubble appearance and behavior */
559
+ bubble?: BubbleConfig;
560
+ }
561
+ type GoogleConsentValue = "follow_advertising" | "follow_analytics" | "granted" | "denied";
562
+ interface GoogleConsentOverride {
563
+ ad_storage?: GoogleConsentValue;
564
+ ad_user_data?: GoogleConsentValue;
565
+ ad_personalization?: GoogleConsentValue;
566
+ analytics_storage?: GoogleConsentValue;
567
+ }
568
+ interface GoogleAdsConversionMapping {
569
+ event_name: string;
570
+ send_to: string;
571
+ value_param_path?: string;
572
+ currency_param_path?: string;
573
+ default_currency?: string;
574
+ send_transaction_id?: boolean;
575
+ transaction_id_param_path?: string;
576
+ }
577
+ /**
578
+ * How gtag.js is loaded — mirrors the server-side `proxy_mode` destination
579
+ * setting:
580
+ *
581
+ * - `proxied` (default) — route through `api_host/gt/*`. `api_host` is the
582
+ * SDK-level proxy setting; self-hosted customers point it at their own
583
+ * domain (which must implement the `/gt/*` spec).
584
+ * - `direct` — no proxy; gtag.js loads straight from
585
+ * `https://www.googletagmanager.com/gtag/js`.
586
+ */
587
+ type GoogleTagProxyMode = "proxied" | "direct";
588
+ /**
589
+ * Configuration for the Google Tag Gateway SDK feature. Ships under the
590
+ * `googleTag` key of /decide when at least one `ga4_gtag` or `google_ads_gtag` destination is
591
+ * enabled for the project.
592
+ */
593
+ interface GoogleTagClientConfig {
594
+ destinationId: string;
595
+ /**
596
+ * Proxy mode. When absent the SDK falls back to `proxied` so older
597
+ * `/decide` responses and the zero-config default remain compatible.
598
+ */
599
+ proxyMode?: GoogleTagProxyMode;
600
+ tagIds: string[];
601
+ conversions: GoogleAdsConversionMapping[];
602
+ enhancedConversions: boolean;
603
+ conversionLinker: boolean;
604
+ linkerDomains: string[];
605
+ capturePageview: boolean;
606
+ debugMode: boolean;
607
+ consentOverride?: GoogleConsentOverride;
608
+ /**
609
+ * Master switch for forwarding every `vt.capture()` event to GA4 via
610
+ * `gtag('event', name, params)`. Defaults to `true` when absent. When
611
+ * `false`, only events that match an explicit row in `eventMappings` — or
612
+ * an Ads `conversions` mapping — fire; everything else is left to the
613
+ * Google tag's own behavior (page_view, enhanced measurement, etc.).
614
+ */
615
+ autoForward?: boolean;
616
+ /**
617
+ * Whether to fire the direct Ads conversion beacon
618
+ * (`gtag('event', 'conversion', {send_to: 'AW-.../...'})`) for rows in
619
+ * `conversions`. Defaults to `true` when absent. Turn off when GA4 is
620
+ * linked to Google Ads in the Ads account — in that mode the GA4 event
621
+ * (marked as a conversion in GA4) propagates to Ads automatically and
622
+ * the direct beacon would duplicate it. Has no effect when `conversions`
623
+ * is empty.
624
+ */
625
+ sendAdsConversions?: boolean;
626
+ /**
627
+ * Admin-configured event renames and param remappings. Mirrors the
628
+ * generic `event_mappings` configured on the destination. Applied after
629
+ * the filter check and before firing `gtag('event', ...)`.
630
+ */
631
+ eventMappings?: GoogleTagEventMapping[];
632
+ /**
633
+ * Admin-configured include/exclude lists. Mirrors the generic
634
+ * `event_filter` on the destination. Evaluated before any mapping.
635
+ */
636
+ eventFilter?: {
637
+ include?: string[];
638
+ exclude?: string[];
639
+ };
640
+ }
641
+ /**
642
+ * Rename an event and optionally remap payload paths to gtag param paths.
643
+ * Structurally identical to the server-side `EventMapping` type but lives
644
+ * in the browser package to avoid cross-package imports. Source paths use
645
+ * dotted notation into the captured payload (e.g. `order.total`); dest
646
+ * paths use dotted notation into the outgoing gtag `params` object.
647
+ */
648
+ interface GoogleTagEventMapping {
649
+ source: string;
650
+ destination: string;
651
+ param_mappings?: GoogleTagParamMapping[];
652
+ }
653
+ interface GoogleTagParamMapping {
654
+ source: string;
655
+ destination: string;
656
+ }
657
+ interface RemoteConfig {
658
+ sessionRecording?: {
659
+ enabled?: boolean;
660
+ sampleRate?: number;
661
+ minimumDurationMs?: number;
662
+ /** Full DOM snapshot interval in ms (default 300000 = 5 min). Higher = less data. */
663
+ fullSnapshotIntervalMs?: number;
664
+ maskAllInputs?: boolean;
665
+ maskAllText?: boolean;
666
+ captureConsole?: boolean;
667
+ captureCanvas?: {
668
+ recordCanvas?: boolean;
669
+ canvasFps?: number;
670
+ canvasQuality?: number;
671
+ };
672
+ };
673
+ chat?: {
674
+ enabled?: boolean;
675
+ widgetPosition?: "bottom-right" | "bottom-left";
676
+ widgetColor?: string;
677
+ bubbleDraggable?: boolean;
678
+ bubbleVisible?: boolean;
679
+ };
680
+ chatTracking?: {
681
+ trackUserMessages?: boolean;
682
+ trackAgentMessages?: boolean;
683
+ };
684
+ analytics?: {
685
+ capturePageview?: boolean;
686
+ capturePageleave?: boolean;
687
+ capturePerformance?: boolean;
688
+ autocapture?: boolean;
689
+ scrollDepthMilestones?: boolean;
690
+ scrollDepthPageleave?: boolean;
691
+ };
692
+ privacy?: {
693
+ respectDnt?: boolean;
694
+ requireConsent?: boolean;
695
+ ipAnonymization?: boolean;
696
+ };
697
+ /**
698
+ * Diagnostics — runtime-tunable console verbosity. Applied by the SDK only
699
+ * when the integrator did NOT pass `log_level` / `debug` to `vt.init()`.
700
+ * Set from the dashboard's Default Configuration → Diagnostics tab.
701
+ */
702
+ diagnostics?: {
703
+ defaultLogLevel?: "none" | "error" | "warn" | "info" | "debug";
704
+ };
705
+ featureFlags?: FeatureFlagsConfig;
706
+ /** Whether to send elements as chain string (PostHog compatibility) */
707
+ elementsChainAsString?: boolean;
708
+ /** Server-side autocapture opt-out */
709
+ autocapture_opt_out?: boolean;
710
+ /**
711
+ * Google Tag Gateway config (absent when no client Google gtag destination is
712
+ * enabled for the project). Drives the gtag.js proxy loader, Consent Mode
713
+ * v2 bridge, and event → conversion mappings.
714
+ */
715
+ googleTag?: GoogleTagClientConfig;
716
+ }
717
+
718
+ /**
719
+ * Session Manager - Handles session_id and window_id
720
+ *
721
+ * Uses shared StorageManager for consistent storage operations.
722
+ *
723
+ * Session ID: Unique per user session, expires after 30 minutes of inactivity
724
+ * Window ID: Unique per browser tab, persists across page reloads
725
+ */
726
+
727
+ declare class SessionManager {
728
+ private storage;
729
+ private _windowId;
730
+ private _isNewSession;
731
+ constructor(storageMethod?: PersistenceMethod, cross_subdomain?: boolean);
732
+ /**
733
+ * Hydrate window ID from sessionStorage.
734
+ * Called by VTilt._boot() once the browser environment is ready.
735
+ */
736
+ hydrateFromStorage(): void;
737
+ /**
738
+ * Get session ID (always returns a value, generates if needed)
739
+ */
740
+ getSessionId(): string;
741
+ /**
742
+ * Set session ID in storage
743
+ * Extends TTL if session_id exists, generates new one if not
744
+ */
745
+ setSessionId(): string;
746
+ /**
747
+ * Reset session ID (generates new session on reset)
748
+ */
749
+ resetSessionId(): void;
750
+ /**
751
+ * Returns true if the current session was just started (new session ID generated
752
+ * because the session cookie expired or didn't exist). Resets after first call.
753
+ * Matches GA4's _ss=1 semantics.
754
+ */
755
+ consumeSessionStart(): boolean;
756
+ /**
757
+ * Get session ID from storage (raw, can return null)
758
+ * Cookie Max-Age handles expiration automatically
759
+ */
760
+ private _getSessionIdRaw;
761
+ /**
762
+ * Store session ID
763
+ * Uses plain string format - cookie Max-Age handles expiration
764
+ */
765
+ private _storeSessionId;
766
+ /**
767
+ * Clear session ID from storage
768
+ */
769
+ private _clearSessionId;
770
+ /**
771
+ * Get window ID
772
+ * Window ID is unique per browser tab/window and persists across page reloads
773
+ * Always returns a window_id (generates one if not set)
774
+ */
775
+ getWindowId(): string;
776
+ /**
777
+ * Set window ID
778
+ * Stores in sessionStorage which is unique per tab
779
+ */
780
+ private _setWindowId;
781
+ /**
782
+ * Initialize window ID
783
+ * Detects tab duplication and handles window_id persistence
784
+ */
785
+ private _initializeWindowId;
786
+ /**
787
+ * Listen to window unload to clear primary window flag
788
+ * This helps distinguish between page reloads and tab duplication
789
+ */
790
+ private _listenToUnload;
791
+ /**
792
+ * Update storage method at runtime
793
+ */
794
+ updateStorageMethod(method: PersistenceMethod, cross_subdomain?: boolean): void;
795
+ }
796
+
797
+ /**
798
+ * User Manager - Handles user identity and properties
799
+ *
800
+ * Uses shared StorageManager for consistent storage operations.
801
+ *
802
+ * Manages:
803
+ * - anonymous_id: Generated ID for anonymous users
804
+ * - distinct_id: User-provided ID after identification
805
+ * - device_id: Persistent device identifier
806
+ * - user_properties: Custom properties set via identify/setUserProperties
807
+ * - user_state: "anonymous" or "identified"
808
+ */
809
+
810
+ declare class UserManager {
811
+ private storage;
812
+ private userIdentity;
813
+ private _isFirstVisit;
814
+ constructor(storageMethod?: PersistenceMethod, cross_subdomain?: boolean);
815
+ /**
816
+ * Hydrate identity from persistent storage.
817
+ *
818
+ * Called by VTilt._boot() once the browser environment is guaranteed ready
819
+ * (DOMContentLoaded). This is the only code path that reads from
820
+ * localStorage / cookies. If storage is empty (first visit), the generated
821
+ * IDs are persisted so they survive the next page load.
822
+ */
823
+ hydrateFromStorage(): void;
824
+ /**
825
+ * Generate an ephemeral in-memory identity with no storage access.
826
+ * Used by the constructor so the SDK is safe to instantiate in SSR.
827
+ */
828
+ private generateEphemeralIdentity;
829
+ /**
830
+ * Get current user identity
831
+ */
832
+ getUserIdentity(): UserIdentity;
833
+ /**
834
+ * Get current distinct ID (identified user ID)
835
+ */
836
+ getDistinctId(): string | null;
837
+ /**
838
+ * Get current anonymous ID
839
+ */
840
+ getAnonymousId(): string;
841
+ /**
842
+ * Get current user properties
843
+ */
844
+ getUserProperties(): Record<string, any>;
845
+ /**
846
+ * Get the effective ID for event tracking
847
+ */
848
+ getEffectiveId(): string;
849
+ /**
850
+ * Get current device ID
851
+ */
852
+ getDeviceId(): string;
853
+ /**
854
+ * Get current user state
855
+ */
856
+ getUserState(): "anonymous" | "identified";
857
+ /**
858
+ * Returns true if this is the user's first visit (no prior anonymous_id
859
+ * in storage when the SDK booted). Resets after first call.
860
+ * Matches GA4's _fv=1 semantics.
861
+ */
862
+ consumeFirstVisit(): boolean;
863
+ /**
864
+ * Apply batched identity changes with a single save.
865
+ * Replaces individual setters to avoid multiple storage writes per operation.
866
+ */
867
+ applyUpdate(update: IdentityUpdate): void;
868
+ /**
869
+ * Reset identity to anonymous state. Generates new IDs and clears user data.
870
+ */
871
+ reset(resetDeviceId?: boolean): void;
872
+ /**
873
+ * Set initial person info
874
+ */
875
+ set_initial_person_info(maskPersonalDataProperties?: boolean, customPersonalDataProperties?: string[]): void;
876
+ /**
877
+ * Get initial props
878
+ */
879
+ get_initial_props(): Record<string, any>;
880
+ /**
881
+ * Update referrer info
882
+ */
883
+ update_referrer_info(): void;
884
+ /**
885
+ * Load user identity from storage.
886
+ *
887
+ * For traditional SSR websites where each page navigation reloads JavaScript,
888
+ * identity MUST be persisted immediately when generated to ensure the same
889
+ * anonymous_id is used across all page loads.
890
+ *
891
+ * Flow:
892
+ * 1. Load from storage (reads cookies first for critical properties in SSR mode)
893
+ * 2. Generate new IDs if not found
894
+ * 3. Immediately persist to storage (saved to both localStorage and cookies)
895
+ *
896
+ * With `localStorage+cookie` persistence (default):
897
+ * - Critical properties are stored in cookies for SSR compatibility
898
+ * - Full data is stored in localStorage for fast SPA-style access
899
+ * - Cookies ensure identity persists across full page reloads
900
+ */
901
+ private loadUserIdentity;
902
+ /**
903
+ * Save user identity to storage
904
+ */
905
+ private saveUserIdentity;
906
+ /**
907
+ * Get user properties from storage
908
+ */
909
+ private getStoredUserProperties;
910
+ /**
911
+ * Set user properties in storage
912
+ */
913
+ private setStoredUserProperties;
914
+ /**
915
+ * Register a value once (only if not already set)
916
+ */
917
+ private register_once;
918
+ private generateAnonymousId;
919
+ private generateDeviceId;
920
+ /**
921
+ * Update storage method at runtime.
922
+ */
923
+ updateStorageMethod(method: PersistenceMethod, cross_subdomain?: boolean): void;
924
+ }
925
+
926
+ /**
927
+ * Feature Interface & Base Classes
928
+ *
929
+ * Standard interfaces and abstract base classes for vTilt SDK features.
930
+ *
931
+ * Hierarchy:
932
+ * Feature (interface) — eager features (Autocapture, HistoryAutocapture)
933
+ * ToggleableFeature (interface)— features that actively stop when disabled
934
+ * LazyFeature (abstract) — lazy-loaded features (WebVitals, Chat)
935
+ * ToggleableLazyFeature — lazy-loaded + toggle (SessionRecording)
936
+ *
937
+ * @see docs/patterns/tracker-feature-lifecycle.md
938
+ */
939
+
940
+ /**
941
+ * Feature interface that all vTilt features should implement.
942
+ * Provides a consistent lifecycle for feature initialization and management.
943
+ */
944
+ interface Feature {
945
+ readonly name: string;
946
+ readonly isEnabled: boolean;
947
+ readonly isStarted: boolean;
948
+ startIfEnabled(): void;
949
+ stop(): void;
950
+ /**
951
+ * Handle VTilt configuration updates.
952
+ * Called when the main VTilt config is updated via updateConfig().
953
+ * Features should re-evaluate their enabled state and start/stop accordingly.
954
+ */
955
+ onConfigUpdate?(config: VTiltConfig): void;
956
+ }
957
+ interface FeatureConfig {
958
+ enabled?: boolean;
959
+ }
960
+
961
+ /**
962
+ * Autocapture
963
+ *
964
+ * Automatic DOM event capture for clicks, form submissions, and input changes.
965
+ * Privacy-first approach with element chain tracking and sensitive data filtering.
966
+ *
967
+ * Lifecycle (see docs/patterns/tracker-feature-lifecycle.md):
968
+ * - Construction: created by FeatureManager when not hard-disabled.
969
+ * - startIfEnabled: attaches DOM listeners when isEnabled becomes true.
970
+ * - stop: detaches DOM listeners. Subsequent startIfEnabled re-attaches.
971
+ * - onConfigUpdate: re-evaluates isEnabled on every config change and starts or
972
+ * stops accordingly. This is what flips autocapture on when the
973
+ * /decide endpoint returns `analytics.autocapture: true`.
974
+ *
975
+ * Enabled state precedence (highest first):
976
+ * 1. _userOverride === false → off (set by vt.stopAutocapture())
977
+ * 2. _isDisabledServerSide === true → off (set by remote autocapture_opt_out)
978
+ * 3. _userOverride === true → on (set by vt.startAutocapture())
979
+ * 4. config.autocapture truthy → on
980
+ * 5. otherwise → off
981
+ */
982
+
983
+ /**
984
+ * Reasons isEnabled may evaluate to false. Surfaced by getDiagnostics() so that
985
+ * integrators can pinpoint why no `$autocapture` events are flowing.
986
+ */
987
+ type AutocaptureDisabledReason = "user_stop_called" | "server_opt_out" | "config_autocapture_false" | "config_autocapture_undefined";
988
+ interface AutocaptureDiagnostics {
989
+ /** Whether the feature is enabled given current config and overrides. */
990
+ isEnabled: boolean;
991
+ /** Whether DOM listeners are currently attached. */
992
+ isStarted: boolean;
993
+ /** Why the feature is disabled (if any). */
994
+ disabledReason: AutocaptureDisabledReason | null;
995
+ /** Snapshot of inputs that drove the decision. */
996
+ inputs: {
997
+ configAutocapture: unknown;
998
+ isDisabledServerSide: boolean;
999
+ userOverride: boolean | null;
1000
+ elementsChainAsString: boolean;
1001
+ captureCopiedText: boolean;
1002
+ scrollDepthMilestones: boolean;
1003
+ scrollDepthPageleave: boolean;
1004
+ scrollDepthListenerAttached: boolean;
1005
+ };
1006
+ }
1007
+ /**
1008
+ * Autocapture class for automatic DOM event tracking.
1009
+ * Implements the Feature interface for consistent lifecycle management.
1010
+ */
1011
+ declare class Autocapture implements Feature {
1012
+ readonly name = "Autocapture";
1013
+ private _instance;
1014
+ private _initialized;
1015
+ private _isDisabledServerSide;
1016
+ /** Explicit user override via vt.startAutocapture() / vt.stopAutocapture(). */
1017
+ private _userOverride;
1018
+ private _elementSelectors;
1019
+ private _rageclicks;
1020
+ /**
1021
+ * Compact-payload mode for `$autocapture`. When true (the default), the SDK
1022
+ * only sends the `$elements_chain` string and omits the verbose `$elements`
1023
+ * array — the array is duplicate information for the ingestion side and is
1024
+ * what pushes payloads past the client size cap on apps with deep DOM
1025
+ * trees / Tailwind / Material class soup. Integrators that still need
1026
+ * `$elements` (legacy filters / external pipelines) can opt out with
1027
+ * `vt.init({ elementsChainAsString: false })` or via `/decide`.
1028
+ */
1029
+ private _elementsChainAsString;
1030
+ private _cachedConfig;
1031
+ private _cachedConfigSource;
1032
+ /**
1033
+ * Bound DOM handlers. Stored so stop() can detach them — passing the same
1034
+ * function reference is required by removeEventListener().
1035
+ */
1036
+ private _domHandler;
1037
+ private _copyHandler;
1038
+ private _copyHandlerAttached;
1039
+ private _scrollDepthTracker;
1040
+ private _pageviewUnsubscribe;
1041
+ static extractConfig(config: VTiltConfig): {
1042
+ enabled: boolean;
1043
+ };
1044
+ constructor(instance: VTilt, _config?: {
1045
+ enabled: boolean;
1046
+ });
1047
+ private get _config();
1048
+ get isEnabled(): boolean;
1049
+ get isStarted(): boolean;
1050
+ startIfEnabled(): void;
1051
+ stop(): void;
1052
+ /**
1053
+ * Max scroll depth % for the current page when pageleave mode is enabled.
1054
+ * Used to enrich `$pageleave` payloads.
1055
+ */
1056
+ getMaxScrollDepthPctForPageleave(): number | null;
1057
+ onConfigUpdate(config: VTiltConfig): void;
1058
+ /**
1059
+ * Update autocapture configuration (for programmatic control).
1060
+ * Called from vt.startAutocapture() / vt.stopAutocapture().
1061
+ */
1062
+ updateConfig(config: Partial<{
1063
+ enabled: boolean;
1064
+ }>): void;
1065
+ getDiagnostics(): AutocaptureDiagnostics;
1066
+ setElementSelectors(selectors: Set<string>): void;
1067
+ getElementSelectors(element: Element | null): string[] | null;
1068
+ /**
1069
+ * Single-source-of-truth for whether autocapture should be active.
1070
+ * Returns the disabled reason so diagnostics and logging can be precise.
1071
+ */
1072
+ private _evaluateEnabled;
1073
+ private _addDomEventHandlers;
1074
+ private _removeDomEventHandlers;
1075
+ /**
1076
+ * Scroll depth listener — opt-in via `autocapture.scroll_depth` milestones and/or pageleave.
1077
+ */
1078
+ private _syncScrollDepthHandler;
1079
+ private _teardownScrollDepth;
1080
+ /**
1081
+ * The copy/cut listener is opt-in via `autocapture.capture_copied_text`.
1082
+ * Callable from both startIfEnabled and onConfigUpdate so toggling the flag
1083
+ * mid-session correctly attaches or detaches the listener.
1084
+ */
1085
+ private _syncCopyHandler;
1086
+ private _captureEvent;
1087
+ private _isBrowserSupported;
1088
+ }
1089
+
1090
+ /**
1091
+ * Consent Manager
1092
+ *
1093
+ * Manages user consent state for analytics, marketing, and advertising.
1094
+ * Stores consent in a first-party cookie (_vtilt_consent) and provides
1095
+ * consent properties to attach to every event.
1096
+ *
1097
+ * When `requireConsent` is true in config, the CaptureManager gates
1098
+ * non-essential events until setConsent() is called.
1099
+ */
1100
+ interface ConsentState {
1101
+ analytics?: boolean;
1102
+ marketing?: boolean;
1103
+ advertising?: boolean;
1104
+ }
1105
+ interface ConsentHost {
1106
+ _emitter?: {
1107
+ emit(event: string, payload?: unknown): void;
1108
+ };
1109
+ getConfig(): {
1110
+ require_consent?: boolean;
1111
+ };
1112
+ }
1113
+ declare class ConsentManager {
1114
+ private _host;
1115
+ private _state;
1116
+ private _hasBeenSet;
1117
+ constructor(host: ConsentHost);
1118
+ /**
1119
+ * Set consent state. Merges with existing state.
1120
+ * Persists to cookie and emits consent:updated.
1121
+ */
1122
+ setConsent(consent: ConsentState): void;
1123
+ /**
1124
+ * Get current consent state.
1125
+ * Returns undefined fields for categories not yet set.
1126
+ */
1127
+ getConsent(): ConsentState;
1128
+ /**
1129
+ * Whether setConsent() has been called (or consent was loaded from cookie).
1130
+ * Used by CaptureManager to gate events when requireConsent is true.
1131
+ */
1132
+ hasConsent(): boolean;
1133
+ /**
1134
+ * Apply default-all-granted state when no explicit consent exists.
1135
+ * Sets all categories to true in memory but does NOT persist to cookie
1136
+ * (implicit defaults don't need storage — only explicit user choices do).
1137
+ */
1138
+ setDefaultGranted(): void;
1139
+ /**
1140
+ * Returns event properties to attach to every captured event.
1141
+ * Only includes fields that have been explicitly set.
1142
+ */
1143
+ getConsentProperties(): Record<string, boolean>;
1144
+ /**
1145
+ * Reset consent state (e.g. on user logout).
1146
+ */
1147
+ reset(): void;
1148
+ private _readFromCookie;
1149
+ private _writeToCookie;
1150
+ private _removeCookie;
1151
+ }
1152
+
1153
+ /**
1154
+ * Consent Mode v2 bridge.
1155
+ *
1156
+ * Maps vTilt's 3-boolean consent (analytics / marketing / advertising) to
1157
+ * Google's 4-key Consent Mode v2 payload (ad_storage, ad_user_data,
1158
+ * ad_personalization, analytics_storage) and pushes it through gtag.
1159
+ *
1160
+ * Mapping (default):
1161
+ * advertising -> ad_storage + ad_user_data + ad_personalization
1162
+ * analytics -> analytics_storage
1163
+ * marketing is not sent to Google by default (it covers email/SMS, not ads).
1164
+ *
1165
+ * Admin UI may override individual keys (`consentOverride`) to hard-wire a
1166
+ * specific value regardless of user consent — useful for jurisdictions or
1167
+ * projects with fixed policies.
1168
+ */
1169
+
1170
+ type GtagFn = (...args: unknown[]) => void;
1171
+
1172
+ /**
1173
+ * `vt.gtag(...)` escape hatch.
1174
+ *
1175
+ * Power users may need to call `gtag` directly (e.g. to fire a custom
1176
+ * conversion from a third-party widget or to set a debug param). We expose
1177
+ * a flat passthrough that:
1178
+ *
1179
+ * - queues calls made before the SDK has booted (keeps them in FIFO order),
1180
+ * - queues calls made before `gtag.js` has loaded (forwarded via the
1181
+ * `dataLayer` shim, which naturally buffers until the real script runs),
1182
+ * - records every call so tests + the delivery log can see them.
1183
+ */
1184
+
1185
+ type GtagCall = unknown[];
1186
+
1187
+ /**
1188
+ * Enhanced Conversions helper.
1189
+ *
1190
+ * Hashes user-provided PII (email/phone/name/address) with SHA-256 before
1191
+ * it leaves the browser, matching Google Ads' Enhanced Conversions format:
1192
+ * https://support.google.com/google-ads/answer/13258081
1193
+ *
1194
+ * Returns an object suitable for `gtag('set', 'user_data', { ... })`.
1195
+ */
1196
+ interface RawUserData {
1197
+ email?: string | null;
1198
+ phone?: string | null;
1199
+ first_name?: string | null;
1200
+ last_name?: string | null;
1201
+ street?: string | null;
1202
+ city?: string | null;
1203
+ region?: string | null;
1204
+ postal_code?: string | null;
1205
+ country?: string | null;
1206
+ }
1207
+
1208
+ /**
1209
+ * GoogleTagGateway feature.
1210
+ *
1211
+ * Orchestrates the client-side half of the Google Tag Gateway destination:
1212
+ *
1213
+ * 1. Maintains `window.dataLayer` / `window.gtag`.
1214
+ * 2. Pushes Consent Mode v2 defaults BEFORE gtag.js loads, and re-pushes
1215
+ * on `consent:updated` events.
1216
+ * 3. Injects `gtag/js?id=<primary>` from the vTilt gateway (`/gt`) so
1217
+ * every measurement request flows through the first-party origin.
1218
+ * 4. Subscribes to EVENT_CAPTURED and forwards mapped events to Ads
1219
+ * (`gtag('event', 'conversion', ...)`).
1220
+ * 5. Exposes a flat `vt.gtag(...)` passthrough for power users.
1221
+ *
1222
+ * Forwards only after `__remote_config_loaded` is true (same signal as
1223
+ * EventBuffer: fresh `/decide` applied, bootstrap, or fetch failure).
1224
+ * Captures before that are queued so we never drop events just because
1225
+ * `/decide` has not committed yet. After remote is ready, we install the
1226
+ * official `dataLayer` + `gtag` shim (`ensureDataLayer`) and forward
1227
+ * immediately — the shim queues until `gtag.js` loads; we do not maintain a
1228
+ * second SDK queue for that window.
1229
+ *
1230
+ * Feature lifecycle matches the rest of the SDK — registered with
1231
+ * FeatureManager via a descriptor that pulls the admin-configured shape
1232
+ * out of `/decide` under the `googleTag` key.
1233
+ */
1234
+
1235
+ interface GoogleTagGatewayFeatureConfig extends FeatureConfig {
1236
+ remote?: GoogleTagClientConfig;
1237
+ }
1238
+ interface DeliveryLogEntry {
1239
+ ts: number;
1240
+ tag_ids: string[];
1241
+ event_name: string;
1242
+ send_to: string;
1243
+ status: "fired" | "dropped";
1244
+ reason?: string;
1245
+ }
1246
+ declare class GoogleTagGateway implements Feature {
1247
+ readonly name = "GoogleTagGateway";
1248
+ private _instance;
1249
+ private _config;
1250
+ private _isStarted;
1251
+ private _scriptInjected;
1252
+ private _scriptLoaded;
1253
+ private _consentDefaultsPushed;
1254
+ private _gtag;
1255
+ private _publicApi;
1256
+ private _loaderOptions;
1257
+ private _unsubscribeCaptured;
1258
+ private _unsubscribeConsent;
1259
+ private _deliveryLog;
1260
+ private readonly _maxDeliveryLog;
1261
+ /**
1262
+ * Captures observed before `__remote_config_loaded` only. Once remote
1263
+ * commits, `ensureDataLayer` + gtag forward — gtag's own queue handles
1264
+ * ordering until `gtag.js` is on the wire.
1265
+ */
1266
+ private readonly _pendingCaptures;
1267
+ constructor(instance: VTilt, config?: GoogleTagGatewayFeatureConfig);
1268
+ static extractConfig(config: VTiltConfig): GoogleTagGatewayFeatureConfig;
1269
+ get isEnabled(): boolean;
1270
+ get isStarted(): boolean;
1271
+ /** Exposed for tests and the public `vt.gtag` binding. */
1272
+ get gtag(): GtagFn;
1273
+ get deliveryLog(): DeliveryLogEntry[];
1274
+ startIfEnabled(): void;
1275
+ stop(): void;
1276
+ onConfigUpdate(config: VTiltConfig): void;
1277
+ /**
1278
+ * Set the user identifiers that power Enhanced Conversions. Values are
1279
+ * normalized + SHA-256 hashed client-side before being pushed to gtag,
1280
+ * so raw PII never leaves the browser.
1281
+ */
1282
+ setUserData(raw: RawUserData): Promise<void>;
1283
+ getRecentPublicCalls(): GtagCall[];
1284
+ private _start;
1285
+ private _drainPending;
1286
+ private _pushConsentDefaultsOnce;
1287
+ private _subscribeCaptured;
1288
+ /**
1289
+ * Handle one captured event. Only `__remote_config_loaded === false` uses
1290
+ * `_pendingCaptures`. After remote commits, we boot the gtag pipeline on
1291
+ * demand (`startIfEnabled`) and forward — the dataLayer shim buffers until
1292
+ * `gtag.js` loads.
1293
+ */
1294
+ private _handleCaptured;
1295
+ private _subscribeConsent;
1296
+ private _record;
1297
+ }
1298
+
1299
+ /**
1300
+ * VTD Overlay Feature
1301
+ *
1302
+ * Displays destination content in a fullscreen iframe overlay when vtd= URL parameter is present.
1303
+ * Used for tracking links that redirect to specific content (video, page, etc.).
1304
+ *
1305
+ * Example: https://example.com/?vt=person_id&vtd=https://youtube.com/watch?v=abc123
1306
+ *
1307
+ * @see docs/architecture/proposals/vt-vtd-tracking-links.md
1308
+ */
1309
+
1310
+ interface VtdOverlayConfig {
1311
+ /** Whether the overlay feature is enabled */
1312
+ enabled?: boolean;
1313
+ }
1314
+ declare class VtdOverlay implements Feature {
1315
+ readonly name = "VtdOverlay";
1316
+ private _instance;
1317
+ private _config;
1318
+ private _isStarted;
1319
+ private _destinationUrl;
1320
+ private _originalUrl;
1321
+ private _isLoading;
1322
+ private _container;
1323
+ private _iframe;
1324
+ private _loadingEl;
1325
+ constructor(instance: VTilt, config?: VtdOverlayConfig);
1326
+ static extractConfig(config: VTiltConfig): VtdOverlayConfig;
1327
+ get isEnabled(): boolean;
1328
+ get isStarted(): boolean;
1329
+ startIfEnabled(): void;
1330
+ stop(): void;
1331
+ onConfigUpdate(config: VTiltConfig): void;
1332
+ /**
1333
+ * Set the destination URL and show the overlay.
1334
+ * Called by vtilt.ts when vtd= parameter is detected.
1335
+ *
1336
+ * @param url - The destination URL (can be URL-encoded)
1337
+ */
1338
+ setDestinationUrl(url: string): void;
1339
+ /**
1340
+ * Get the current destination URL.
1341
+ */
1342
+ getDestinationUrl(): string | null;
1343
+ /**
1344
+ * Close the overlay with animation.
1345
+ */
1346
+ close(): void;
1347
+ private _isValidUrl;
1348
+ /**
1349
+ * Transform URLs to embeddable format for known platforms.
1350
+ * Many sites block iframe embedding but provide dedicated embed URLs.
1351
+ */
1352
+ private _toEmbedUrl;
1353
+ private _getHostname;
1354
+ private _getFaviconUrl;
1355
+ private _showOverlay;
1356
+ private _destroyOverlay;
1357
+ private _attachEventListeners;
1358
+ private _getBackdropStyles;
1359
+ private _getModalStyles;
1360
+ private _getHeaderStyles;
1361
+ private _getHeaderHTML;
1362
+ private _getIframeWrapperStyles;
1363
+ private _getLoadingStyles;
1364
+ private _getLoadingHTML;
1365
+ private _getIframeStyles;
1366
+ private _getGlobalStyles;
1367
+ private _truncateUrl;
1368
+ private _escapeHtml;
1369
+ }
1370
+
1371
+ /**
1372
+ * Request Queue - Event Batching (PostHog-style)
1373
+ *
1374
+ * Batches multiple events together and sends them at configurable intervals.
1375
+ * This reduces the number of HTTP requests significantly for active users.
1376
+ *
1377
+ * Features:
1378
+ * - Configurable flush interval (default 3 seconds)
1379
+ * - Batches events by URL/batchKey
1380
+ * - Uses sendBeacon on page unload for reliable delivery
1381
+ * - Converts absolute timestamps to relative offsets before sending
1382
+ */
1383
+
1384
+ interface QueuedRequest {
1385
+ url: string;
1386
+ event: TrackingEvent;
1387
+ batchKey?: string;
1388
+ transport?: "xhr" | "sendBeacon";
1389
+ }
1390
+
1391
+ /**
1392
+ * Rate Limiter - Token Bucket Algorithm (PostHog-style)
1393
+ *
1394
+ * Prevents runaway loops from flooding the server with events.
1395
+ * Uses a token bucket algorithm with configurable rate and burst limits.
1396
+ *
1397
+ * Features:
1398
+ * - Configurable events per second (default: 10)
1399
+ * - Configurable burst limit (default: 100)
1400
+ * - Token replenishment over time
1401
+ * - Warning event when rate limited
1402
+ */
1403
+ interface RateLimitBucket {
1404
+ tokens: number;
1405
+ last: number;
1406
+ }
1407
+ interface RateLimiterConfig {
1408
+ eventsPerSecond?: number;
1409
+ eventsBurstLimit?: number;
1410
+ persistence?: {
1411
+ get: (key: string) => RateLimitBucket | null;
1412
+ set: (key: string, value: RateLimitBucket) => void;
1413
+ };
1414
+ captureWarning?: (message: string) => void;
1415
+ }
1416
+ declare class RateLimiter {
1417
+ private eventsPerSecond;
1418
+ private eventsBurstLimit;
1419
+ private lastEventRateLimited;
1420
+ private persistence?;
1421
+ private captureWarning?;
1422
+ constructor(config?: RateLimiterConfig);
1423
+ /**
1424
+ * Check if the client should be rate limited
1425
+ *
1426
+ * @param checkOnly - If true, don't consume a token (just check)
1427
+ * @returns Object with isRateLimited flag and remaining tokens
1428
+ */
1429
+ checkRateLimit(checkOnly?: boolean): {
1430
+ isRateLimited: boolean;
1431
+ remainingTokens: number;
1432
+ };
1433
+ /**
1434
+ * Check if an event should be allowed (consumes a token if allowed)
1435
+ */
1436
+ shouldAllowEvent(): boolean;
1437
+ /**
1438
+ * Get remaining tokens without consuming
1439
+ */
1440
+ getRemainingTokens(): number;
1441
+ }
1442
+
1443
+ /**
1444
+ * Simple Event Emitter
1445
+ *
1446
+ * Lightweight pub/sub system for internal feature communication.
1447
+ * Following PostHog's SimpleEventEmitter pattern.
1448
+ */
1449
+ /**
1450
+ * Event listener function type
1451
+ */
1452
+ type EventListener<T = unknown> = (payload: T) => void;
1453
+ /**
1454
+ * Unsubscribe function returned by on()
1455
+ */
1456
+ type Unsubscribe = () => void;
1457
+ /**
1458
+ * Simple event emitter for internal SDK communication.
1459
+ * Features can emit and listen to events without direct coupling.
1460
+ *
1461
+ * @example
1462
+ * ```typescript
1463
+ * const emitter = new SimpleEventEmitter();
1464
+ *
1465
+ * // Subscribe to events
1466
+ * const unsubscribe = emitter.on('user:identified', (data) => {
1467
+ * console.log('User identified:', data);
1468
+ * });
1469
+ *
1470
+ * // Emit events
1471
+ * emitter.emit('user:identified', { userId: '123' });
1472
+ *
1473
+ * // Unsubscribe when done
1474
+ * unsubscribe();
1475
+ * ```
1476
+ */
1477
+ declare class SimpleEventEmitter {
1478
+ private _events;
1479
+ private _onceEvents;
1480
+ /**
1481
+ * Subscribe to an event.
1482
+ *
1483
+ * @param event - Event name to subscribe to
1484
+ * @param listener - Callback function
1485
+ * @returns Unsubscribe function
1486
+ */
1487
+ on<T = unknown>(event: string, listener: EventListener<T>): Unsubscribe;
1488
+ /**
1489
+ * Subscribe to an event once (auto-unsubscribes after first call).
1490
+ *
1491
+ * @param event - Event name to subscribe to
1492
+ * @param listener - Callback function
1493
+ * @returns Unsubscribe function
1494
+ */
1495
+ once<T = unknown>(event: string, listener: EventListener<T>): Unsubscribe;
1496
+ /**
1497
+ * Emit an event to all listeners.
1498
+ *
1499
+ * @param event - Event name to emit
1500
+ * @param payload - Data to pass to listeners
1501
+ */
1502
+ emit<T = unknown>(event: string, payload?: T): void;
1503
+ /**
1504
+ * Remove all listeners for an event.
1505
+ *
1506
+ * @param event - Event name (or undefined to remove all)
1507
+ */
1508
+ off(event?: string): void;
1509
+ /**
1510
+ * Get the number of listeners for an event.
1511
+ *
1512
+ * @param event - Event name
1513
+ * @returns Number of listeners
1514
+ */
1515
+ listenerCount(event: string): number;
1516
+ /**
1517
+ * Check if there are any listeners for an event.
1518
+ *
1519
+ * @param event - Event name
1520
+ * @returns True if there are listeners
1521
+ */
1522
+ hasListeners(event: string): boolean;
1523
+ }
1524
+
1525
+ /**
1526
+ * Feature Manager
1527
+ *
1528
+ * Central registry for SDK features. Features self-describe via descriptors
1529
+ * that declare their config keys, remote config mappings, and class references.
1530
+ *
1531
+ * Responsibilities:
1532
+ * - Registration: features register descriptors before init
1533
+ * - Instance creation: createInstances() constructs instances during init() (pre-boot)
1534
+ * - Starting: initAll() starts created instances at boot via startIfEnabled
1535
+ * - Config propagation: notifyAll() calls onConfigUpdate on each instance
1536
+ * - Descriptor exposure: getDescriptors() lets RemoteConfigManager._apply iterate
1537
+ *
1538
+ * @see docs/patterns/tracker-feature-lifecycle.md
1539
+ */
1540
+
1541
+ /**
1542
+ * Self-describing metadata for a feature.
1543
+ * Declared once at registration time; used by FeatureManager and RemoteConfigManager.
1544
+ */
1545
+ interface FeatureDescriptor {
1546
+ /** Unique name (used as map key and for get()) */
1547
+ name: string;
1548
+ /** VTiltConfig key that holds this feature's config (e.g. "session_recording") */
1549
+ configKey?: keyof VTiltConfig;
1550
+ /** VTiltConfig boolean key that hard-disables the feature (e.g. "disable_session_recording") */
1551
+ disableKey?: keyof VTiltConfig;
1552
+ /** Remote config mapping — tells _apply how to extract config from RemoteConfig */
1553
+ remoteConfig?: {
1554
+ /** Key on the RemoteConfig object (e.g. "sessionRecording") */
1555
+ key: string;
1556
+ /** Transform remote section into the shape written to VTiltConfig[configKey] */
1557
+ map: (remote: Record<string, unknown>) => Record<string, unknown>;
1558
+ };
1559
+ /** Feature class — must have a static extractConfig and a constructor */
1560
+ FeatureClass: {
1561
+ new (instance: any, config?: any): Feature;
1562
+ extractConfig(config: VTiltConfig): any;
1563
+ };
1564
+ }
1565
+ /**
1566
+ * Minimal host interface to avoid circular dependency with VTilt.
1567
+ */
1568
+ interface FeatureHost {
1569
+ getConfig(): VTiltConfig;
1570
+ }
1571
+ declare class FeatureManager {
1572
+ private _host;
1573
+ private _descriptors;
1574
+ private _instances;
1575
+ constructor(host: FeatureHost);
1576
+ /** Register a feature descriptor. Call before initAll(). */
1577
+ register(desc: FeatureDescriptor): void;
1578
+ /**
1579
+ * Create instances for all registered features without starting them.
1580
+ * Safe to call before DOM boot — constructors are lightweight.
1581
+ * Idempotent: skips features that already have an instance.
1582
+ *
1583
+ * Hard-disabled features are skipped (instance not created):
1584
+ * - `disableKey` is true (e.g. `disable_chat: true`)
1585
+ * - `configKey` section has `enabled: false` (e.g. `chat: { enabled: false }`)
1586
+ */
1587
+ createInstances(): void;
1588
+ /**
1589
+ * Create and start all registered features.
1590
+ * Calls `createInstances()` first (idempotent), then `startIfEnabled()` on each.
1591
+ */
1592
+ initAll(): void;
1593
+ /** Notify all initialized features of a config change. */
1594
+ notifyAll(config: VTiltConfig): void;
1595
+ /** Get a feature instance by name. */
1596
+ get<T extends Feature>(name: string): T | undefined;
1597
+ /** Register a late-created feature instance (e.g. from a public start*() call). */
1598
+ set(name: string, instance: Feature): void;
1599
+ /** Expose descriptors so RemoteConfigManager._apply can iterate for remote config mapping. */
1600
+ getDescriptors(): Map<string, FeatureDescriptor>;
1601
+ /**
1602
+ * True when the integrator explicitly hard-disabled this feature in code config.
1603
+ * Two signals: `disableKey` flag (e.g. `disable_chat: true`) or
1604
+ * `configKey` section with `enabled: false` (e.g. `chat: { enabled: false }`).
1605
+ *
1606
+ * When `enabled` is omitted (undefined), the feature may still auto-configure
1607
+ * from dashboard settings, so we must construct the instance.
1608
+ */
1609
+ private _isHardDisabled;
1610
+ }
1611
+
1612
+ /**
1613
+ * VTilt SDK - Main Entry Point
1614
+ *
1615
+ * Privacy-first analytics SDK with modular architecture.
1616
+ * This file is a thin orchestrator that delegates to specialized managers:
1617
+ *
1618
+ * - ConfigManager: Configuration management
1619
+ * - SessionManager: Session and window ID management
1620
+ * - UserManager: User identity and properties
1621
+ * - CaptureManager: Event capture and payload enrichment
1622
+ * - IdentityManager: High-level identity operations
1623
+ * - RemoteConfigManager: Remote configuration from /decide
1624
+ * - FeatureManager: Feature lifecycle management (descriptors, initAll, notifyAll)
1625
+ *
1626
+ * @see docs/patterns/tracker-feature-lifecycle.md
1627
+ */
1628
+
1629
+ declare class VTilt {
1630
+ readonly version: string;
1631
+ __loaded: boolean;
1632
+ private configManager;
1633
+ sessionManager: SessionManager;
1634
+ userManager: UserManager;
1635
+ private _captureManager;
1636
+ private _identityManager;
1637
+ private _remoteConfigManager;
1638
+ consentManager: ConsentManager;
1639
+ _featureManager: FeatureManager;
1640
+ vtdOverlay?: VtdOverlay;
1641
+ private _eventBuffer;
1642
+ private requestQueue;
1643
+ private retryQueue;
1644
+ rateLimiter: RateLimiter;
1645
+ _emitter: SimpleEventEmitter;
1646
+ private _has_warned_about_config;
1647
+ private static readonly BOOT_GATED_METHODS;
1648
+ private _booted;
1649
+ private _pendingCalls;
1650
+ private _postBootInitDone;
1651
+ constructor(config?: Partial<VTiltConfig>);
1652
+ /**
1653
+ * Register all features with their descriptors.
1654
+ * Descriptors tell FeatureManager and RemoteConfigManager how each feature works.
1655
+ */
1656
+ private _registerFeatures;
1657
+ private _installBootGate;
1658
+ _boot(): void;
1659
+ init(token: string, config?: Partial<VTiltConfig>, name?: string): VTilt;
1660
+ private _init;
1661
+ /**
1662
+ * Substantive init work that requires both init() config AND a booted
1663
+ * browser environment. Runs exactly once.
1664
+ *
1665
+ * Init order: hydrate storage -> initAll features -> load remote config
1666
+ * Features must exist before remote config loads so cached/fresh config
1667
+ * can trigger onConfigUpdate on already-initialized features.
1668
+ */
1669
+ private _runPostBootInit;
1670
+ startAutocapture(): void;
1671
+ stopAutocapture(): void;
1672
+ isAutocaptureActive(): boolean;
1673
+ /**
1674
+ * Returns a structured snapshot of the autocapture state — useful for
1675
+ * debugging "no `$autocapture` events" complaints. Returns `null` if the
1676
+ * Autocapture feature has not been registered (e.g. before init).
1677
+ */
1678
+ getAutocaptureDiagnostics(): ReturnType<Autocapture["getDiagnostics"]> | null;
1679
+ startSessionRecording(): void;
1680
+ stopSessionRecording(): void;
1681
+ isRecordingActive(): boolean;
1682
+ getSessionRecordingId(): string | null;
1683
+ openChat(): void;
1684
+ closeChat(): void;
1685
+ toggleChat(): void;
1686
+ showChat(): void;
1687
+ hideChat(): void;
1688
+ /**
1689
+ * Send a chat message. By default uses the active conversation; pass options to
1690
+ * start a new conversation, target a channel, or open the widget panel.
1691
+ */
1692
+ sendChatMessage(content: SendChatMessageContent, options?: SendChatMessageOptions): Promise<void>;
1693
+ /**
1694
+ * Raw `gtag(...)` passthrough. Queues calls made before the feature is
1695
+ * enabled or before `gtag.js` has loaded, flushed FIFO once ready. Safe
1696
+ * to call at any time, including before `vt.init()`.
1697
+ *
1698
+ * @example
1699
+ * vt.gtag('event', 'sign_up', { method: 'email' })
1700
+ */
1701
+ gtag(...args: unknown[]): void;
1702
+ /**
1703
+ * Set Enhanced Conversions user identifiers. Values are normalized and
1704
+ * SHA-256 hashed in the browser before being forwarded to gtag.
1705
+ */
1706
+ setGoogleUserData(data: Parameters<GoogleTagGateway["setUserData"]>[0]): Promise<void>;
1707
+ get featureManager(): FeatureManager;
1708
+ on<T = unknown>(event: string, listener: EventListener<T>): Unsubscribe;
1709
+ once<T = unknown>(event: string, listener: EventListener<T>): Unsubscribe;
1710
+ /** Removes all listeners for `event` (same semantics as internal emitter). */
1711
+ off(event: string): void;
1712
+ /**
1713
+ * Whether this browser session looks like a bot/crawler (PostHog parity).
1714
+ * When true and bot filtering is enabled, `capture()` is a no-op.
1715
+ */
1716
+ _is_bot(): boolean;
1717
+ capture(name: string, payload: EventPayload, options?: {
1718
+ skip_client_rate_limiting?: boolean;
1719
+ skip_engagement?: boolean;
1720
+ }): void;
1721
+ /** Emit $pageleave for the current page when enabled (SPA transitions, lifecycle hooks). */
1722
+ tryCapturePageleave(reason: string): void;
1723
+ identify(newDistinctId?: string, userPropertiesToSet?: Record<string, any>, userPropertiesToSetOnce?: Record<string, any>): void;
1724
+ setUserProperties(userPropertiesToSet?: Record<string, any>, userPropertiesToSetOnce?: Record<string, any>): void;
1725
+ resetUser(reset_device_id?: boolean): void;
1726
+ alias(alias: string, original?: string): void;
1727
+ setConsent(consent: ConsentState): void;
1728
+ getConsent(): ConsentState;
1729
+ getUserIdentity(): Record<string, any>;
1730
+ getDeviceId(): string;
1731
+ getUserState(): "anonymous" | "identified";
1732
+ getConfig(): VTiltConfig;
1733
+ getRemoteConfig(): RemoteConfig | null;
1734
+ getSessionId(): string | null;
1735
+ getDistinctId(): string;
1736
+ getAnonymousId(): string;
1737
+ toString(): string;
1738
+ /**
1739
+ * Merge a partial config patch into the live SDK config and notify all features.
1740
+ * Use for any post-`init()` change (autocapture, `chat`, persistence, etc.).
1741
+ * Top-level keys shallow-merge; nested `chat` deep-merges.
1742
+ */
1743
+ updateConfig(config: Partial<VTiltConfig>): void;
1744
+ buildUrl(): string;
1745
+ buildEndpointUrl(path: string): string;
1746
+ sendRequest(url: string, event: TrackingEvent): void;
1747
+ /**
1748
+ * Route a captured event through the EventBuffer.
1749
+ * $snapshot and $snapshot_items bypass the buffer (they have identity from
1750
+ * UserManager and don't need config filtering).
1751
+ */
1752
+ bufferEvent(name: string, url: string, event: TrackingEvent): void;
1753
+ private _is_configured;
1754
+ private _send_batched_request;
1755
+ private _send_http_request;
1756
+ private _send_beacon_request;
1757
+ _send_retriable_request(item: QueuedRequest): void;
1758
+ private _setup_unload_handler;
1759
+ private _start_queue_if_opted_in;
1760
+ private _read_vt_param_from_url;
1761
+ private _initVtdOverlay;
1762
+ _execute_array(array: any[]): void;
1763
+ _dom_loaded(): void;
1764
+ }
1765
+
1766
+ /**
1767
+ * Method names registered on the inline `window.vt` stub before `array.js` loads.
1768
+ *
1769
+ * npm / ESM imports (`import { vt } from '@v-tilt/browser'`) do **not** use this
1770
+ * list — `vt` is the real SDK instance. Only the HTML snippet's loader IIFE
1771
+ * needs these names so calls queue in `window.vt._i` until the bundle loads.
1772
+ *
1773
+ * When adding a new public `vt.*` method that integrators may call before
1774
+ * `init()` completes, append it here and update public install docs.
1775
+ */
1776
+ declare const VTILT_SNIPPET_STUB_METHOD_NAMES: readonly ["init", "capture", "identify", "setUserProperties", "resetUser", "getUserIdentity", "getDeviceId", "getUserState", "alias", "getConfig", "getSessionId", "updateConfig", "setConsent", "on", "once", "off", "startAutocapture", "stopAutocapture", "startSessionRecording", "stopSessionRecording", "openChat", "closeChat", "toggleChat", "showChat", "hideChat", "sendChatMessage", "gtag", "setGoogleUserData"];
1777
+ /** Space-separated stub method string for the minified install snippet. */
1778
+ declare const VTILT_SNIPPET_STUB_METHODS: string;
1779
+ type VtiltSnippetStubMethodName = (typeof VTILT_SNIPPET_STUB_METHOD_NAMES)[number];
1780
+
1781
+ declare const vt: VTilt;
1782
+
1783
+ /**
1784
+ * Full ESM bundle — core SDK plus recorder and web-vitals pre-registered on
1785
+ * `__VTiltExtensions__`. Same role as PostHog's `module.full.es.ts`.
1786
+ *
1787
+ * Chat is not included (see `module.full.chat.es.ts` or side-effect-import
1788
+ * `./chat` before init). Matches PostHog keeping `conversations` out of the
1789
+ * default full bundle because of bundle size.
1790
+ */
1791
+
1792
+ export { ALL_WEB_VITALS_METRICS, DEFAULT_WEB_VITALS_METRICS, VTILT_SNIPPET_STUB_METHODS, VTILT_SNIPPET_STUB_METHOD_NAMES, VTilt, vt as default, vt };
1793
+ export type { AutocaptureOptions, CaptureOptions, CapturePerformanceConfig, CaptureResult, ChatWidgetConfig, EventPayload, FeatureFlagsConfig, GeolocationData, GoogleAdsConversionMapping, GoogleConsentOverride, GoogleConsentValue, GoogleTagClientConfig, GoogleTagEventMapping, GoogleTagParamMapping, GoogleTagProxyMode, GroupsConfig, IdentityUpdate, PersistenceMethod, Properties, Property, PropertyOperations, RemoteConfig, RequestOptions, SessionData, SessionIdChangedCallback, SessionRecordingMaskInputOptions, SessionRecordingOptions, SupportedWebVitalsMetric, TrackingEvent, UserIdentity, UserProperties, VTiltConfig, VtiltSnippetStubMethodName, WebVitalMetric };