Measure Web Performance with Web Vitals
Tags: performance, javascript, webdev, tutorial
Published: 2024-01-29 07:44:10

Measuring Web Performance can be tricky. We usually open our dev tools and run a test with Lighthouse. Don't get me wrong, I am not saying that it is a bad approach. But it could certainly use some improvements to give you more adequate data to work with.

![Core Web Vitals](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/f7msehenpsrv2qzm0ouo.png)

As I am quite frequently trying to improve the performance of websites to their limits, I decided to write a little bit about how you can use Web Vitals to measure Web Performance (even on not deployed websites).

Enjoy!

## Litle Theory

Before we jump into how you can use Web Vitals to measure the performance, let's talk briefly about what are most known and common performance metrics.

In general, we can divide the data we measure to two main groups:

* Lab
* Field

The first data can be gathered from a tool like Lighthouse. How it works is that your application code is run in so called isolated environment and tests are conducted on it to give you some performance and other categories metrics in form like the one below:

```
Performance: 90
SEO: 100
Accessibility: 96
// etc
```

But what does it actually mean? Is only the score of 100 in performance good? Is 70 score e-commerce website actually worse than a 90 score blog?

You can see the patern here. As we developers love to say that `it depends` it works here as well.

![Lighthouse](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/n380ech75yq4l11niydi.png)

Even the metrics such as `Largest Contentful Paint`, `Cumulative Layout Shift` etc are not entirely correct as they are gathered from this isolated environment which basically does not correspond to the real load of the application can get (like you website can deliver a performance of 100 in small load and 60 in huge load).

So what can we do to get more adequate data? Use the second data as well which is the `Field` data.

This data is gathered from Real User devices. This means that it gives you much more up to date results of how your website is perceived by real users not isolated environment.

This also leads to interesting findings, for example CLS metric (the one resposnible for measuing the layout shift) is 0 in Lab data but is 0.100 in Field data. So it means that for some reason, real users are experiencing some kind of layout shift that wasn't observerd in the isolated environment. Maybe some kind of Ad banner that is shifting their page? Interesting isn't it? :)

The one problem you may encounter is that this Field data is usually coming from CrUX which does not have data about every page but only about few of them.

![CrUX](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/w6gd7huq28lwywg8pq8c.png)

This means that for test/stage/local environments of your web application you will not get information about real user experience. But don't worry, the folks at Google have found a way to achieve that :)

## Using Web Vitals package

The `web-vitals` package allows you to gather Core Web Vitals metrics from real user devices on even not deployed websites!

The usage of the package itself is very (very) simple. Take a look at the below code:

```ts
import {onLCP, onFID, onCLS} from 'web-vitals';

onCLS(console.log);
onFID(console.log);
onLCP(console.log);
```

We just import certain utility functions that will display in the console the values of certain metrics that we can then analyze.

But this will only display these values in the user console in dev tools. How am I supposed to track it?

The folks at Google thought about it too! And they have added an option to send the results of the audit to certain analytics application such as Google Analytics.

And it is easy as well. Take a look!

```ts
import {onCLS, onFID, onLCP} from 'web-vitals';

function sendToGoogleAnalytics({name, delta, value, id}) {
  // Assumes the global `gtag()` function exists, see:
  // https://developers.google.com/analytics/devguides/collection/ga4
  gtag('event', name, {
    // Built-in params:
    value: delta, // Use `delta` so the value can be summed.
    // Custom params:
    metric_id: id, // Needed to aggregate events.
    metric_value: value, // Optional.
    metric_delta: delta, // Optional.

    // OPTIONAL: any additional params or debug info here.
    // See: https://web.dev/debug-performance-in-the-field/
    // metric_rating: 'good' | 'needs-improvement' | 'poor',
    // debug_info: '...',
    // ...
  });
}

onCLS(sendToGoogleAnalytics);
onFID(sendToGoogleAnalytics);
onLCP(sendToGoogleAnalytics);
```

But as I mentioned, you can also send these results directly to any other analytics application like following:

```ts
import {onCLS, onFID, onLCP} from 'web-vitals';

function sendToAnalytics(metric) {
  const body = JSON.stringify(metric);
  // Use `navigator.sendBeacon()` if available, falling back to `fetch()`.
  (navigator.sendBeacon && navigator.sendBeacon('/analytics', body)) ||
    fetch('/analytics', {body, method: 'POST', keepalive: true});
}

onCLS(sendToAnalytics);
onFID(sendToAnalytics);
onLCP(sendToAnalytics);
```

And that's it! This solves all the problem I mentioned in the introduction!

## Summary

Nicely done! You now understand the types of perfomance data and how to measure them both. You also know how to use web-vitals package and send the results to analytics tool. That is a lot! Make sure to check out following links for additional info:

* https://web.dev/articles/vitals#measure_core_web_vitals_in_javascript
* https://github.com/GoogleChrome/web-vitals

Take care and see you next time!