From abfb710c4be8d808ace32a4151128debe084e281 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Wed, 14 Jan 2026 02:09:22 +0000 Subject: [PATCH] Fix: guard Umami tracking and web vitals performance APIs Avoid calling undefined umami.track, add safe checks for Performance APIs, and clean up load listeners to prevent .call() crashes in Chrome. --- components/AnalyticsProvider.tsx | 6 ++++++ lib/analytics.ts | 13 +++++++++++-- lib/useWebVitals.ts | 11 +++++++++-- 3 files changed, 26 insertions(+), 4 deletions(-) diff --git a/components/AnalyticsProvider.tsx b/components/AnalyticsProvider.tsx index da56620..52e5bd6 100644 --- a/components/AnalyticsProvider.tsx +++ b/components/AnalyticsProvider.tsx @@ -69,6 +69,10 @@ export const AnalyticsProvider: React.FC = ({ children } // Track performance metrics to our API const trackPerformanceToAPI = async () => { try { + if (typeof performance === "undefined" || typeof performance.getEntriesByType !== "function") { + return; + } + // Get current page path to extract project ID if on project page const path = window.location.pathname; const projectMatch = path.match(/\/projects\/([^\/]+)/); @@ -266,6 +270,8 @@ export const AnalyticsProvider: React.FC = ({ children } // Cleanup return () => { try { + // Remove load handler if we added it + window.removeEventListener('load', trackPerformanceToAPI); window.removeEventListener('popstate', handleRouteChange); document.removeEventListener('click', handleClick); document.removeEventListener('submit', handleSubmit); diff --git a/lib/analytics.ts b/lib/analytics.ts index e6975b9..35eba8c 100644 --- a/lib/analytics.ts +++ b/lib/analytics.ts @@ -25,12 +25,21 @@ export interface WebVitalsMetric { // Track custom events to Umami export const trackEvent = (event: string, data?: Record) => { - if (typeof window !== 'undefined' && window.umami) { - window.umami.track(event, { + if (typeof window === "undefined") return; + const trackFn = window.umami?.track; + if (typeof trackFn !== "function") return; + + try { + trackFn(event, { ...data, timestamp: Date.now(), url: window.location.pathname, }); + } catch (error) { + // Silently fail - analytics must never break the app + if (process.env.NODE_ENV === "development") { + console.warn("Error tracking Umami event:", error); + } } }; diff --git a/lib/useWebVitals.ts b/lib/useWebVitals.ts index 072ba11..b60bfee 100644 --- a/lib/useWebVitals.ts +++ b/lib/useWebVitals.ts @@ -208,6 +208,13 @@ export const useWebVitals = () => { // Wrap everything in try-catch to prevent errors from breaking the app try { + const safeNow = () => { + if (typeof performance !== "undefined" && typeof performance.now === "function") { + return performance.now(); + } + return Date.now(); + }; + // Store web vitals for batch sending const webVitals: Record = {}; const path = window.location.pathname; @@ -233,7 +240,7 @@ export const useWebVitals = () => { cls: webVitals.CLS || 0, fid: webVitals.FID || 0, ttfb: webVitals.TTFB || 0, - loadTime: performance.now() + loadTime: safeNow() } }) }); @@ -307,7 +314,7 @@ export const useWebVitals = () => { setTimeout(() => { trackPerformance({ name: 'page-load-complete', - value: performance.now(), + value: safeNow(), url: window.location.pathname, timestamp: Date.now(), userAgent: navigator.userAgent,