Monitoring Next.js Apps in Production

By Anthony·September 13, 2021·8 min read

I've been using Next.js for various new projects over the past year, and immediately fell in love with its development experience. Out of the box, it includes goodies such as client-side routing, fast refresh, code splitting, static generation (SSG) and server-side rendering (SSR).

However, over time I've learned that building an application and running it in production are wildly different things. When you run a website in production visitors have certain expectations about its uptime, reliability and performance, and each aspect comes with its own set of challenges.

That's why, whether you're launching a new site or running a mission-critical service, you probably want to have some form of monitoring in place to ensure things are running smoothly.

Performance analytics for a Next.js app Example performance dashboard.

In this guide I'll be showing you how to monitor your Next.js app's live traffic and performance, track custom events, and even set up Slack alerts to get notified when something's up.

I'll be using Panelbear, which has a free tier so you can follow along. By the way, I'm the founder and also wrote a blog post on the tech stack in case you're interested.

Let's get started!

Set up your Next.js project

First things first, let's create a repo and initialize our Next.js app.

npx create-next-app panelbear-example-nextjs --use-npm --example "https://github.com/vercel/next-learn-starter/tree/master/learn-starter"

Next let's cd into the directory, and start the development server.

cd panelbear-example-nextjs

npm run dev

> learn-[email protected]0.1.0 dev
> next dev
> ready - started server on 0.0.0.0:3000, url: http://localhost:3000

If you now open http://localhost:3000 on your browser, you should see the example Next.js starter app appear.

Next.js starter template The Next.js starter template.

Next.js has compiled our app and generated all the assets needed to serve it - pretty standard stuff so far. This is usually where you start building your actual project, but we'll stick to the starter template since we're more interested in the monitoring aspects for this guide.

Now let's move on to adding the analytics script.

Add the tracking code

Assuming you already created your Panelbear account, let's register a new site. We'll call it "Next.js Example App" so we can easily recognise it later.

Site overview You can register new sites on the overview page.

Creating a new site Let's give our site a name.

Panelbear will show you a snippet of code to integrate with any web application framework.

The standard tracking snippet The standard tracking snippet.

Normally you just put this snippet on your HTML head section, but since there's an official Next.js integration, we'll use that instead. For now simply take note of your site ID (you can always find it later in your site settings page).

Simply install the following dependency on your project:

npm install @panelbear/panelbear-nextjs

This package includes a React hook that can be added to the lifecycle of your Next.js app. To do this, create a file in the pages directory of your project, and call it _app.js. The custom Next.js app is what controls the initialisation of each page, and it's always located at pages/_app.js.

For the purposes of this tutorial, it should have the following contents:

// ./pages/_app.js

import { usePanelbear } from "@panelbear/panelbear-nextjs";

function CustomApp({ Component, pageProps }) {

  // Load Panelbear on app init
  usePanelbear("YOUR_SITE_ID");

  return <Component {...pageProps} />;
}

export default CustomApp;

Now simply replace "YOUR_SITE_ID" with the site ID that we got from Panelbear earlier.

That's all that's needed! Next, let's try it locally.

Test the analytics locally

By default, Panelbear does not track events in localhost to prevent using up your plan quota. When you enable debug mode, it will send the events and also log them to the console. Just don't forget to disable it again when deploying to production.

Tip: You could also set the debug option based on an environment variable such as NODE_ENV or load it from a configuration file - it's completely up to you!

This is what your pages/_app.js file should look like at this point:

// ./pages/_app.js

import { usePanelbear } from "@panelbear/panelbear-nextjs";

function CustomApp({ Component, pageProps }) {

  // Load Panelbear on app init
  usePanelbear("YOUR_SITE_ID", {
    debug: true
  });

  return <Component {...pageProps} />;
}

export default CustomApp;

Since we made changes to our Next.js main app, we'll need to restart the development server. Let's do that and refresh the page at http://localhost:3000/. If you open the console, you should see that an event is being triggered.

Debug mode Events are sent and logged to console on debug mode.

Also, if you now head to the Panelbear dashboard, you should see the page impression appearing shortly after it happened.

Analytics dashboard The analytics dashboard without much data yet.

You can also simply click on anything to filter for it. For example, on a dashboard with a lot of data I can filter for visits coming from the United States who found my site via Google.

Filter analytics example Example dashboard with more data.

That's great! Next let's review some useful features we could make use of in our application.

Track custom events

A really useful feature available in Panelbear is being able to record custom events. Events are simply data points collected during a visit. For example, a Pageview is the most common type of event, but you could also track Signup events or ButtonClick events if you wanted.

To send custom events, all you have to do is to call the Panelbear.track(...) function anywhere in your client-side code.

For example, here's how you would record a NewsletterSignup event as a form submit.

import * as Panelbear from "@panelbear/panelbear-js";
import { useState } from "react";

