Home  /  CDN Analytics  /  CDN User Experience Scoring
CDN Analytics

CDN User Experience Scoring: Combining RUM and Synthetic Data for UX Metrics

By Mei-Lin Wu, Web Performance Analyst • September 7, 2026 • 9 min read

A CDN can report 99.9% cache hit ratio and still deliver a poor user experience. True UX scoring requires correlating what users actually feel with what your probes measure. Here's how to fuse Real User Monitoring (RUM) and synthetic testing into a single, actionable CDN experience score.

Key Takeaway: RUM tells you what users experienced; synthetic tells you why and where it happened. A weighted composite score that normalizes both sources eliminates blind spots from sampling bias, network variance, and lab-only conditions.

Why CDN Metrics Alone Fail the User

Traditional CDN dashboards optimize for infrastructure health: edge hit ratio, origin offload, bandwidth, and PoP availability. Those are necessary but not sufficient. A user in Bentonville on a mid-range Android over LTE doesn't care that your edge HIT ratio is 96% if Largest Contentful Paint (LCP) is 3.8s due to a late-discovered hero image or unoptimized edge logic.

Understanding what is a CDN at the network layer helps, but UX scoring shifts the lens from network efficiency to perceived performance. The goal is a single 0-100 score that product, engineering, and marketing can track, with drill-downs that point directly to CDN configuration, not just frontend code.

We see three common failure modes when teams score UX from one source:

A combined model solves this by using synthetic as a controlled baseline and RUM as the ground truth distribution.

RUM vs Synthetic: Strengths, Limits, and Complementarity

RUM captures every navigation via the Performance API and Web Vitals library. Synthetic uses scripted browsers from managed agents to measure the same metrics under controlled conditions. For CDN analytics, they answer different questions.

Performance Comparison: Edge vs Origin Processing
Metric Edge Processing Origin Processing Improvement
Latency (p50)8–15 ms120–300 ms15–20x faster
Cache Hit Ratio85–95%N/AReduces origin load
TLS Handshake1–5 ms (nearby PoP)50–150 ms10–30x faster
Bandwidth Cost$0.01–0.04/GB$0.05–0.12/GB3–5x cheaper
Availability99.99% (multi-PoP)99.9% (single DC)10x fewer outages
Dimension RUM (Field Data) Synthetic (Lab Data) Combined UX Score
Coverage 100% of real sessions, all geos/devices Selected PoPs, devices, networks Global distribution calibrated by controlled probes
Consistency High variance, noisy Highly reproducible, low variance Normalized variance with synthetic baseline
Diagnostics Limited (no waterfall on sampled beacons) Full waterfall, headers, cache status Root-cause attribution via synthetic trace
Detection Speed Delayed (needs traffic volume) Immediate (5-min intervals) Early warning from synthetic, confirmed by RUM
CDN Signals TTFB, Next Hop Protocol, cache status via headers Full edge timing, x-cache, server-timing Correlated edge performance vs. user perception
Best For p75/p90 Core Web Vitals, business correlation Regression detection, PoP comparison, deploy gates Executive score + engineering drill-down

For teams evaluating how CDN works under real load, RUM reveals cache fragmentation by URL pattern and device, while synthetic isolates PoP health and origin latency. Neither is optional.

What RUM Gives You That Synthetic Cannot

RUM exposes the long tail. In our analysis of 42M navigations across retail and media sites, p75 LCP from RUM was on average 620ms slower than synthetic median from the same region, driven by low-end Android and congested last-mile networks. RUM also captures interaction metrics like Interaction to Next Paint (INP) that synthetic cannot meaningfully simulate without real user input patterns.

Essential RUM fields for CDN scoring: navigationTiming (TTFB, responseStart), largestContentfulPaint, interactionToNextPaint, cumulativeLayoutShift, nextHopProtocol (h2 vs h3), and custom serverTiming for edge vs origin.

What Synthetic Gives You That RUM Cannot

Synthetic is your control group. By fixing device (Moto G4 equivalent), network (RTT 150ms, 1.6 Mbps down), and cache state, you isolate CDN changes. When you enable HTTP/3 and QUIC or tune image optimization at the edge, synthetic shows the delta within minutes, before RUM reaches statistical significance.

Synthetic also validates cache invalidation correctness. A purge that appears successful in RUM aggregates may still serve stale content from a single PoP that synthetic catches immediately.

The Combined Scoring Model

We recommend a 0-100 composite score with four weighted pillars. Weights should reflect user impact, not infrastructure convenience.

Each pillar is scored 0-100 using threshold-based interpolation from Web Vitals guidance, then weighted. Crucially, RUM and synthetic contribute differently per pillar.

RUM and Synthetic Data Fusion for CDN UX Scoring Diagram showing RUM and synthetic inputs merging through normalization and weighting into a unified UX score. RUM STREAM Web Vitals BeaconsLCP • INP • CLS • TTFB Device / NetworkCPU • RTT • EffectiveType Edge Signalsserver-timing • x-cache p75 • p90 • Volume Weighted SYNTHETIC PROBES Scheduled Runs5-15 min • 8-12 PoPs Full WaterfallHeaders • Trace • Filmstrip Controlled ConfigCold/Warm Cache • H2/H3 Median • StDev • Baseline FUSION ENGINE Normalization Outlier trim • Geo weight Weighted Scoring 40/25/15/20 • RUM 70% Syn 30% Drift Detection Synthetic delta vs RUM p75 UX SCORE 87 GOOD • +3 WoW LCP 2.1s • INP 88ms • CLS 0.04 Continuous • High volume Periodic • Controlled
Figure 1: Fusion pipeline — RUM (70% weight) provides distribution truth; synthetic (30% weight) provides calibration, waterfall diagnostics, and early regression detection.

