Web Performance Profiling: Instacart.com
Tags: performance, webdev, javascript, webperf
Published: 2020-11-12 17:13:52

---
title: Web Performance Profiling: Instacart.com
published: true
date: 2020-11-12 00:00:00 UTC
tags: performance, webdev, javascript, webperf
canonical_url: https://requestmetrics.com/web-performance/performance-profiling-instacart
cover_image: https://requestmetrics.com/assets/images/webperf/perf-instacart/title-2000.png
---

Grocery shopping is tedious and time consuming. In search of a more streamlined experience, I decided to try Instacart. Unfortunately, using their site is _also_ tedious and time consuming.

## Common Actions Take Too Long

In the video you’ll see I attempt to visit the landing page of my local grocery store and, after that loads, do a search for _yogurt_.

![Visiting a grocery store homepage](https://dev-to-uploads.s3.amazonaws.com/i/7xl8p2x8vc4nefok3rrv.gif)

Over **25** seconds to perform a single load and search. Just loading the Cub Foods “storefront” page took **14** seconds and **154** requests.

![Loading a single storefront](https://requestmetrics.com/assets/images/webperf/perf-instacart/insta-total-stats.png)

On the plus side there were some very nice placeholder graphics that set the mood while I waited.

![Placeholder graphics for days](https://requestmetrics.com/assets/images/webperf/perf-instacart/insta-placeholder.png)

### When it’s not JavaScript’s Fault

Usually when I look at “modern” websites the main performance culprit is JavaScript. Too many scripts doing too much rendering. While Instacart _does_ have too much JavaScript, they have a bigger problem: **the server**.

#### The Initial Page Load is Slow

Instacart uses some combination of server and client rendering. On the one hand, it’s great that they don’t just load a blank page with a big spinner in the middle and wait for 20MB of JavaScript to load.

![3 seconds to load the basic page skeleton](https://requestmetrics.com/assets/images/webperf/perf-instacart/insta-slow-page.png)

On the other hand it took **3** seconds to get the single page layout skeleton back.

![Just a basic SPA template](https://requestmetrics.com/assets/images/webperf/perf-instacart/insta-skeleton.png)

The images to populate the placeholder template took another few seconds:

![4 seconds for a background image](https://requestmetrics.com/assets/images/webperf/perf-instacart/insta-slow-image.png)

If you notice the first segment of the URL after the Cloudfront domain is `/156x/`. These endpoints will return custom sized images and that first segment is the requested dimensions. You can change that segment to `/300x/`, for example, and you’ll get a bigger image that maintains aspect ratio (it will be 300px wide by whatever the height should be to keep the ratio). You can also specify a height if you want a different effect:

![Custom images sizes are great, but costly for performance](https://requestmetrics.com/assets/images/webperf/perf-instacart/insta-custom-image-size.png)

Cool, but this is almost certainly part of the reason loading uncached images is so slow. The origin behind Cloudfront is doing a lot of work to make a custom image and send it over the wire on-demand.

In all fairness, these images have the proper cache response headers, so subsequent page loads will have the images served from the browser memory cache. But that first hit is very slow.

#### The API is Slow Too

It isn’t just the page load and images that are slow. The servers responding to API requests are taking their time as well. Some of the calls to populate data on the page took over **5** seconds!

![Several API calls took over 5 seconds](https://requestmetrics.com/assets/images/webperf/perf-instacart/insta-slow-api.png)

One of the endpoints shown here fetches coupon information. In the initial loading video you can see the coupon section is particularly slow to render. Even though there is content loaded below the fold, the user has no idea since the placeholders are still shown for the coupon section until that call returns.

#### Placeholders are Nice But Faster Endpoints are Better

This is where the hybrid rendering model falls apart a bit. There is a lot of dynamic content being rendered post page load. And since the API is slow the user is getting even more placeholders.

As the user scrolls down the page there are on-demand API calls made to show products from each grocery department. These calls can take upwards of 2 seconds each. And there’s a lot of them.

![On-demand API calls to load additional products are slow.](https://requestmetrics.com/assets/images/webperf/perf-instacart/insta-slow-department.png)

For each one we get more placeholder graphics until the server returns its response:

![Placeholders are cool, but speed would be better.](https://requestmetrics.com/assets/images/webperf/perf-instacart/insta-more-placeholders.png)

Placeholders do a nice job of minimizing jank or [cumulative layout shift](https://requestmetrics.com/web-performance/cumulative-layout-shift) but they are a poor substitute for the actual content. Paradoxically I find they can also make a site feel slower since the UI is changing out from under the user so frequently.

### Maybe Instacart Doesn’t Think It Has a Performance Problem?

There’s a [few articles](https://tech.instacart.com/building-instacarts-view-model-api-part-1-why-view-model-4362f64ffd2a) on [the Instacart engineering blog](https://tech.instacart.com/scaling-at-instacart-distributing-data-across-multiple-postgres-databases-with-rails-13b1e4eba202) discussing the back-end technical implementation of the site. In both the linked articles they discuss “improved performance” and the existing “healthy performance” of the site. Perhaps the main problem is they don’t think there’s a performance issue to fix?

Most modern technical stacks are capable of serving pages and API calls in sub-second time if that’s the company’s goal. I suspect in this case they have limited resources and other priorities. Maybe things are better in the phone app, but I think I’ll stick with going to the grocery store for now, it’s faster.