In the realm of modern hospitality, Blueground stands out by providing fully furnished apartments that redefine travel. However, beyond the sophistication of our spaces, a pivotal factor comes into play — our website's load speed performance. Serving thousands of daily users requires a digital experience that matches the excellence of our physical spaces. In this blog post, we share the journey of how we harnessed the power of performance optimization to optimize our website for Google’s Core Web Vitals (CWV), and guarantee swift, seamless user interactions.
A glimpse into the past
CWVs weren't always the talk of the town. Google introduced these metrics in May 2020 in response to the growing importance of user experience on the web for desktop and mobile devices. Google acknowledged that beyond contributing to user satisfaction and good UX, a website's speed and responsiveness played a vital role in maintaining the overall health of the internet.
Understanding Core Web Vitals and their impact on rankings
There are three CWVs, which together evaluate a website's user experience: Largest Contentful Paint (LCP), First Input Delay (FID), and Cumulative Layout Shift (CLS). LCP focuses on loading performance, FID on interactivity, and CLS on visual stability.
Google will replace FID with a new CWV, Interaction to Next Paint (INP), in March 2024.
Apart from enhancing user experience, both website speed and Core Web Vitals play a critical role in influencing search engine rankings. Search engines give precedence to websites with rapid loading times and outstanding user experiences. Consequently, an accelerated and highly responsive website not only sustains user engagement but also amplifies your visibility in search results, which is crucial for garnering impressions and facilitating conversions on your website.
Unraveling the LCP challenge
Since Core Web Vitals became a ranking factor, many websites have struggled to optimize the LCP in particular, especially on mobile devices. Blueground wasn't an exception 🙂, with an initial score of 2.7s - 3s on mobile devices, just above the baseline of 2.5s (75% required to be considered “Green”). This led to a suboptimal page experience and low impressions reported by Google Search Console (GSC), and we had to improve.
According to Google:
“LCP specifically measures the loading performance of a web page by focusing on the rendering of the largest content element within the user's viewport. This could be an image, a video, or a block-level element like a paragraph. The goal is to ensure that the most significant content on a page is loaded quickly, allowing users to see and interact with it without delays.”
Striving to achieve "Green" status across all Core Web Vitals is crucial for our business, particularly for our listing pages, which showcase our entire property portfolio. Given that these pages lack static content and require real-time updates, optimizing them has proven more challenging than for our other pages.
Laying baseline infrastructure
Before addressing the key changes that have helped us increase the scores of Core Web Vitals across our entire website, I highlight some prerequisites and basic optimizations already implemented in our website's infrastructure. Our website supports code splitting at both the route and component levels using Webpack, employs Lazy loading of components, enables Dynamic imports of static assets, uses HTTP/3, and manages assets caching through CloudFront CDN with Brotli compression. Also, we've implemented Server-Side Rendering (SSR) to aid the Google Bot in promptly indexing the HTML content.
Key changes that boosted our LCP score
1. Ensuring accessibility across regions
The server's response time plays a vital role, particularly with our goal to maintain a Time to First Byte (TTFB) of around 300ms on our listing pages. This timing directly impacts the LCP score, because even if TTFB were to respond very slowly, regardless of the critical rendering path's speed in the browser, the LCP remains problematic.
Initially, our website was hosted in Europe. Recognizing the need for faster response times, we expanded its availability to other regions. Achieving this involved implementing a global load balancer, distributing requests to the relevant cluster based on the user's location. The diagram below illustrates this behavior.
2. Cross-region replication for MongoDB
Additionally, we've implemented cross-region replication in our database to reduce read latency. MongoDB Atlas provides built-in support, which has proven highly beneficial.
This involves enabling local reads for geographically distributed users. For instance, users in California can access data from a nearby replica, significantly reducing latency for an optimized experience.
3. Extracting Critical CSS
To enhance the rendering process, we focused on eliminating any render-blocking resources. CSS files, being render-blocking resources, require the browser to download and parse them before displaying the page. In cases where CSS files are large or network conditions are suboptimal, requests for CSS files can significantly extend the time needed to render a web page, impacting both the FCP and LCP scores.
We employed the critical library to selectively extract above-the-fold CSS based on the specified viewport. This step is crucial in avoiding Flash of Unstyled Content (FOUC). Importantly, we extracted only the necessary CSS to minimize its impact on the Document size.
4. Font preloading
Web fonts can slow down page load times. However, employing font preloading allows for a substantial improvement in the user experience by ensuring faster font loading. By preloading font files, we guarantee that the fonts are readily available when needed, eliminating the need for users to wait for them to load.
<link rel="preload" as="font" type="font/woff2" crossorigin="anonymous" href="/fonts/hero-new-400.woff2">
5. Property image optimization & Priority hints on LCP element
To enhance the LCP score, the first step is to pinpoint the LCP element. In our scenario, this element is the initial property photo visible within the user's viewport on the listings page. We implemented two optimizations:
- We identified the perfect balance to preserve image quality while keeping the file weight as light as possible. This involved transitioning our property photos to the AVIF image format and refining the color profile within our photo delivery service, Dali. Dali provides on-demand image thumbnailing using CloudFront edge functions allowing us to switch all of our property photos to AVIF with minimal effort.
- We enforced preload for the image with a "high" fetch priority (
fetchpriority="high") using priority hints, ensuring compatibility across all browsers. This aligns with Chrome's default behavior for all images within the viewport. Further, we gathered data on the number of images displayed above the fold for the most common screen resolutions using GA4 events and assigned a "high" fetch priority specifically to these images.
Performance results 📊
Following these optimizations, we've achieved a 50% acceleration in TTFB, a 500ms reduction in FCP, and an LCP score of approximately 2s on mobile devices for our listing pages. 🚀
Tools for Identifying and Debugging LCP Issues
The essential tools that helped us resolve and identify issues were: GSC (Google Search Console), PageSpeed, WebPageTest, Chrome dev tools using the Performance panel, and Lighthouse. Be sure to check them out. 😉
Our pursuit of optimal performance doesn't end here; there's more ground to cover. Our upcoming objective is to implement early-hints for critical resources and explore offloading the main thread from third-party libraries, potentially leveraging Partytown or Cloudflare workers. Stay tuned for the next phase of our performance enhancement journey.
And, of course, INP is on our radar too! Stay tuned. ✌️