Skip to content

Frontend Performance Monitoring: AI-Driven Auto Optimization

Traditional performance monitoring relies on manual investigation after problems are found. In 2025, AI can not only detect issues but also automatically suggest—and even automatically apply—fixes.

Monitoring Architecture

User Browser
    │
    ▼
┌─────────────┐     ┌─────────────┐     ┌─────────────┐
│  Collection │────▶│  AI Engine  │────▶│  Auto Fix   │
│  (web-vitals)│     │  (Claude)    │     │  (PR/config)│
└─────────────┘     └─────────────┘     └─────────────┘
    │                      │                    │
    ▼                      ▼                    ▼
  Raw Metrics       Perf Report + Diagnosis  Auto Fix PR

Data Collection

ts
// lib/performance-monitor.ts
import { onLCP, onINP, onCLS, onTTFB, type Metric } from "web-vitals";

interface PerformanceEntry extends Metric {
  url: string;
  userAgent: string;
  connectionType: string;
  deviceMemory: number;
  timestamp: number;
}

function collectVitals() {
  const baseData = {
    url: window.location.href,
    userAgent: navigator.userAgent,
    connectionType: (navigator as any).connection?.effectiveType ?? "unknown",
    deviceMemory: (navigator as any).deviceMemory ?? 0,
    timestamp: Date.now(),
  };

  const report = (metric: Metric) => {
    const entry: PerformanceEntry = { ...metric, ...baseData };

    // Report to analytics platform
    fetch("/api/vitals", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify(entry),
      // Use sendBeacon to ensure delivery on page close
      keepalive: true,
    }).catch(() => {
      navigator.sendBeacon?.("/api/vitals", JSON.stringify(entry));
    });

    // Alert immediately when performance is poor
    if (entry.rating === "poor") {
      console.warn(`[Performance] ${entry.name} = ${entry.value} (${entry.rating})`);
    }
  };

  onLCP(report);
  onINP(report);
  onCLS(report);
  onTTFB(report);
}

// Re-collect on route change (SPA scenario)
let lastPath = window.location.pathname;
new PerformanceObserver(() => {
  if (window.location.pathname !== lastPath) {
    lastPath = window.location.pathname;
    collectVitals();
  }
}).observe({ type: "navigation", buffered: true });

AI Analysis Engine

ts
// scripts/performance-analyzer.ts
import Anthropic from "@anthropic-ai/sdk";

const client = new Anthropic();

interface PerfReport {
  page: string;
  metrics: {
    lcp: { p50: number; p75: number; p95: number };
    inp: { p50: number; p75: number; p95: number };
    cls: { p50: number; p75: number; p95: number };
    ttfb: { p50: number; p75: number; p95: number };
  };
  trend: "improving" | "stable" | "degrading";
  regressions: string[];
}

async function analyzePerformance(report: PerfReport) {
  const response = await client.messages.create({
    model: "claude-sonnet-4-20250514",
    max_tokens: 4096,
    system: `You are a frontend performance expert. Analyze performance data and provide specific, actionable optimization suggestions.
Output JSON format:
{
  "diagnosis": "problem diagnosis",
  "rootCauses": ["cause1", "cause2"],
  "suggestions": [
    {
      "priority": "high|medium|low",
      "action": "specific action",
      "estimatedImpact": "expected improvement",
      "codeExample": "code example (optional)"
    }
  ]
}`,
    messages: [
      {
        role: "user",
        content: `Analyze the following page performance data:

Page: ${report.page}
Trend: ${report.trend}
Regressions: ${report.regressions.join(", ")}

LCP: P50=${report.metrics.lcp.p50}ms, P75=${report.metrics.lcp.p75}ms, P95=${report.metrics.lcp.p95}ms
INP: P50=${report.metrics.inp.p50}ms, P75=${report.metrics.inp.p75}ms, P95=${report.metrics.inp.p95}ms
CLS: P50=${report.metrics.cls.p50}, P75=${report.metrics.cls.p75}, P95=${report.metrics.cls.p95}
TTFB: P50=${report.metrics.ttfb.p50}ms, P75=${report.metrics.ttfb.p75}ms, P95=${report.metrics.ttfb.p95}ms

Core Web Vitals thresholds: LCP<2.5s, INP<200ms, CLS<0.1`,
      },
    ],
  });

  return JSON.parse(response.content[0].type === "text" ? response.content[0].text : "{}");
}

Auto Optimization Suggestions

tsx
// AI-generated actual optimization suggestions example

// Diagnosis: LCP P75 = 4.2s, exceeds threshold
// Root causes: Hero image not preloaded, fonts blocking render

// Suggestion 1: Preload critical resources
// app/layout.tsx
export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html>
      <head>
        {/* preload LCP image */}
        <link
          rel="preload"
          as="image"
          href="/hero-banner.webp"
          fetchPriority="high"
        />
        {/* preload critical font */}
        <link
          rel="preload"
          as="font"
          href="/fonts/inter-var.woff2"
          type="font/woff2"
          crossOrigin="anonymous"
        />
      </head>
      <body>{children}</body>
    </html>
  );
}

// Suggestion 2: Image optimization
// components/HeroBanner.tsx
import Image from "next/image";

export function HeroBanner() {
  return (
    <Image
      src="/hero-banner.webp"
      width={1920}
      height={800}
      priority  // auto preload + fetchPriority="high"
      sizes="100vw"
      alt="Hero banner"
      // auto-generates srcset, loads appropriate size on demand
    />
  );
}

// Suggestion 3: Font optimization
// Use font-display: swap to avoid font blocking
@font-face {
  font-family: "Inter";
  src: url("/fonts/inter-var.woff2") format("woff2");
  font-display: swap;  // use system font first, swap when loaded
}

Regression Detection

ts
// Automatic performance regression alerting
function checkRegression(current: PerfReport, baseline: PerfReport) {
  const regressions: string[] = [];
  const THRESHOLD = 0.2; // 20%+ counts as regression

  for (const metric of ["lcp", "inp", "cls", "ttfb"] as const) {
    const currentP75 = current.metrics[metric].p75;
    const baselineP75 = baseline.metrics[metric].p75;
    const change = (currentP75 - baselineP75) / baselineP75;

    if (change > THRESHOLD) {
      regressions.push(
        `${metric.toUpperCase()} P75 rose from ${baselineP75} to ${currentP75} (+${(change * 100).toFixed(1)}%)`,
      );
    }
  }

  if (regressions.length > 0) {
    // Auto-create Issue or send alert
    notifyTeam({
      title: "Performance Regression Alert",
      body: regressions.join("\n"),
      severity: regressions.length > 2 ? "critical" : "warning",
    });
  }
}

Summary

  • Performance monitoring must collect Real User Monitoring (RUM) data, not just lab data
  • AI can analyze performance data and provide specific, actionable optimization suggestions
  • Automatic regression detection alerts when production performance degrades
  • Performance optimization is an ongoing process, not a one-time task
  • Add performance metrics to CI gates to prevent regressions

MIT Licensed