Getting Started with Lighthouse User Flows
Tags: performance, javascript, webdev, webperf
Published: 2021-11-19 22:37:52

The Google Chrome Team recently announced two big features coming to [Lighthouse 9.0](https://developer.chrome.com/blog/lighthouse-9-0/) and Chrome DevTools: User Flow Reports in Lighthouse, and a new Recorder panel in DevTools that can capture and replay user journeys with just a few clicks.

I've been experimenting with both of these tools for the past couple of weeks, and I've been genuinely impressed by how powerful they are and the possibilities they bring when you use them together.

In this post, I want to share a quick overview of what these features are and how they work, and finally walk you through an example that combines them to unlock their full potential. Let's dive in!

---

## Lighthouse User Flow Reports
Unlike traditional Lighthouse reports (which only audit a website during its initial page-load), user flow reports can analyze a page at any point during its life-cycle. We can take "snapshots" of a page at a particular moment, or even collect metrics over a period of time that includes user interactions.

User flows are available as a new API in the [Lighthouse Node module](https://github.com/GoogleChrome/lighthouse), and we can use them alongside tools like Puppeteer which allow us to control the browser and trigger synthetic events programmatically.

Here's an example of how we can generate a user flow report using Puppeteer and the Lighthouse API (you can see the complete code [here](https://github.com/Charca/lighthouse-user-flows/blob/main/examples/navigation-report.js)).

```js
async function captureReport() {
  // Puppeteer initialization
  const browser = await puppeteer.launch();
  const page = await browser.newPage();

  // Start user flow
  const flow = await lighthouse.startFlow(page, { name: 'My User Flow' });
  
  // ... Caputure reports here ...
  
  // End user flow
  return flow.generateReport();
}
```

Within a user flow, there are three types of reports that we can capture:

- **Navigations** – to audit cold and warm page-loads,
- **Snapshots** – to audit the exact state of the page at any point in time, and
- **Timespans** – to audit a page during any period of time.

We're going to see concrete examples of each one of them in the last section, but here's a quick overview of what they do and how their APIs look like.

![Navigation Report Diagram](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5ukft25nj3v3e508i3s8.png)

### Navigations
These are the standard Lighthouse reports that audit a page during page-load, except that now we can measure both cold page-loads (clearing caches and local storage), and warm page-loads (without clearing the cache). We can even capture multiple navigation reports as part of the same user flow report see how they compare.

This is how we can capture a navigation report with this new API:

```js
await flow.navigate('https://www.nytimes.com')
```

We can also give the report a descriptive name with the `stepName` option:

```js
await flow.navigate('https://www.nytimes.com', {
	stepName: 'Cold navigation'
})
```

And we can capture a warm load by setting the `disableStorageReset` flag:

```js
await flow.navigate('https://www.nytimes.com', {
	stepName: 'Warm navigation',
	configContext: {
		settingsOverrides: { disableStorageReset: true },
	}
})
```

![Snapshot Report Diagram](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/onfwjd27wm5x8t2lg2z8.png)

### Snapshots
We can take a snapshot at any point during the user flow, and Lighthouse will analyze the page in its exact state. This is useful for when we want to audit a particular state of the UI that only appears after a user interaction – like a modal that shows up when the user clicks a button.

```js
await flow.snapshot({ stepName: 'Checkout modal opened' });
```

Since we're only analyzing a single moment and not a period of time, the metrics in the snapshot report are not terribly useful for performance, but they're a great way to get accessibility and best practices insights based on the state of the page after the user interacts with it, which is something that wasn't possible before.

![Timespan Report Diagram](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1k51r2k1e7oje0v1jjjq.png)

### Timestamps
These reports audit a website over a period of time, which can contain user interactions as well. From a performance perspective, they're useful to measure Total Blocking Time (TBT) and Cumulative Layout Shift (CLS) while a user interacts with a page.

```js

await flow.startTimespan({ stepName: 'Checkout flow' });

// ... user interactions here ...

await flow.endTimespan();

```

Measuring CLS beyond the initial page is particularly useful because it gives us a more accurate measure of this metric in the lab, that is closer to what we'll see in our field data.

---

> For a much more detailed overview of Lighthouse user flows with complete code examples, I highly recommend checking out the [official tutorial](https://web.dev/lighthouse-user-flows/) on web.dev.

![User Flow Reports Explained](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/h7gihdl0e2do53m4ud57.png)

---

## Chrome DevTools Recorder Panel
The Recorder panel is a new feature coming to Chrome DevTools (currently available in Chrome 97), which allow us to record and replay user journeys with just a few clicks.

![Chrome DevTools Recorder Panel](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/w0xvc1wz603z02q2hvb7.gif)

At the time of writing, the Recorder panel is only available in the [Chrome Dev](https://www.google.com/chrome/dev/) and [Canary](https://www.google.com/chrome/canary/) builds, so make sure you have one of those installed if you'd like to follow along.

You can find the Recorder panel in DevTools under **More options** > **More tools** > **Recorder**, or by opening the Command Menu (with **Cmd + Shift + P**) and searching for **Recorder**.

![Recorder How To Find It](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fwbs6m4uhr77mqs26d0p.png)

With the Recorder panel opened, you can click the **Start new recording** button, give the recording a name, and start interacting with the page in any way you want (for example, completing an sign up or checkout flow). Once you're done with the recording, you'll be able to replay it, modify it, run a performance profile for the entire journey, or export the recording as a Puppeteer script.

This last feature is what we're mostly interested in. We can use the auto-generated Puppeteer script as a starting point for creating user flow reports with Lighthouse, which will save us a ton of time and effort. We'll explore this approach next.

---

## Lighthouse Reports on User Journeys
Now that we've seen what Lighthouse user flow reports are and how we can record user journeys and export them as Puppeteer scripts with the DevTools Recorder panel, let's explore how we can use them together to capture a user flow report based on a user journey.

The process is simple: we'll record a user journey in DevTools, export it as a Puppeteer script, and we'll modify the script by adding a few calls to the Lighthouse user flow APIs in the right places. In the end, we'll be able to run the script with Node.js and get shiny new User Flow Report back.

### 1. Project setup
The first thing we need to do is initialize a new npm project (ideally in a new folder) and install the dependencies we're going to be using:

```
mkdir lighthouse-reports
cd lighthouse-reports
npm init -y
npm install lighthouse puppeteer open --save
```

We'll use the `open` package so that we can automatically open the HTML report in the browser once the script finishes, but this is an optional dependency (and you definitely don't need it if your running the script in CI).

### 2. Record and export a user journey
For this tutorial, I'm going to use this [coffee shopping](https://coffee-cart.netlify.app/) demo app (borrowed from Google's documentation) to record a simple user journey: adding a couple of items to the cart, navigating to the shopping cart, and going through the (fake) checkout process.

I encourage you to do something similar to keep things simple, but you can of course use any website you want and go wild with your user journey. Simply hit the "Start recording" button on the Recorder panel and start interacting with the page by clicking around, scrolling, or filling out forms. Make sure you stop the recording once you're done.

![Example Recording Animation](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tpyfs790g3t99dkmrikl.gif)

Once you've finished recording, make sure you can replay it by hitting the **Replay** button on the top right. **This is important.** If the flow can't be replayed consistently, you might run into issues generating the Lighthouse reports later on.

> For more details on how to use the Recorder panel, check you [this great article](https://developer.chrome.com/docs/devtools/recorder/) in the Chrome DevTools documentation site.

Once you're happy with your recording, export the user flow as a Puppeteer script by clicking the Export icon on the top (be careful not to click the delete icon by mistake, they're dangerously close together!), and save it in the project folder as `user-flow.js`.

### 3. Edit the script
Now comes the fun part. If you open the `user-flow.js` script, you'll find that it consists of a bunch of utility functions at the top, followed by a series of code blocks, each one representing a "step" in our user journey (clicks, scrolls, keyboard events, etc.)

We're going to make a few modifications to this script to generate a Lighthouse user flow report consisting of four "sub-reports":
- Two navigation reports (to measure both cold and warm page-loads),
- A snapshot report to capture the state of the page when the checkout modal is open, and
- A timespan report to capture the entire checkout flow.

You might find it easier to see the modifications to the script in [this annotated file](https://github.com/Charca/lighthouse-user-flows/blob/main/examples/user-flow-modified.js) or in [this diff](https://github.com/Charca/lighthouse-user-flows/compare/modify-script), but if you prefer a step-by-step guide, just read on and code along!

#### 3.1 Import dependencies
First off, let's import the rest of our dependencies right after the `puppeteer` require in the first line:

```js
const open = require('open');
const fs = require('fs');
const lighthouse = require('lighthouse/lighthouse-core/fraggle-rock/api.js');
```

#### 3.2 Create the user flow
Right at the top of the script's main function, you'll find a couple of lines that create the Puppeteer `browser` and `page` instances. We'll create our user `flow` instance right after that:

```js
const flow = await lighthouse.startFlow(page, { name: 'My User Flow' });
```

#### 3.3 Add the Navigation reports
Now we need to scroll down to where the code blocks start. We'll add the two navigation reports right after the block with the `targetPage.goto('https://coffee-cart.netlify.app/')` call:

```js
// Cold navigation report
{
  const targetPage = page;
  await flow.navigate('https://coffee-cart.netlify.app/', {
    stepName: 'Cold navigation'
  });
}

// Warm navigation report
{
  const targetPage = page;
  await flow.navigate('https://coffee-cart.netlify.app/', {
    stepName: 'Warm navigation',
    configContext: {
      settingsOverrides: { disableStorageReset: true },
    }
  });
}
```

#### 3.4 Add the Snapshot report
You can add this call between any two steps in the script, but for demonstration purposes, we want to take the snapshot once the Checkout modal opens. Add the following code right after the code block with the `waitForSelector` call that waits for the `"aria/Proceed to checkout"` element:

```js
{
  await flow.snapshot({ stepName: 'Checkout modal opened' });
}
```

#### 3.5 Add the Timespan report
We'll start the timespan right after the `snapshot()` call from the previous step:

```js
{
  await flow.startTimespan({ stepName: 'Checkout flow' });
}
```

And we'll end it at the end of the flow, right before the call to `browser.close()`:

```js
{
  await flow.endTimespan();
}
```

#### 3.6 Generate the user flow report
Finally, we need to generate the report, save it as an HTML file, and open it in the browser. Add the following lines right before the end of the main function (after the call to `browser.close()`):

```js
const reportPath = __dirname + '/user-flow.report.html';
const report = flow.generateReport();
fs.writeFileSync(reportPath, report);
open(reportPath, { wait: false });
```

And we're done! If you save and run the script (with `node user-flow.js`), you should see the report coming up on your browser after a few moments. 

![User Flow Report Screenshot](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xkfz3wo97n8a3sunp7vl.png)

If you didn't follow the steps with me but would like to see how the report looks like, you can open the live report and play with it [here](https://lighthouse-user-flow-report.netlify.app/). You'll see a timeline with our four reports in the order we captured them, and you can click in each one for a more detailed view. How cool is that?!

## Final thoughts
Lighthouse user flows and the new DevTools Recorder panel are like milk and cookies: they're both amazing on their own, but they're definitely better together.

The new Lighthouse APIs enable new ways to measure the performance and accessibility of our websites, generating lab data that is more representative of what real users experience in the field. And with the auto-generated Puppeteer scripts, the process of capturing these data is a breeze.

The Recorder panel also has many interesting use cases in addition to measuring performance. We can use the Puppeteer scripts as a starting point for running automated end-to-end tests, or even use them directly as a quick way to assert that user journeys can be completed correctly. And of course, since these are just Node scripts, we can run them as an additional step in our CI pipelines.

Finally, I think it's important to keep in mind that these features are still quite young, so you may run into a few issues here and there (if you do, be sure to share your feedback with the Chrome team!). I still encourage you to give them a try and explore the cool things you can do with them.

---

## Resources
- For more information about Lighthouse user flow reports, check out the [official tutorial](https://web.dev/lighthouse-user-flows/) on web.dev.
- For detailed instructions about the DevTools Recorder panel, take a look at the [official documentation](https://developer.chrome.com/docs/devtools/recorder/) on Chrome Developers.

---

I would love to hear your thoughts about this process if you give it a try! Please let me know in the comments, or reach out on [Twitter](https://twitter.com/charca).

Thank you for reading ❤️