export function SignupForm(props) {
  const [email, setEmail] = useState("");

  const handleSubmit = (event) => {
    event.preventDefault();

    // Handle form submit
    alert(`Handling newsletter signup: ${email}`);

    // Record custom event on submit
    Panelbear.track("SignupNewsletter");
  };

  return (
    <form onSubmit={handleSubmit}>
      <label>
        Email:
        <input
          type="text"
          value={email}
          onChange={(e) => setEmail(e.target.value)}
        />
      </label>
      <input type="submit" value="Submit" />
    </form>
  );
}

Notice it's simply a matter of calling the function with the desired event name.

Here's what custom events look like on one of my dashboards:

Custom events example Example custom events.

What's interesting is that you can filter for one of them - say newsletter sign ups - and plot the conversion rate over time. For example:

Plotting conversion rate for custom events Plotting conversion rate for custom events.

You can use custom events for pretty much anything you can think of, but most applications use it to track product-related metrics (eg. signups, modals, which features are being used the most).

Monitor your app usage and performance

Out of the box, Panelbear records usage and performance stats on every visit. These stats include things such as the session country, referrers, page load time, and various timings such as time spent on the frontend, backend and network.

For example, here's what one of my site's performance dashboard looks like:

Website performance dashboard Website performance dashboard.

The data collection approach uses no tracking cookies, there's no way to trace the session data back to an individual, and Panelbear is funded by paid subscriptions, not by selling personal data to anyone.

To achieve this, all interactions made by a visitor are stripped out of personal data and grouped into short lived sessions. These sessions are isolated per site, only collect what is necessary, and automatically expire after a short period of inactivity.

Anonymizing specific URLs

Panelbear already strips out the most common places where sensitive data appears. Things like the IP-address, cookies, query parameters, and various other data points are already handled.

However, sometimes there's sensitive data being reported in the page URL. For example, in user setting pages such as /users/123456789/settings , the user ID is clearly visible in the page URL which will appear on the analytics dashboards. This could leak information about the session and some of the interactions this visitor performed on our site.

To modify the event data before it even reaches Panelbear's servers, we can make use of the beforeSend feature on the tracking snippet. It's a small hook that lets you transform or filter out events right before being sent.

Let's add this functionality to our Panelbear hook in the pages/_app.js file.

// ./pages/_app.js

import { usePanelbear } from "./../hooks/panelbear";

function CustomApp({ Component, pageProps }) {

    usePanelbear("YOUR_SITE_ID", {
        // Enable debug mode to send events locally
        debug: false,

        // Transform events before sending
        beforeSend: function (event) {
            if (event.url) {
                // Replace user ID with placeholder
                let match = /.*\/users\/([a-z-A-Z0-9]*)(\/.*)/gm.exec(event.url);
                if (match && match[1]) {
                    event.url = event.url.replace(match[1], "user_id");
                }
            }
            return event;
        }
    });

    return <Component {...pageProps} />;
}

export default CustomApp;

This will check if the event has a URL component, and try to search and replace user IDs into some placeholder value. For example, the /users/123456789/settings URL from earlier will be reported as /users/user_id/settings instead.

Receive alerts when something's up

Now that we have set up analytics and performance monitoring on our Next.js app, let's configure some alerts to get notified when our site is getting increased traffic.

But first, we'll need to configure a couple of notification channels. These are the integrations that should be notified when any alert triggers. It could be anything from the email of the marketing team to a Slack or Discord channel.

To do so, simply head to your Account Settings and click on Integrations.

Available integrations Available integrations.

Next, you can add any integrations you wish. For example you could use the email notification to send alerts to a "developers" or "on-call" team inbox, or you could even add a Slack or Discord channel dedicated to alerts - it's completely up to you!

Example Slack integration Example Slack integration.

Finally, now that we configured a couple of integrations let's setup our first alert. Simply go to the Alerts tab on your website's dashboard and click on New Alert.

You should now configure the alert to trigger when the number of visits in the past hour exceeds a desired threshold. You should also pick one or more integrations that should be notified.

Creating a new alert Creating a new alert.

Save it, and we’re done! In order to test the alert, you can click on the "Test" button to send an example alert.

Testing alerts via Slack Testing alerts via Slack.

You can of course create more alerts and different notification channels. Optionally you can also create page speed alerts, it's not only limited to traffic spikes.

Where to go from here

We've covered how to set up traffic and performance monitoring for our Next.js app. Additionally we saw how to track custom events, and anonymize sensitive pages to protect visitor privacy.

Of course, there's plenty more we could monitor about our application. For example there's uptime monitoring, runtime errors, and perceived performance with Core Web Vitals.

You can monitor pretty much every aspect about your application, and there's hundreds of tools available. That's why I also wrote a guide on the various website monitoring tools available, feel free to check it out too.

I hope you enjoyed this post, and it comes useful to you. Have any comments or questions? Feel free to shoot me a message on Twitter - I'm happy to help.

Panelbear analytics charts

Ready to try Panelbear?

It's free for small websites - no credit card required.