Skip to content

PerformanceObservation

PerformanceObservation holds performance and Core Web Vitals data from two sources: field data from the CrUX (Chrome User Experience Report) connector, and lab data from Lighthouse when a rendered crawl is triggered. Comparing the two is a first-class finding type.

interface PerformanceObservation {
url: string;
projectId: string;
observedAt: string;
// CrUX field data (from Chrome users in the real world)
cruxLcp75thMs: number | null; // 75th percentile LCP in ms
cruxInp75thMs: number | null; // 75th percentile INP in ms (replaced FID)
cruxCls75th: number | null; // 75th percentile CLS score (unitless)
cruxFcp75thMs: number | null; // 75th percentile FCP in ms
cruxTtfb75thMs: number | null; // 75th percentile TTFB in ms
cruxLcpRating: 'good' | 'needs_improvement' | 'poor' | null;
cruxInpRating: 'good' | 'needs_improvement' | 'poor' | null;
cruxClsRating: 'good' | 'needs_improvement' | 'poor' | null;
cruxDeviceType: 'phone' | 'desktop' | 'tablet';
cruxObservationDate: string | null; // ISO date of CrUX data
cruxDataLevel: 'url' | 'origin'; // URL-level or origin-level fallback
// Lighthouse lab data (from controlled test environment)
lighthouseLcpMs: number | null;
lighthouseInpMs: number | null;
lighthouseCls: number | null;
lighthouseFcpMs: number | null;
lighthouseTtfbMs: number | null;
lighthouseScore: number | null; // overall performance score 0-100
lighthouseRunAt: string | null;
// Field vs lab discrepancy
fieldLabLcpDeltaMs: number | null; // CrUX - Lighthouse (positive = field worse)
fieldLabDiscrepancyFlag: boolean; // field significantly worse than lab
}
MetricGoodNeeds ImprovementPoor
LCP≤ 2,500ms2,500–4,000ms> 4,000ms
INP≤ 200ms200–500ms> 500ms
CLS≤ 0.10.1–0.25> 0.25

These are Google’s thresholds. VisibilityIQ uses these exactly for rating assignments.

A fieldLabDiscrepancyFlag = true is set when CrUX LCP exceeds Lighthouse LCP by more than 1,000ms (1 second). This is a meaningful signal because:

  • Lab tests run under controlled conditions with no third-party scripts, no browser extensions, no network contention
  • If real users experience significantly worse performance than the lab predicts, something is degrading field performance that lab tests don’t capture (third-party scripts, A/B testing libraries, ad networks, personalization layers, CDN configuration issues)

This generates a High severity finding with the delta as evidence.

CrUX provides data at two granularities: URL-level (this specific page) and origin-level (the whole domain). URL-level is more accurate but requires sufficient traffic on that specific URL (CrUX suppresses data for low-traffic URLs). When URL-level data is unavailable, origin-level data is used as a fallback, and cruxDataLevel = 'origin' is set. This is noted in the finding evidence.