The 70/30 RUM-to-synthetic weighting is a starting point. For low-traffic pages (<1k views/day), shift to 50/50 because RUM variance is too high. For high-traffic landing pages, 80/20 emphasizes real user impact.

Normalization is critical. Without it, a traffic spike from a slow region will tank your score even though the CDN performed correctly. Steps:

  1. Segment: Bucket RUM by country, device memory class, and effective connection type (4G/3G).
  2. Trim: Use p75 for scoring, not mean. Trim p99 outliers from bot traffic and background tabs.
  3. Weight: Weight segments by business importance, not just volume. If 12% of revenue comes from Germany, weight DE accordingly even if US traffic is 5x.
  4. Calibrate: Compare RUM p75 to synthetic median per PoP. A growing gap indicates last-mile or device issues, not CDN regression.

Implementing the Score: Code and Data Pipeline

Start with lightweight RUM collection. Use the web-vitals library and attach CDN-specific metadata from Server-Timing and X-Cache.

// RUM beacon with CDN context - ~1KB gzipped
import { onLCP, onINP, onCLS } from 'web-vitals';

function getCDNMeta() {
  const timing = performance.getEntriesByType('navigation')[0];
  const st = timing.serverTiming || [];
  return {
    ttfb: timing.responseStart,
    cache: st.find(e => e.name === 'cache')?.description || 'unknown', // HIT/MISS
    edge: st.find(e => e.name === 'edge')?.duration,
    protocol: timing.nextHopProtocol // h2, h3, http/1.1
  };
}

function send(metric) {
  const body = JSON.stringify({
    ...metric, ...getCDNMeta(),
    conn: navigator.connection?.effectiveType
  });
  navigator.sendBeacon('/__rum', body);
}
onLCP(send); onINP(send); onCLS(send);

On the synthetic side, configure probes to expose edge timing explicitly. Most CDNs can emit Server-Timing: edge;dur=12, origin;dur=87, cache;desc=HIT. Your synthetic agent should assert on these headers.

# Scoring function (Python) - threshold interpolation
def score_lcp(p75_ms):
    # Good <=2500, Poor >=4000 per Web Vitals
    if p75_ms <= 2500: return 100
    if p75_ms >= 4000: return 0
    return 100 - ((p75_ms - 2500) / 1500 * 100)

def composite(rum, syn):
    # rum/syn are dicts with normalized 0-100 pillar scores
    pillars = {}
    for k in ['loading','interactivity','stability','delivery']:
        pillars[k] = 0.7 * rum[k] + 0.3 * syn[k]
    weights = {'loading':0.4, 'interactivity':0.25, 'stability':0.15, 'delivery':0.2}
    return sum(pillars[k]*weights[k] for k in pillars)

# Example: rum={'loading':82, ...}, syn={'loading':91, ...} -> 86.4

Store RUM in a columnar store (ClickHouse, BigQuery) partitioned by date and PoP. Store synthetic results alongside with is_synthetic=true to enable unified queries. Alert when synthetic degrades >10% before RUM confirms — this is your early warning.

CDN-Specific Signals to Include

Beyond Core Web Vitals, add delivery efficiency metrics that the CDN directly controls:

Correlate these with UX pillars. If LCP degrades but edge TTFB is stable, the issue is origin render or image weight, not CDN. If both degrade, investigate PoP routing or cache fragmentation.

Operationalizing: Dashboards, Alerts, and Deploy Gates

A score is only useful if it drives action. Build three views:

1. Executive trend: 7/30-day UX score with WoW delta and revenue correlation. Single number, updated hourly from RUM p75.

2. Engineering drill-down: Score by PoP, URL group, cache status, and protocol. Synthetic waterfall linked from any regression.

3. Deploy gate: Block promotion if synthetic UX score drops >5 points or LCP regresses >150ms on warm-cache runs. This catches cache invalidation errors and edge function regressions before RUM sees them.

Review weighting quarterly. If INP becomes the dominant complaint in support tickets, increase its weight. The score should reflect user pain, not a static formula.

Finally, document your methodology. A score without transparent thresholds and weights erodes trust. Publish the weighting and update log where teams can see it.

Frequently Asked Questions

Why combine RUM and synthetic data for CDN UX scoring?

RUM captures the full diversity of real networks, devices, and geographies but is noisy and lacks reproducibility. Synthetic provides a stable baseline from controlled locations with full waterfalls and header diagnostics. Together they give statistical coverage plus precise root-cause analysis.

What metrics should be included in a CDN UX score?

Include Core Web Vitals (LCP, INP, CLS) weighted highest, plus CDN-controlled signals: edge TTFB, cache HIT ratio by content type, TLS handshake time, and HTTP/3 adoption. We recommend 40% loading, 25% interactivity, 15% stability, and 20% delivery efficiency.

How often should synthetic tests run to complement RUM?

Every 5–15 minutes from your top 8–12 user regions and PoPs, plus on every deploy, config change, or purge. This catches PoP-specific issues and config drift quickly, while continuous RUM fills gaps between runs and validates real impact.

How do you prevent RUM data bias in the UX score?

Segment by geography, device class, and connection type, trim outliers at p99, and weight segments by business importance rather than raw volume. Use synthetic medians as a calibration baseline to detect sampling bias in low-traffic regions.

External References

References & Standards: RFC 7234 · W3C Web Performance