Performance is the key to successful user retention. Even a second of page load delay diminishes user satisfaction and brand perception. With Google’s growing emphasis on Core Web Vitals, we decided to prioritize Lighthouse optimization across our front-end portfolio — 40+ applications, including 10+ monolithic apps and 30+ single-page applications serving millions of concurrent users.
Our landing route alone handled 0.7 million weekly visits and 3 million monthly traffic. Any regression could directly impact business metrics, so we needed a careful, incremental approach.
The Four Metrics That Matter
We identified the four metrics that cover 80% of the Lighthouse 8 scoring weight:
| Metric | Weightage | Target | Purpose |
|---|---|---|---|
| First Contentful Paint (FCP) | 10% | 1.8s | Initial content visibility |
| Largest Contentful Paint (LCP) | 25% | 2.5s | Main content load completion |
| Total Blocking Time (TBT) | 30% | 200ms | Main thread responsiveness |
| Cumulative Layout Shift (CLS) | 15% | 0.1 | Visual stability |
We set a target Lighthouse score of 90+ across all pages and prioritized routes based on two factors: high traffic volume and low performance scores.
UX Benchmarks
Before diving into optimizations, we established clear benchmarks:
- First load (slow 3G): under 5 seconds for critical content, with deferred loading for non-essential assets
- Subsequent loads: ~2 seconds
- User interaction response: under 100ms
- Rendering target: 60 frames per second
Optimizing First Contentful Paint (FCP)
FCP measures when the first piece of content becomes visible. The primary bottleneck here is render-blocking resources.
- Load only critical CSS for the initial paint; defer the remainder
- Inline essential styles directly in HTML
- Inline critical JavaScript within
<script>tags - Apply
asyncordeferattributes to non-essential scripts - Organize stylesheets by media type (mobile vs. desktop)
Optimizing Largest Contentful Paint (LCP)
LCP measures when the largest visible element finishes loading — typically a hero image or heading block. We focused on reducing resource load times:
- Defer non-critical CSS and fonts until after page load
- Serve static assets through a CDN for faster delivery
- Use
font-display: swapso text renders immediately with a fallback font - Apply
loading="lazy"on below-fold images - Code-split JavaScript bundles to reduce the initial payload
- Convert images to WebP format
- Deploy Brotli compression instead of gzip for smaller transfer sizes
Optimizing Total Blocking Time (TBT)
TBT measures how long the main thread is blocked and unable to respond to user input. Think of it like a grocery store — if the cashier (main thread) is busy when a customer arrives (user interaction), that customer leaves (user abandons the page).
- Eliminate unnecessary JavaScript entirely
- Audit main thread tasks and remove non-essential work
- Apply code-splitting to reduce JS payloads
- Use event delegation and specific CSS selectors to reduce processing overhead
- Remove blocking scripts (e.g., unnecessary language property files)
Optimizing Cumulative Layout Shift (CLS)
CLS measures visual stability — unexpected layout shifts that frustrate users.
- Apply the
font-displayproperty to prevent text reflow when web fonts load - Preload web fonts with
<link rel="preload"> - Implement skeleton loaders to reserve layout space during loading
- Define explicit width and height dimensions on all images to prevent reflow
Challenges with Monoliths and SPAs
Monolithic applications (88% of our audited pages) posed the biggest risk. They serve millions of concurrent users, so any change had to be incremental and carefully validated.
Single-page applications required a different focus — optimizing the first load by reorganizing code to prevent unnecessary downloads, parallelizing JavaScript chunks, and prioritizing critical content for LCP.
Monitoring and Alerting
Optimization without monitoring is incomplete. We set up two layers of observability:
Elastic Real User Monitoring (RUM)
We deployed a JavaScript-based RUM agent across all applications to capture real user data:
- Percentile metrics from P50 through P99 for each Core Web Vital
- Page load analysis and latency visualization
- Historical trend tracking to measure progress over time
- Visitor demographics and experience breakdowns
This gave us dashboards showing real FCP, LCP, TBT, and CLS distributions — not just synthetic Lighthouse runs, but actual user experience data.
Grafana Alerting
To catch regressions post-deployment, we configured Grafana with latency-based thresholds across all applications. Alerts were piped to Slack via webhooks, ensuring the team was notified immediately when performance degraded.
Results
Over six months of systematic optimization across ~40 pages:
- 29% average improvement — Lighthouse score went from 69 to 89
- 50% more pages hitting 90+ — from 4% to 54%
- Month-over-month tracking showed consistent, steady progression
Key Takeaways
- Prioritize by impact — start with high-traffic, low-scoring routes
- Focus on the right metrics — FCP, LCP, TBT, and CLS cover 80% of the score
- Monitor with real user data — synthetic audits alone don’t tell the full story
- Alert on regressions — performance gains are meaningless if they silently erode after deployment
- Move incrementally — especially on monolithic apps serving production traffic