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:
2026-03-18 02:41:43 +00:00
parent b1d1aef702
commit 9b3b82882e
2 changed files with 39 additions and 0 deletions

View 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)
}

View File

@@ -6,6 +6,7 @@ import { createRoot } from 'react-dom/client'
import { reactErrorHandler } from '@sentry/react'
import { HelmetProvider } from 'react-helmet-async'
import { PostHogProvider } from '@posthog/react'
import { initWebVitals } from './lib/webVitals'
import { Toaster } from 'sonner'
import './index.css'
import App from './App'
@@ -22,6 +23,9 @@ if (posthogKey) {
})
}
// Start Web Vitals reporting to PostHog
initWebVitals()
createRoot(document.getElementById('root')!, {
onUncaughtError: reactErrorHandler(),
onCaughtError: reactErrorHandler(),