@v-tilt/browser 1.2.0 → 1.3.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 (41) hide show
  1. package/dist/all-external-dependencies.js +2 -0
  2. package/dist/all-external-dependencies.js.map +1 -0
  3. package/dist/array.full.js +2 -0
  4. package/dist/array.full.js.map +1 -0
  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/entrypoints/all-external-dependencies.d.ts +8 -0
  10. package/dist/entrypoints/array.full.d.ts +17 -0
  11. package/dist/entrypoints/web-vitals.d.ts +14 -0
  12. package/dist/external-scripts-loader.js +1 -1
  13. package/dist/external-scripts-loader.js.map +1 -1
  14. package/dist/main.js +1 -1
  15. package/dist/main.js.map +1 -1
  16. package/dist/module.d.ts +34 -4
  17. package/dist/module.js +1 -1
  18. package/dist/module.js.map +1 -1
  19. package/dist/module.no-external.d.ts +34 -4
  20. package/dist/module.no-external.js +1 -1
  21. package/dist/module.no-external.js.map +1 -1
  22. package/dist/recorder.js.map +1 -1
  23. package/dist/types.d.ts +32 -2
  24. package/dist/utils/globals.d.ts +27 -0
  25. package/dist/web-vitals.d.ts +89 -5
  26. package/dist/web-vitals.js +2 -0
  27. package/dist/web-vitals.js.map +1 -0
  28. package/lib/config.js +5 -3
  29. package/lib/entrypoints/all-external-dependencies.d.ts +8 -0
  30. package/lib/entrypoints/all-external-dependencies.js +10 -0
  31. package/lib/entrypoints/array.full.d.ts +17 -0
  32. package/lib/entrypoints/array.full.js +19 -0
  33. package/lib/entrypoints/external-scripts-loader.js +1 -1
  34. package/lib/entrypoints/web-vitals.d.ts +14 -0
  35. package/lib/entrypoints/web-vitals.js +29 -0
  36. package/lib/types.d.ts +32 -2
  37. package/lib/types.js +16 -0
  38. package/lib/utils/globals.d.ts +27 -0
  39. package/lib/web-vitals.d.ts +89 -5
  40. package/lib/web-vitals.js +354 -46
  41. package/package.json +1 -1
