// Analytics utilities for Umami with Performance Tracking declare global { interface Window { umami?: { track: (event: string, data?: Record) => void; }; } } export interface PerformanceMetric { name: string; value: number; url: string; timestamp: number; userAgent?: string; } export interface WebVitalsMetric { name: 'CLS' | 'FID' | 'FCP' | 'LCP' | 'TTFB'; value: number; delta: number; id: string; url: string; } // Track custom events to Umami export const trackEvent = (event: string, data?: Record) => { if (typeof window !== 'undefined' && window.umami) { window.umami.track(event, { ...data, timestamp: Date.now(), url: window.location.pathname, }); } }; // Track performance metrics export const trackPerformance = (metric: PerformanceMetric) => { trackEvent('performance', { metric: metric.name, value: Math.round(metric.value), url: metric.url, userAgent: metric.userAgent, }); }; // Track Web Vitals export const trackWebVitals = (metric: WebVitalsMetric) => { trackEvent('web-vitals', { name: metric.name, value: Math.round(metric.value), delta: Math.round(metric.delta), id: metric.id, url: metric.url, }); }; // Track page load performance export const trackPageLoad = () => { if (typeof window === 'undefined' || typeof performance === 'undefined') return; try { const navigationEntries = performance.getEntriesByType('navigation'); const navigation = navigationEntries[0] as PerformanceNavigationTiming | undefined; if (navigation && navigation.loadEventEnd && navigation.fetchStart) { trackPerformance({ name: 'page-load', value: navigation.loadEventEnd - navigation.fetchStart, url: window.location.pathname, timestamp: Date.now(), userAgent: navigator.userAgent, }); // Track individual timing phases trackEvent('page-timing', { dns: navigation.domainLookupEnd && navigation.domainLookupStart ? Math.round(navigation.domainLookupEnd - navigation.domainLookupStart) : 0, tcp: navigation.connectEnd && navigation.connectStart ? Math.round(navigation.connectEnd - navigation.connectStart) : 0, request: navigation.responseStart && navigation.requestStart ? Math.round(navigation.responseStart - navigation.requestStart) : 0, response: navigation.responseEnd && navigation.responseStart ? Math.round(navigation.responseEnd - navigation.responseStart) : 0, dom: navigation.domContentLoadedEventEnd && navigation.responseEnd ? Math.round(navigation.domContentLoadedEventEnd - navigation.responseEnd) : 0, load: navigation.loadEventEnd && navigation.domContentLoadedEventEnd ? Math.round(navigation.loadEventEnd - navigation.domContentLoadedEventEnd) : 0, url: window.location.pathname, }); } } catch (error) { // Silently fail - performance tracking is not critical if (process.env.NODE_ENV === 'development') { console.warn('Error tracking page load:', error); } } }; // Track API response times export const trackApiCall = (endpoint: string, duration: number, status: number) => { if (typeof window === 'undefined') return; trackEvent('api-call', { endpoint, duration: Math.round(duration), status, url: window.location.pathname, }); }; // Track user interactions export const trackInteraction = (action: string, element?: string) => { if (typeof window === 'undefined') return; trackEvent('interaction', { action, element, url: window.location.pathname, }); }; // Track errors export const trackError = (error: string, context?: string) => { if (typeof window === 'undefined') return; trackEvent('error', { error, context, url: window.location.pathname, }); };