Skip to content
Prajwal Bhatia
← Work

Virtual Internships · 2023–25

Web Vitals Programme

Was 5.45snow 3.17s

LCP p75

The batch-selection page was the highest-traffic flow in the product and its LCP p75 sat at 5.45s. The instinct with a number like that is to reach for a rewrite. It didn't need one.

What was actually slow

The LCP element was a single SVG the browser couldn’t discover until JavaScript had parsed and rendered. Everything else was contention — Google Analytics and HubSpot competing for the main thread during first paint, and DNS lookups happening serially at the worst possible moment.

The fix

Preload the LCP image with fetchpriority="high" so the browser starts fetching before it knows the DOM. dns-prefetch and preconnect for the third-party origins, with crossoriginon the preconnect so the connection isn’t opened twice. Defer analytics to post-interactive. Move web-vitals initialisation into requestIdleCallback. Add an eager prop to BgImageWithLoader so an already-preloaded image skips its JavaScript load check entirely.

Layout shift

CLS was a separate, duller problem: things arriving late and pushing content down. Reserve the header height, reserve the container, and make skeleton cards exactly 145×325px so the swap to real content moves nothing. That took it under 0.1, and on intern profiles the same approach took CLS p75 from 0.229 to 0.006.

Results

Measured at p75 in the field, not on my laptop
MeasureWasNow
Batch selection — LCP p755.45s3.17s
Intern profile — CLS p750.2290.006
Onboarding — LCP p759.9s8.6s
Dashboard — CLS p750.440.24