package/dist/types.d.ts CHANGED
@@ -51,8 +51,11 @@ export interface VTiltConfig {
51
51
  person_profiles?: PersonProfilesMode;
52
52
  /** Enable autocapture */
53
53
  autocapture?: boolean;
54
- /** Enable web vitals tracking */
55
- capture_performance?: boolean;
54
+ /**
55
+ * Enable web vitals tracking.
56
+ * Can be a boolean or an object with detailed configuration.
57
+ */
58
+ capture_performance?: boolean | CapturePerformanceConfig;
56
59
  /** Enable page view tracking */
57
60
  capture_pageview?: boolean | "auto";
58
61
  /** Enable page leave tracking */
@@ -160,6 +163,29 @@ export interface AliasEvent {
160
163
  distinct_id: string;
161
164
  original: string;
162
165
  }
166
+ /** Supported Web Vitals metrics */
167
+ export type SupportedWebVitalsMetric = "LCP" | "CLS" | "FCP" | "INP" | "TTFB";
168
+ /** All supported Web Vitals metrics */
169
+ export declare const ALL_WEB_VITALS_METRICS: SupportedWebVitalsMetric[];
170
+ /** Default Web Vitals metrics (matches PostHog defaults) */
171
+ export declare const DEFAULT_WEB_VITALS_METRICS: SupportedWebVitalsMetric[];
172
+ /**
173
+ * Web Vitals capture configuration
174
+ */
175
+ export interface CapturePerformanceConfig {
176
+ /** Enable or disable web vitals capture */
177
+ web_vitals?: boolean;
178
+ /** Which metrics to capture (default: LCP, CLS, FCP, INP) */
179
+ web_vitals_allowed_metrics?: SupportedWebVitalsMetric[];
180
+ /** Delay before flushing metrics in ms (default: 5000) */
181
+ web_vitals_delayed_flush_ms?: number;
182
+ /**
183
+ * Maximum allowed metric value in ms (default: 900000 = 15 minutes)
184
+ * Values above this are considered anomalies and ignored.
185
+ * Set to 0 to disable this check.
186
+ */
187
+ __web_vitals_max_value?: number;
188
+ }
163
189
  export interface WebVitalMetric {
164
190
  name: string;
165
191
  value: number;
@@ -167,6 +193,10 @@ export interface WebVitalMetric {
167
193
  rating: "good" | "needs-improvement" | "poor";
168
194
  id: string;
169
195
  navigationType: string;
196
+ /** Timestamp when the metric was captured (added internally) */
197
+ timestamp?: number;
198
+ /** Attribution data from web-vitals library */
199
+ attribution?: Record<string, unknown>;
170
200
  }
171
201
  export interface GeolocationData {
172
202
  country?: string;
@@ -17,6 +17,31 @@ export interface LazyLoadedSessionRecordingInterface {
17
17
  log: (message: string, level: "log" | "warn" | "error") => void;
18
18
  updateConfig: (config: any) => void;
19
19
  }
20
+ /**
21
+ * Web Vitals metric callback type
22
+ */
23
+ export type WebVitalsMetricCallback = (metric: any) => void;
24
+ /**
25
+ * Options for web vitals callbacks
26
+ */
27
+ export interface WebVitalsCallbackOptions {
28
+ /** Report all changes (useful for CLS which updates over time) */
29
+ reportAllChanges?: boolean;
30
+ }
31
+ /**
32
+ * Web Vitals callback function type (with optional options)
33
+ */
34
+ export type WebVitalsCallbackFn = (callback: WebVitalsMetricCallback, options?: WebVitalsCallbackOptions) => void;
35
+ /**
36
+ * Web Vitals callbacks interface (set by web-vitals.ts entrypoint)
37
+ */
38
+ export interface WebVitalsCallbacks {
39
+ onLCP: WebVitalsCallbackFn;
40
+ onCLS: WebVitalsCallbackFn;
41
+ onFCP: WebVitalsCallbackFn;
42
+ onINP: WebVitalsCallbackFn;
43
+ onTTFB?: WebVitalsCallbackFn;
44
+ }
20
45
  /**
21
46
  * VTilt Extensions interface for dynamically loaded modules
22
47
  * This is the contract between lazily loaded extensions and the SDK
@@ -37,6 +62,8 @@ export interface VTiltExtensions {
37
62
  };
38
63
  /** Factory to create LazyLoadedSessionRecording (set by recorder.ts) */
39
64
  initSessionRecording?: (instance: any, config?: any) => LazyLoadedSessionRecordingInterface;
65
+ /** Web Vitals callbacks (set by web-vitals.ts entrypoint) */
66
+ webVitalsCallbacks?: WebVitalsCallbacks;
40
67
  }
41
68
  export type AssignableWindow = Window & typeof globalThis & {
42
69
  /** Main VTilt instance */
@@ -1,11 +1,95 @@
1
- import { VTiltConfig } from "./types";
1
+ import { VTiltConfig, SupportedWebVitalsMetric } from "./types";
2
2
  import { VTilt } from "./vtilt";
3
+ /**
4
+ * Web Vitals Manager
5
+ *
6
+ * Captures Core Web Vitals (LCP, CLS, FCP, INP, TTFB) and sends them
7
+ * as batched $web_vitals events. Follows PostHog's approach with:
8
+ *
9
+ * 1. Extension pattern - checks for callbacks registered on __VTiltExtensions__
10
+ * 2. Lazy loading - loads web-vitals.js on demand if not bundled
11
+ * 3. Configurable metrics - choose which metrics to capture
12
+ * 4. Smart buffering - collects metrics per page, flushes on navigation or timeout
13
+ * 5. Session context - includes session_id and window_id for correlation
14
+ *
15
+ * Event structure:
16
+ * - event: "$web_vitals"
17
+ * - properties:
18
+ * - $web_vitals_LCP_value: number
19
+ * - $web_vitals_LCP_event: { name, value, delta, rating, ... }
20
+ * - $pathname: string
21
+ * - $current_url: string
22
+ */
3
23
  export declare class WebVitalsManager {
4
24
  private instance;
5
- private webVitals;
6
- constructor(config: VTiltConfig, instance: VTilt);
25
+ private buffer;
26
+ private flushTimer;
27
+ private initialized;
28
+ private config;
29
+ constructor(vtiltConfig: VTiltConfig, instance: VTilt);
7
30
  /**
8
- * Initialize web vitals tracking
31
+ * Parse capture_performance config (boolean or object)
9
32
  */
10
- private initializeWebVitals;
33
+ private parseConfig;
34
+ /**
35
+ * Check if web vitals capture is enabled
36
+ */
37
+ get isEnabled(): boolean;
38
+ /**
39
+ * Get the list of metrics to capture
40
+ */
41
+ get allowedMetrics(): SupportedWebVitalsMetric[];
42
+ /**
43
+ * Get flush timeout in ms
44
+ */
45
+ get flushTimeoutMs(): number;
46
+ /**
47
+ * Get maximum allowed metric value
48
+ */
49
+ get maxAllowedValue(): number;
50
+ private createEmptyBuffer;
51
+ /**
52
+ * Check if web vitals callbacks are available
53
+ */
54
+ private getWebVitalsCallbacks;
55
+ /**
56
+ * Start capturing if enabled and callbacks are available
57
+ */
58
+ startIfEnabled(): void;
59
+ /**
60
+ * Lazy load web-vitals extension
61
+ */
62
+ private loadWebVitals;
63
+ /**
64
+ * Start capturing web vitals using the provided callbacks
65
+ */
66
+ private startCapturing;
67
+ /**
68
+ * Get current URL
69
+ */
70
+ private getCurrentUrl;
71
+ /**
72
+ * Get current pathname
73
+ */
74
+ private getCurrentPathname;
75
+ /**
76
+ * Add a metric to the buffer
77
+ */
78
+ private addToBuffer;
79
+ /**
80
+ * Clean attribution data by removing large elements
81
+ */
82
+ private cleanAttribution;
83
+ /**
84
+ * Get window ID from instance
85
+ */
86
+ private getWindowId;
87
+ /**
88
+ * Schedule a delayed flush
89
+ */
90
+ private scheduleFlush;
91
+ /**
92
+ * Flush buffered metrics as a single event
93
+ */
94
+ private flush;
11
95
  }
@@ -0,0 +1,2 @@
1
+ !function(){"use strict";var n,e=-1,t=function(n){addEventListener("pageshow",function(t){t.persisted&&(e=t.timeStamp,n(t))},!0)},i=function(){return window.performance&&performance.getEntriesByType&&performance.getEntriesByType("navigation")[0]},r=function(){var n=i();return n&&n.activationStart||0},o=function(n,t){var o=i(),u="navigate";return e>=0?u="back-forward-cache":o&&(document.prerendering||r()>0?u="prerender":document.wasDiscarded?u="restore":o.type&&(u=o.type.replace(/_/g,"-"))),{name:n,value:void 0===t?-1:t,rating:"good",delta:0,entries:[],id:"v3-".concat(Date.now(),"-").concat(Math.floor(8999999999999*Math.random())+1e12),navigationType:u}},u=function(n,e,t){try{if(PerformanceObserver.supportedEntryTypes.includes(n)){var i=new PerformanceObserver(function(n){Promise.resolve().then(function(){e(n.getEntries())})});return i.observe(Object.assign({type:n,buffered:!0},t||{})),i}}catch(n){}},c=function(n,e,t,i){var r,o;return function(u){e.value>=0&&(u||i)&&((o=e.value-(r||0))||void 0===r)&&(r=e.value,e.delta=o,e.rating=function(n,e){return n>e[1]?"poor":n>e[0]?"needs-improvement":"good"}(e.value,t),n(e))}},f=function(n){requestAnimationFrame(function(){return requestAnimationFrame(function(){return n()})})},a=function(n){var e=function(e){"pagehide"!==e.type&&"hidden"!==document.visibilityState||n(e)};addEventListener("visibilitychange",e,!0),addEventListener("pagehide",e,!0)},d=function(n){var e=!1;return function(t){e||(n(t),e=!0)}},v=-1,s=function(){return"hidden"!==document.visibilityState||document.prerendering?1/0:0},l=function(n){"hidden"===document.visibilityState&&v>-1&&(v="visibilitychange"===n.type?n.timeStamp:0,h())},m=function(){addEventListener("visibilitychange",l,!0),addEventListener("prerenderingchange",l,!0)},h=function(){removeEventListener("visibilitychange",l,!0),removeEventListener("prerenderingchange",l,!0)},p=function(){return v<0&&(v=s(),m(),t(function(){setTimeout(function(){v=s(),m()},0)})),{get firstHiddenTime(){return v}}},g=function(n){document.prerendering?addEventListener("prerenderingchange",function(){return n()},!0):n()},T=[1800,3e3],L=function(n,e){e=e||{},g(function(){var i,a=p(),d=o("FCP"),v=u("paint",function(n){n.forEach(function(n){"first-contentful-paint"===n.name&&(v.disconnect(),n.startTime<a.firstHiddenTime&&(d.value=Math.max(n.startTime-r(),0),d.entries.push(n),i(!0)))})});v&&(i=c(n,d,T,e.reportAllChanges),t(function(t){d=o("FCP"),i=c(n,d,T,e.reportAllChanges),f(function(){d.value=performance.now()-t.timeStamp,i(!0)})}))})},w=[.1,.25],y=0,P=1/0,b=0,E=function(n){n.forEach(function(n){n.interactionId&&(P=Math.min(P,n.interactionId),b=Math.max(b,n.interactionId),y=b?(b-P)/7+1:0)})},C=function(){return n?y:performance.interactionCount||0},M=function(){"interactionCount"in performance||n||(n=u("event",E,{type:"event",buffered:!0,durationThreshold:0}))},F=[200,500],I=0,k=function(){return C()-I},B=[],N={},O=function(n){var e=B[B.length-1],t=N[n.interactionId];if(t||B.length<10||n.duration>e.latency){if(t)t.entries.push(n),t.latency=Math.max(t.latency,n.duration);else{var i={id:n.interactionId,latency:n.duration,entries:[n]};N[i.id]=i,B.push(i)}B.sort(function(n,e){return e.latency-n.latency}),B.splice(10).forEach(function(n){delete N[n.id]})}},S=[2500,4e3],q={},A=[800,1800],j=function n(e){document.prerendering?g(function(){return n(e)}):"complete"!==document.readyState?addEventListener("load",function(){return n(e)},!0):setTimeout(e,0)},D="undefined"!=typeof window?window:void 0,H="undefined"!=typeof globalThis?globalThis:D,_=null==H?void 0:H.navigator;null==H||H.document,null==H||H.location,null==H||H.fetch,(null==H?void 0:H.XMLHttpRequest)&&"withCredentials"in new H.XMLHttpRequest&&H.XMLHttpRequest,null==H||H.AbortController,null==_||_.userAgent;var x=null!=D?D:{},z={onLCP:function(n,e){e=e||{},g(function(){var i,v=p(),s=o("LCP"),l=function(n){var e=n[n.length-1];e&&e.startTime<v.firstHiddenTime&&(s.value=Math.max(e.startTime-r(),0),s.entries=[e],i())},m=u("largest-contentful-paint",l);if(m){i=c(n,s,S,e.reportAllChanges);var h=d(function(){q[s.id]||(l(m.takeRecords()),m.disconnect(),q[s.id]=!0,i(!0))});["keydown","click"].forEach(function(n){addEventListener(n,function(){return setTimeout(h,0)},!0)}),a(h),t(function(t){s=o("LCP"),i=c(n,s,S,e.reportAllChanges),f(function(){s.value=performance.now()-t.timeStamp,q[s.id]=!0,i(!0)})})}})},onCLS:function(n,e){e=e||{},L(d(function(){var i,r=o("CLS",0),d=0,v=[],s=function(n){n.forEach(function(n){if(!n.hadRecentInput){var e=v[0],t=v[v.length-1];d&&n.startTime-t.startTime<1e3&&n.startTime-e.startTime<5e3?(d+=n.value,v.push(n)):(d=n.value,v=[n])}}),d>r.value&&(r.value=d,r.entries=v,i())},l=u("layout-shift",s);l&&(i=c(n,r,w,e.reportAllChanges),a(function(){s(l.takeRecords()),i(!0)}),t(function(){d=0,r=o("CLS",0),i=c(n,r,w,e.reportAllChanges),f(function(){return i()})}),setTimeout(i,0))}))},onFCP:L,onINP:function(n,e){e=e||{},g(function(){var i;M();var r,f=o("INP"),d=function(n){n.forEach(function(n){n.interactionId&&O(n),"first-input"===n.entryType&&!B.some(function(e){return e.entries.some(function(e){return n.duration===e.duration&&n.startTime===e.startTime})})&&O(n)});var e,t=(e=Math.min(B.length-1,Math.floor(k()/50)),B[e]);t&&t.latency!==f.value&&(f.value=t.latency,f.entries=t.entries,r())},v=u("event",d,{durationThreshold:null!==(i=e.durationThreshold)&&void 0!==i?i:40});r=c(n,f,F,e.reportAllChanges),v&&("PerformanceEventTiming"in window&&"interactionId"in PerformanceEventTiming.prototype&&v.observe({type:"first-input",buffered:!0}),a(function(){d(v.takeRecords()),f.value<0&&k()>0&&(f.value=0,f.entries=[]),r(!0)}),t(function(){B=[],I=C(),f=o("INP"),r=c(n,f,F,e.reportAllChanges)}))})},onTTFB:function(n,e){e=e||{};var u=o("TTFB"),f=c(n,u,A,e.reportAllChanges);j(function(){var a=i();if(a){var d=a.responseStart;if(d<=0||d>performance.now())return;u.value=Math.max(d-r(),0),u.entries=[a],f(!0),t(function(){u=o("TTFB",0),(f=c(n,u,A,e.reportAllChanges))(!0)})}})}};x.__VTiltExtensions__=x.__VTiltExtensions__||{},x.__VTiltExtensions__.webVitalsCallbacks=z}();
2
+ //# sourceMappingURL=web-vitals.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"web-vitals.js","sources":["../../../../node_modules/.pnpm/web-vitals@3.5.2/node_modules/web-vitals/dist/web-vitals.js","../src/utils/globals.ts","../src/entrypoints/web-vitals.ts"],"sourcesContent":["var e,n,t,i,r,a=-1,o=function(e){addEventListener(\"pageshow\",(function(n){n.persisted&&(a=n.timeStamp,e(n))}),!0)},c=function(){return window.performance&&performance.getEntriesByType&&performance.getEntriesByType(\"navigation\")[0]},u=function(){var e=c();return e&&e.activationStart||0},f=function(e,n){var t=c(),i=\"navigate\";a>=0?i=\"back-forward-cache\":t&&(document.prerendering||u()>0?i=\"prerender\":document.wasDiscarded?i=\"restore\":t.type&&(i=t.type.replace(/_/g,\"-\")));return{name:e,value:void 0===n?-1:n,rating:\"good\",delta:0,entries:[],id:\"v3-\".concat(Date.now(),\"-\").concat(Math.floor(8999999999999*Math.random())+1e12),navigationType:i}},s=function(e,n,t){try{if(PerformanceObserver.supportedEntryTypes.includes(e)){var i=new PerformanceObserver((function(e){Promise.resolve().then((function(){n(e.getEntries())}))}));return i.observe(Object.assign({type:e,buffered:!0},t||{})),i}}catch(e){}},d=function(e,n,t,i){var r,a;return function(o){n.value>=0&&(o||i)&&((a=n.value-(r||0))||void 0===r)&&(r=n.value,n.delta=a,n.rating=function(e,n){return e>n[1]?\"poor\":e>n[0]?\"needs-improvement\":\"good\"}(n.value,t),e(n))}},l=function(e){requestAnimationFrame((function(){return requestAnimationFrame((function(){return e()}))}))},p=function(e){var n=function(n){\"pagehide\"!==n.type&&\"hidden\"!==document.visibilityState||e(n)};addEventListener(\"visibilitychange\",n,!0),addEventListener(\"pagehide\",n,!0)},v=function(e){var n=!1;return function(t){n||(e(t),n=!0)}},m=-1,h=function(){return\"hidden\"!==document.visibilityState||document.prerendering?1/0:0},g=function(e){\"hidden\"===document.visibilityState&&m>-1&&(m=\"visibilitychange\"===e.type?e.timeStamp:0,T())},y=function(){addEventListener(\"visibilitychange\",g,!0),addEventListener(\"prerenderingchange\",g,!0)},T=function(){removeEventListener(\"visibilitychange\",g,!0),removeEventListener(\"prerenderingchange\",g,!0)},E=function(){return m<0&&(m=h(),y(),o((function(){setTimeout((function(){m=h(),y()}),0)}))),{get firstHiddenTime(){return m}}},C=function(e){document.prerendering?addEventListener(\"prerenderingchange\",(function(){return e()}),!0):e()},L=[1800,3e3],w=function(e,n){n=n||{},C((function(){var t,i=E(),r=f(\"FCP\"),a=s(\"paint\",(function(e){e.forEach((function(e){\"first-contentful-paint\"===e.name&&(a.disconnect(),e.startTime<i.firstHiddenTime&&(r.value=Math.max(e.startTime-u(),0),r.entries.push(e),t(!0)))}))}));a&&(t=d(e,r,L,n.reportAllChanges),o((function(i){r=f(\"FCP\"),t=d(e,r,L,n.reportAllChanges),l((function(){r.value=performance.now()-i.timeStamp,t(!0)}))})))}))},b=[.1,.25],S=function(e,n){n=n||{},w(v((function(){var t,i=f(\"CLS\",0),r=0,a=[],c=function(e){e.forEach((function(e){if(!e.hadRecentInput){var n=a[0],t=a[a.length-1];r&&e.startTime-t.startTime<1e3&&e.startTime-n.startTime<5e3?(r+=e.value,a.push(e)):(r=e.value,a=[e])}})),r>i.value&&(i.value=r,i.entries=a,t())},u=s(\"layout-shift\",c);u&&(t=d(e,i,b,n.reportAllChanges),p((function(){c(u.takeRecords()),t(!0)})),o((function(){r=0,i=f(\"CLS\",0),t=d(e,i,b,n.reportAllChanges),l((function(){return t()}))})),setTimeout(t,0))})))},A={passive:!0,capture:!0},I=new Date,P=function(i,r){e||(e=r,n=i,t=new Date,k(removeEventListener),F())},F=function(){if(n>=0&&n<t-I){var r={entryType:\"first-input\",name:e.type,target:e.target,cancelable:e.cancelable,startTime:e.timeStamp,processingStart:e.timeStamp+n};i.forEach((function(e){e(r)})),i=[]}},M=function(e){if(e.cancelable){var n=(e.timeStamp>1e12?new Date:performance.now())-e.timeStamp;\"pointerdown\"==e.type?function(e,n){var t=function(){P(e,n),r()},i=function(){r()},r=function(){removeEventListener(\"pointerup\",t,A),removeEventListener(\"pointercancel\",i,A)};addEventListener(\"pointerup\",t,A),addEventListener(\"pointercancel\",i,A)}(n,e):P(n,e)}},k=function(e){[\"mousedown\",\"keydown\",\"touchstart\",\"pointerdown\"].forEach((function(n){return e(n,M,A)}))},D=[100,300],x=function(t,r){r=r||{},C((function(){var a,c=E(),u=f(\"FID\"),l=function(e){e.startTime<c.firstHiddenTime&&(u.value=e.processingStart-e.startTime,u.entries.push(e),a(!0))},m=function(e){e.forEach(l)},h=s(\"first-input\",m);a=d(t,u,D,r.reportAllChanges),h&&p(v((function(){m(h.takeRecords()),h.disconnect()}))),h&&o((function(){var o;u=f(\"FID\"),a=d(t,u,D,r.reportAllChanges),i=[],n=-1,e=null,k(addEventListener),o=l,i.push(o),F()}))}))},B=0,R=1/0,H=0,N=function(e){e.forEach((function(e){e.interactionId&&(R=Math.min(R,e.interactionId),H=Math.max(H,e.interactionId),B=H?(H-R)/7+1:0)}))},O=function(){return r?B:performance.interactionCount||0},q=function(){\"interactionCount\"in performance||r||(r=s(\"event\",N,{type:\"event\",buffered:!0,durationThreshold:0}))},j=[200,500],_=0,z=function(){return O()-_},G=[],J={},K=function(e){var n=G[G.length-1],t=J[e.interactionId];if(t||G.length<10||e.duration>n.latency){if(t)t.entries.push(e),t.latency=Math.max(t.latency,e.duration);else{var i={id:e.interactionId,latency:e.duration,entries:[e]};J[i.id]=i,G.push(i)}G.sort((function(e,n){return n.latency-e.latency})),G.splice(10).forEach((function(e){delete J[e.id]}))}},Q=function(e,n){n=n||{},C((function(){var t;q();var i,r=f(\"INP\"),a=function(e){e.forEach((function(e){(e.interactionId&&K(e),\"first-input\"===e.entryType)&&(!G.some((function(n){return n.entries.some((function(n){return e.duration===n.duration&&e.startTime===n.startTime}))}))&&K(e))}));var n,t=(n=Math.min(G.length-1,Math.floor(z()/50)),G[n]);t&&t.latency!==r.value&&(r.value=t.latency,r.entries=t.entries,i())},c=s(\"event\",a,{durationThreshold:null!==(t=n.durationThreshold)&&void 0!==t?t:40});i=d(e,r,j,n.reportAllChanges),c&&(\"PerformanceEventTiming\"in window&&\"interactionId\"in PerformanceEventTiming.prototype&&c.observe({type:\"first-input\",buffered:!0}),p((function(){a(c.takeRecords()),r.value<0&&z()>0&&(r.value=0,r.entries=[]),i(!0)})),o((function(){G=[],_=O(),r=f(\"INP\"),i=d(e,r,j,n.reportAllChanges)})))}))},U=[2500,4e3],V={},W=function(e,n){n=n||{},C((function(){var t,i=E(),r=f(\"LCP\"),a=function(e){var n=e[e.length-1];n&&n.startTime<i.firstHiddenTime&&(r.value=Math.max(n.startTime-u(),0),r.entries=[n],t())},c=s(\"largest-contentful-paint\",a);if(c){t=d(e,r,U,n.reportAllChanges);var m=v((function(){V[r.id]||(a(c.takeRecords()),c.disconnect(),V[r.id]=!0,t(!0))}));[\"keydown\",\"click\"].forEach((function(e){addEventListener(e,(function(){return setTimeout(m,0)}),!0)})),p(m),o((function(i){r=f(\"LCP\"),t=d(e,r,U,n.reportAllChanges),l((function(){r.value=performance.now()-i.timeStamp,V[r.id]=!0,t(!0)}))}))}}))},X=[800,1800],Y=function e(n){document.prerendering?C((function(){return e(n)})):\"complete\"!==document.readyState?addEventListener(\"load\",(function(){return e(n)}),!0):setTimeout(n,0)},Z=function(e,n){n=n||{};var t=f(\"TTFB\"),i=d(e,t,X,n.reportAllChanges);Y((function(){var r=c();if(r){var a=r.responseStart;if(a<=0||a>performance.now())return;t.value=Math.max(a-u(),0),t.entries=[r],i(!0),o((function(){t=f(\"TTFB\",0),(i=d(e,t,X,n.reportAllChanges))(!0)}))}}))};export{b as CLSThresholds,L as FCPThresholds,D as FIDThresholds,j as INPThresholds,U as LCPThresholds,X as TTFBThresholds,S as getCLS,w as getFCP,x as getFID,Q as getINP,W as getLCP,Z as getTTFB,S as onCLS,w as onFCP,x as onFID,Q as onINP,W as onLCP,Z as onTTFB};\n",null,null],"names":["r","a","o","e","addEventListener","n","persisted","timeStamp","c","window","performance","getEntriesByType","u","activationStart","f","t","i","document","prerendering","wasDiscarded","type","replace","name","value","rating","delta","entries","id","concat","Date","now","Math","floor","random","navigationType","s","PerformanceObserver","supportedEntryTypes","includes","Promise","resolve","then","getEntries","observe","Object","assign","buffered","d","l","requestAnimationFrame","p","visibilityState","v","m","h","g","T","y","removeEventListener","E","setTimeout","firstHiddenTime","C","L","w","forEach","disconnect","startTime","max","push","reportAllChanges","b","B","R","H","N","interactionId","min","O","interactionCount","q","durationThreshold","j","_","z","G","J","K","length","duration","latency","sort","splice","U","V","X","Y","readyState","win","undefined","global","globalThis","navigator","location","fetch","XMLHttpRequest","AbortController","userAgent","assignableWindow","vtiltWebVitalsCallbacks","takeRecords","hadRecentInput","onFCP","entryType","some","PerformanceEventTiming","prototype","onTTFB","responseStart","__VTiltExtensions__","webVitalsCallbacks"],"mappings":"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","x_google_ignoreList":[0]}
package/lib/config.js CHANGED
@@ -39,9 +39,11 @@ class ConfigManager {
39
39
  script.getAttribute("data-storage") || initialConfig.storage;
40
40
  config.stringifyPayload =
41
41
  script.getAttribute("data-stringify-payload") !== "false";
42
- config.capture_performance =
43
- script.getAttribute("data-capture-performance") === "true" ||
44
- initialConfig.capture_performance;
42
+ // Handle capture_performance: data attribute is boolean, initialConfig can be boolean or object
43
+ const dataAttrPerformance = script.getAttribute("data-capture-performance") === "true";
44
+ config.capture_performance = dataAttrPerformance
45
+ ? true
46
+ : initialConfig.capture_performance;
45
47
  // Check for conflicting proxy configurations
46
48
  if (config.proxy && config.proxyUrl) {
47
49
  console.error("Error: Both data-proxy and data-proxy-url are specified. Please use only one of them.");
@@ -0,0 +1,8 @@
1
+ /**
2
+ * All External Dependencies
3
+ *
4
+ * This file imports all external dependency entrypoints.
5
+ * Used by array.full.ts for the full bundle that includes everything.
6
+ */
7
+ import "./recorder";
8
+ import "./web-vitals";
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ /**
3
+ * All External Dependencies
4
+ *
5
+ * This file imports all external dependency entrypoints.
6
+ * Used by array.full.ts for the full bundle that includes everything.
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ require("./recorder");
10
+ require("./web-vitals");
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Full Bundle Entrypoint
3
+ *
4
+ * Same as array.ts but includes all external dependencies bundled in.
5
+ * This is useful for users who want a single script tag without lazy loading.
6
+ *
7
+ * Usage:
8
+ * <script src="https://cdn.example.com/dist/array.full.js"></script>
9
+ *
10
+ * This bundle includes:
11
+ * - Core SDK (array.no-external.ts)
12
+ * - External scripts loader
13
+ * - Session recording (rrweb)
14
+ * - Web Vitals tracking
15
+ */
16
+ import "./all-external-dependencies";
17
+ import "./array";
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ /**
3
+ * Full Bundle Entrypoint
4
+ *
5
+ * Same as array.ts but includes all external dependencies bundled in.
6
+ * This is useful for users who want a single script tag without lazy loading.
7
+ *
8
+ * Usage:
9
+ * <script src="https://cdn.example.com/dist/array.full.js"></script>
10
+ *
11
+ * This bundle includes:
12
+ * - Core SDK (array.no-external.ts)
13
+ * - External scripts loader
14
+ * - Session recording (rrweb)
15
+ * - Web Vitals tracking
16
+ */
17
+ Object.defineProperty(exports, "__esModule", { value: true });
18
+ require("./all-external-dependencies");
19
+ require("./array");
@@ -72,7 +72,7 @@ exports.loadScript = loadScript;
72
72
  /**
73
73
  * SDK version - used for loading correct script version from CDN
74
74
  */
75
- const SDK_VERSION = "1.1.5";
75
+ const SDK_VERSION = "1.3.0";
76
76
  /**
77
77
  * Get the URL for an extension script
78
78
  *
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Web Vitals Extension Entrypoint
3
+ *
4
+ * This file imports the web-vitals library and registers its callbacks
5
+ * on the global __VTiltExtensions__ object. The main SDK checks for these
6
+ * callbacks and uses them if available.
7
+ *
8
+ * Usage:
9
+ * - Include this entrypoint in the full bundle (array.full.ts)
10
+ * - Or load it dynamically via loadExternalDependency('web-vitals', callback)
11
+ */
12
+ import { WebVitalsCallbacks } from "../utils/globals";
13
+ declare const vtiltWebVitalsCallbacks: WebVitalsCallbacks;
14
+ export default vtiltWebVitalsCallbacks;
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+ /**
3
+ * Web Vitals Extension Entrypoint
4
+ *
5
+ * This file imports the web-vitals library and registers its callbacks
6
+ * on the global __VTiltExtensions__ object. The main SDK checks for these
7
+ * callbacks and uses them if available.
8
+ *
9
+ * Usage:
10
+ * - Include this entrypoint in the full bundle (array.full.ts)
11
+ * - Or load it dynamically via loadExternalDependency('web-vitals', callback)
12
+ */
13
+ Object.defineProperty(exports, "__esModule", { value: true });
14
+ const web_vitals_1 = require("web-vitals");
15
+ const globals_1 = require("../utils/globals");
16
+ const vtiltWebVitalsCallbacks = {
17
+ onLCP: web_vitals_1.onLCP,
18
+ onCLS: web_vitals_1.onCLS,
19
+ onFCP: web_vitals_1.onFCP,
20
+ onINP: web_vitals_1.onINP,
21
+ onTTFB: web_vitals_1.onTTFB,
22
+ };
23
+ // Initialize extensions object if not exists
24
+ globals_1.assignableWindow.__VTiltExtensions__ =
25
+ globals_1.assignableWindow.__VTiltExtensions__ || {};
26
+ // Register web vitals callbacks
27
+ globals_1.assignableWindow.__VTiltExtensions__.webVitalsCallbacks =
28
+ vtiltWebVitalsCallbacks;
29
+ exports.default = vtiltWebVitalsCallbacks;
package/lib/types.d.ts CHANGED
@@ -51,8 +51,11 @@ export interface VTiltConfig {
51
51
  person_profiles?: PersonProfilesMode;
52
52
  /** Enable autocapture */
53
53
  autocapture?: boolean;
54
- /** Enable web vitals tracking */
55
- capture_performance?: boolean;
54
+ /**
55
+ * Enable web vitals tracking.
56
+ * Can be a boolean or an object with detailed configuration.
57
+ */
58
+ capture_performance?: boolean | CapturePerformanceConfig;
56
59
  /** Enable page view tracking */
57
60
  capture_pageview?: boolean | "auto";
58
61
  /** Enable page leave tracking */
@@ -160,6 +163,29 @@ export interface AliasEvent {
160
163
  distinct_id: string;
161
164
  original: string;
162
165
  }
166
+ /** Supported Web Vitals metrics */
167
+ export type SupportedWebVitalsMetric = "LCP" | "CLS" | "FCP" | "INP" | "TTFB";
168
+ /** All supported Web Vitals metrics */
169
+ export declare const ALL_WEB_VITALS_METRICS: SupportedWebVitalsMetric[];
170
+ /** Default Web Vitals metrics (matches PostHog defaults) */
171
+ export declare const DEFAULT_WEB_VITALS_METRICS: SupportedWebVitalsMetric[];
172
+ /**
173
+ * Web Vitals capture configuration
174
+ */
175
+ export interface CapturePerformanceConfig {
176
+ /** Enable or disable web vitals capture */
177
+ web_vitals?: boolean;
178
+ /** Which metrics to capture (default: LCP, CLS, FCP, INP) */
179
+ web_vitals_allowed_metrics?: SupportedWebVitalsMetric[];
180
+ /** Delay before flushing metrics in ms (default: 5000) */
181
+ web_vitals_delayed_flush_ms?: number;
182
+ /**
183
+ * Maximum allowed metric value in ms (default: 900000 = 15 minutes)
184
+ * Values above this are considered anomalies and ignored.
185
+ * Set to 0 to disable this check.
186
+ */
187
+ __web_vitals_max_value?: number;
188
+ }
163
189
  export interface WebVitalMetric {
164
190
  name: string;
165
191
  value: number;
@@ -167,6 +193,10 @@ export interface WebVitalMetric {
167
193
  rating: "good" | "needs-improvement" | "poor";
168
194
  id: string;
169
195
  navigationType: string;
196
+ /** Timestamp when the metric was captured (added internally) */
197
+ timestamp?: number;
198
+ /** Attribution data from web-vitals library */
199
+ attribution?: Record<string, unknown>;
170
200
  }
171
201
  export interface GeolocationData {
172
202
  country?: string;
package/lib/types.js CHANGED
@@ -6,3 +6,19 @@
6
6
  * Following PostHog's patterns where applicable.
7
7
  */
8
8
  Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.DEFAULT_WEB_VITALS_METRICS = exports.ALL_WEB_VITALS_METRICS = void 0;
10
+ /** All supported Web Vitals metrics */
11
+ exports.ALL_WEB_VITALS_METRICS = [
12
+ "LCP",
13
+ "CLS",
14
+ "FCP",
15
+ "INP",
16
+ "TTFB",
17
+ ];
18
+ /** Default Web Vitals metrics (matches PostHog defaults) */
19
+ exports.DEFAULT_WEB_VITALS_METRICS = [
20
+ "LCP",
21
+ "CLS",
22
+ "FCP",
23
+ "INP",
24
+ ];
@@ -17,6 +17,31 @@ export interface LazyLoadedSessionRecordingInterface {
17
17
  log: (message: string, level: "log" | "warn" | "error") => void;
18
18
  updateConfig: (config: any) => void;
19
19
  }
20
+ /**
21
+ * Web Vitals metric callback type
22
+ */
23
+ export type WebVitalsMetricCallback = (metric: any) => void;
24
+ /**
25
+ * Options for web vitals callbacks
26
+ */
27
+ export interface WebVitalsCallbackOptions {
28
+ /** Report all changes (useful for CLS which updates over time) */
29
+ reportAllChanges?: boolean;
30
+ }
31
+ /**
32
+ * Web Vitals callback function type (with optional options)
33
+ */
34
+ export type WebVitalsCallbackFn = (callback: WebVitalsMetricCallback, options?: WebVitalsCallbackOptions) => void;
35
+ /**
36
+ * Web Vitals callbacks interface (set by web-vitals.ts entrypoint)
37
+ */
38
+ export interface WebVitalsCallbacks {
39
+ onLCP: WebVitalsCallbackFn;
40
+ onCLS: WebVitalsCallbackFn;
41
+ onFCP: WebVitalsCallbackFn;
42
+ onINP: WebVitalsCallbackFn;
43
+ onTTFB?: WebVitalsCallbackFn;
44
+ }
20
45
  /**
21
46
  * VTilt Extensions interface for dynamically loaded modules
22
47
  * This is the contract between lazily loaded extensions and the SDK
@@ -37,6 +62,8 @@ export interface VTiltExtensions {
37
62
  };
38
63
  /** Factory to create LazyLoadedSessionRecording (set by recorder.ts) */
39
64
  initSessionRecording?: (instance: any, config?: any) => LazyLoadedSessionRecordingInterface;
65
+ /** Web Vitals callbacks (set by web-vitals.ts entrypoint) */
66
+ webVitalsCallbacks?: WebVitalsCallbacks;
40
67
  }
41
68
  export type AssignableWindow = Window & typeof globalThis & {
42
69
  /** Main VTilt instance */
@@ -1,11 +1,95 @@
1
- import { VTiltConfig } from "./types";
1
+ import { VTiltConfig, SupportedWebVitalsMetric } from "./types";
2
2
  import { VTilt } from "./vtilt";
3
+ /**
4
+ * Web Vitals Manager
5
+ *
6
+ * Captures Core Web Vitals (LCP, CLS, FCP, INP, TTFB) and sends them
7
+ * as batched $web_vitals events. Follows PostHog's approach with:
8
+ *
9
+ * 1. Extension pattern - checks for callbacks registered on __VTiltExtensions__
10
+ * 2. Lazy loading - loads web-vitals.js on demand if not bundled
11
+ * 3. Configurable metrics - choose which metrics to capture
12
+ * 4. Smart buffering - collects metrics per page, flushes on navigation or timeout
13
+ * 5. Session context - includes session_id and window_id for correlation
14
+ *
15
+ * Event structure:
16
+ * - event: "$web_vitals"
17
+ * - properties:
18
+ * - $web_vitals_LCP_value: number
19
+ * - $web_vitals_LCP_event: { name, value, delta, rating, ... }
20
+ * - $pathname: string
21
+ * - $current_url: string
22
+ */
3
23
  export declare class WebVitalsManager {
4
24
  private instance;
5
- private webVitals;
6
- constructor(config: VTiltConfig, instance: VTilt);
25
+ private buffer;
26
+ private flushTimer;
27
+ private initialized;
28
+ private config;
29
+ constructor(vtiltConfig: VTiltConfig, instance: VTilt);
7
30
  /**
8
- * Initialize web vitals tracking
31
+ * Parse capture_performance config (boolean or object)
9
32
  */
10
- private initializeWebVitals;
33
+ private parseConfig;
34
+ /**
35
+ * Check if web vitals capture is enabled
36
+ */
37
+ get isEnabled(): boolean;
38
+ /**
39
+ * Get the list of metrics to capture
40
+ */
41
+ get allowedMetrics(): SupportedWebVitalsMetric[];
42
+ /**
43
+ * Get flush timeout in ms
44
+ */
45
+ get flushTimeoutMs(): number;
46
+ /**
47
+ * Get maximum allowed metric value
48
+ */
49
+ get maxAllowedValue(): number;
50
+ private createEmptyBuffer;
51
+ /**
52
+ * Check if web vitals callbacks are available
53
+ */
54
+ private getWebVitalsCallbacks;
55
+ /**
56
+ * Start capturing if enabled and callbacks are available
57
+ */
58
+ startIfEnabled(): void;
59
+ /**
60
+ * Lazy load web-vitals extension
61
+ */
62
+ private loadWebVitals;
63
+ /**
64
+ * Start capturing web vitals using the provided callbacks
65
+ */
66
+ private startCapturing;
67
+ /**
68
+ * Get current URL
69
+ */
70
+ private getCurrentUrl;
71
+ /**
72
+ * Get current pathname
73
+ */
74
+ private getCurrentPathname;
75
+ /**
76
+ * Add a metric to the buffer
77
+ */
78
+ private addToBuffer;
79
+ /**
80
+ * Clean attribution data by removing large elements
81
+ */
82
+ private cleanAttribution;
83
+ /**
84
+ * Get window ID from instance
85
+ */
86
+ private getWindowId;
87
+ /**
88
+ * Schedule a delayed flush
89
+ */
90
+ private scheduleFlush;
91
+ /**
92
+ * Flush buffered metrics as a single event
93
+ */
94
+ private flush;
11
95
  }