feat: add Core Web Vitals reporting to PostHog
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
35
frontend/src/lib/webVitals.ts
Normal file
35
frontend/src/lib/webVitals.ts
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
/**
|
||||||
|
* Core Web Vitals reporting via PostHog.
|
||||||
|
*
|
||||||
|
* Tracks LCP, INP, CLS, FCP, and TTFB as PostHog events so we can
|
||||||
|
* build dashboards and correlate performance with product usage.
|
||||||
|
*
|
||||||
|
* Each metric fires once per page load. PostHog captures 100% of
|
||||||
|
* sessions (vs Sentry's 20% sample), giving better coverage.
|
||||||
|
*/
|
||||||
|
import { onLCP, onINP, onCLS, onFCP, onTTFB } from 'web-vitals'
|
||||||
|
import type { Metric } from 'web-vitals'
|
||||||
|
import posthog from 'posthog-js'
|
||||||
|
|
||||||
|
function sendToPostHog(metric: Metric) {
|
||||||
|
// Only send if PostHog is loaded
|
||||||
|
if (!(posthog as unknown as { __loaded?: boolean }).__loaded) return
|
||||||
|
|
||||||
|
posthog.capture('web_vitals', {
|
||||||
|
metric_name: metric.name,
|
||||||
|
metric_value: metric.value,
|
||||||
|
metric_rating: metric.rating,
|
||||||
|
metric_delta: metric.delta,
|
||||||
|
metric_id: metric.id,
|
||||||
|
page_path: window.location.pathname,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Register all Web Vitals observers. Call once after PostHog init. */
|
||||||
|
export function initWebVitals() {
|
||||||
|
onLCP(sendToPostHog)
|
||||||
|
onINP(sendToPostHog)
|
||||||
|
onCLS(sendToPostHog)
|
||||||
|
onFCP(sendToPostHog)
|
||||||
|
onTTFB(sendToPostHog)
|
||||||
|
}
|
||||||
@@ -6,6 +6,7 @@ import { createRoot } from 'react-dom/client'
|
|||||||
import { reactErrorHandler } from '@sentry/react'
|
import { reactErrorHandler } from '@sentry/react'
|
||||||
import { HelmetProvider } from 'react-helmet-async'
|
import { HelmetProvider } from 'react-helmet-async'
|
||||||
import { PostHogProvider } from '@posthog/react'
|
import { PostHogProvider } from '@posthog/react'
|
||||||
|
import { initWebVitals } from './lib/webVitals'
|
||||||
import { Toaster } from 'sonner'
|
import { Toaster } from 'sonner'
|
||||||
import './index.css'
|
import './index.css'
|
||||||
import App from './App'
|
import App from './App'
|
||||||
@@ -22,6 +23,9 @@ if (posthogKey) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Start Web Vitals reporting to PostHog
|
||||||
|
initWebVitals()
|
||||||
|
|
||||||
createRoot(document.getElementById('root')!, {
|
createRoot(document.getElementById('root')!, {
|
||||||
onUncaughtError: reactErrorHandler(),
|
onUncaughtError: reactErrorHandler(),
|
||||||
onCaughtError: reactErrorHandler(),
|
onCaughtError: reactErrorHandler(),
|
||||||
|
|||||||
Reference in New Issue
Block a user