Studies show that even a one-second delay in page load time can significantly impact conversions and bounce rates. This article outlines our comprehensive approach to improving their site performance and achieving remarkable results.
In the competitive B2B landscape, every second counts. Studies show that even a one-second delay in page load time can significantly impact conversions and bounce rates. We recently partnered with a B2B eCommerce client facing this challenge: their site suffered from slow loading times, glitchy pages, and frustrated users. This article outlines our comprehensive approach to improving their site performance and achieving remarkable results.
Understanding the Challenge
Our first step was understanding the client's concerns and gathering end-user feedback. They reported:
Extremely slow page load times
Significant delays in loading product and pricing information
Persistent loading spinners throughout the site
Difficulties loading more products on product listing and search pages
The browser freezes when attempting to load more products
Overall sluggishness and glitches while browsing
A Data-Driven Approach
To pinpoint the root causes of these performance issues, we utilized a combination of tools and techniques:
Quantum Metric: This web analytics platform provided insights into user behavior and identified pain points.
Chrome Performance Tab: We used this tool to analyze page load performance and identify bottlenecks.
Lighthouse: This tool provided an in-depth performance audit and identified areas for improvement.
Custom Scripting: We developed a script to measure Largest Contentful Paint (LCP) for "soft navigation" within the single-page application (SPA).
Key Findings
Our analysis revealed several key areas for improvement:
Slow Largest Contentful Paint
Generally speaking, LCP up to 2.5 seconds is considered good, 2.5 to 4 seconds is regarded as needing improvement, and above 4 seconds is considered poor. The LCP for product listing and search results pages averaged about 5.5 seconds, falling into the "poor" range.
Sluggish and duplicated API Calls
Only 74% of API calls were completed within 3 seconds, with 15% exceeding 6 seconds. This significantly impacted page load times. The site also made numerous duplicate API calls, wasting resources and increasing load times. We focused on the four most important API calls for product pages:
Search call
Product call
Price call
Stock level call
Large Asset Sizes
Large image files and inefficient asset-loading practices contributed to slow page loads. In some cases, 100MB of images were downloaded for each page load.
Uncached Calls
Many API calls were not cached effectively, leading to unnecessary server requests. We listed out calls that can be cached and planned to reuse already loaded data without having to make extra API calls. We noted the following -
The number of uncached calls, calls cached on the edge server (For example - Cloudflare), and calls that are cached on the browser. We also recorded the amount of time they were cached.
All POST API calls, which could be converted to GET calls and then cached
Reusing authentication token where applicable within the validity period of the token
Render-Blocking Resources
Several resources were blocking page rendering and delaying the time to first paint. The Performance tab and Lighthouse, available on Chrome dev tools, offer a great way to check out the chain of events leading up to the site's complete load. They also show information about the memory footprint of the page load event. Analyzing this helped us find bottlenecks in the page load and transition flows.
Geolocation Impact
API call speeds varied significantly based on user location. For example, we looked into product API call timings for users in Japan and South Africa and compared them to users in the United States.
User Journey and Glitches on the Site
The top page hops were PLP to PLP, followed closely by PLP to PDP. For the next 10-page hops, PLP, PDP, Home, and SRP were consistently the top pages. Understanding these hops allowed us to determine what data could be reused as the user navigates through the site.
Additionally, we could filter out errors, bottlenecks, glitchy flickering behaviors, long-running spinners, user rage clicks, reload events, and many others by watching session replays on Quantum Metric. These events indicated potential problems that users encounter on the site.
Implementing the Solutions
We implemented a multi-faceted strategy to address these performance bottlenecks:
API Optimization
Refactoring
We refactored critical API calls, such as those for pricing and stock information, to reduce simultaneous render blocking requests made from the frontend and improve efficiency. For the platform we were working with, this involved leveraging Oracle Commerce Cloud's Server-Side Extensions (SSE) to overcome browser limitations around simultaneous API calls made from the frontend.
Payload Reduction
We optimized API calls to fetch only essential data, significantly reducing payload sizes and response times. This was achieved by utilizing APIs' full range of query parameters and limits.
Caching
We implemented aggressive API call caching strategies, including browser and edge caching (using Cloudflare). This dramatically improved response times, especially for users in geographically distant locations.
An example of this is the call to fetch product information. After analyzing the frequency of changes to product information, we concluded that the product calls could be cached on the browser cache and edge cache for a certain period. Instead of making a bulk call that could include any combination of items (hence, it is not beneficial to cache it), we decided to make individual calls for products and cache those. It could then be reused in multiple pages without having to reach the end server every time.
The added advantage of this approach is that it would be incredibly beneficial for specific geo-locations that are distant from the end server. The data would be served from the nearest edge server, dramatically improving the response time. The original penalty to reach the end server would be paid only by a single user, once, in the entire geographical area served by the edge server under consideration.
Specific API calls need authentication tokens when connecting to external or backend services. These authentication tokens are often valid for a certain period and can be reused. We implemented caching mechanisms to reuse these tokens where possible. This meant that the response time of many calls was reduced by an amount of whatever the authentication call took- anywhere from a couple of hundred milliseconds to seconds.
We also updated specific API calls from POST to GET calls and cached them.
Duplicate Call Prevention
We eliminated duplicate API calls by reusing data from the redux state, browser cache, and edge cache whenever possible.
By preventing multiple calls from happening and reusing already available information, we prevented the application state from storing duplicates and growing excessively large. This was especially helpful for product listing pages where a large number of products may be loaded with an infinite scroll element or pagination.
Asset Optimization
Reusing Data from Application State
Certain information like product information, profile information, organization information, and search results, among others, do not need to be requested multiple times in a SPA site. Especially in an application that has a redux state available.
We reused a lot of information that was already available in the state. A great example of this is revisiting a PLP which was already visited. Reusing the product information already available in the state meant that most of the information required on the page would be available without making a single API call.
We also measured the number of duplicate calls on these pages when the user navigated using SPA navigation. The general rule of thumb for reducing the number of duplicate calls is in this order:
Take from the state if the information is already available
Take from the browser cache
Take from the edge cache
Pull from server
Image and Font Optimization
We optimized image formats, dimensions, and loading techniques. This included fetching the appropriate image sizes, effectively caching images, and implementing lazy loading without impacting LCP.
We cached font files to reduce rendering glitches and improve initial load times.
Code Optimization
Bottleneck Removal
We analyzed the chain of events that led up to the loading of prices on product pages. We made sure only to make the absolutely necessary API calls to eventually load the product prices and removed or deferred all other calls.
For example, a standard flow could include - requesting a page, loading user profile information, using some information from the profile to build a required query for search, executing a search, fetching product data, and fetching price and stock. We actively sought to find bottlenecks in this flow and eliminated them.
Server-Side Rendering
Different platforms have varying ways to achieve this and may have limitations around what can be rendered on the server side. For our case, we utilized Oracle's Open Store Framework's "fetchers" feature to fetch critical information on the server side, improving initial page load times.
Coding Best Practices
We improved code quality by leveraging React's callback and memo hooks, preventing unnecessary re-renders, and optimizing the use of the useEffect hook.
Our Success Story
Our efforts resulted in significant performance improvements:
2.5x Faster LCP: The LCP for key pages improved from 5.5 seconds to under 2.5 seconds, now falling within the "good" range. This led to faster page loads and smoother user journeys.
Faster API Calls: 99% of API calls are now completed within 3 seconds, with 0% exceeding 6 seconds. This dramatically improved responsiveness and reduced user frustration.
Reduced API Calls: The total number of API calls made by the frontend was significantly reduced, improving efficiency and reducing server load. For example, the number of price and stock API calls was reduced by 95%.
Reduced Asset Sizes: Image download sizes were dramatically reduced, from over 100MB to a few KBs in many cases. This significantly improved load times, particularly for mobile users.
Improved Global Performance: Users in geographically distant locations, such as South Africa and Japan, experienced up to 6x faster product API calls due to improved caching.
We delivered a significantly faster and more efficient B2B eCommerce experience by addressing performance bottlenecks and implementing best practices. This improved user satisfaction and significantly improved our client's net promoter score.
Rohit is a forward-thinking eCommerce evangelist, especially focused on re-energizing the B2B sector and merging the old disciplines with new technology opportunities. He is passionate about delivering profitable growth through people-driven digital transformation. Watch his talk on digital transformation.