How to Implement Amplitude in Next.js 14 App Router

6 Min Read

blog img

Updated to 2024 standards

In this data-driven era, analytic tools like Amplitude Analytics are indispensable for startups. Amplitude, with its event-based analysis method, offers deep insights into user interactions. This is particularly critical during a product’s growth stages, as it allows for immediate evaluation of feature effectiveness upon production release. This enables rapid experimentation with different UI/UX strategies and the identification of problem areas. Effectively leveraging these insights can lead to a user experience finely tuned to your product’s audience, significantly boosting user retention. This article provides a guide on integrating Amplitude into a Next.js 14 App Router application, leveraging the latest advancements in frontend development.

Author note: Reflecting on my journey with Amplitude and Next.js, it’s astounding to see how much has changed since my first integration project. Back in the days of Next 12, everything was new and challenging. Now, after numerous integrations across personal, freelance, and professional projects, my expertise in Next.js, React, and React Native has grown immensely. I even shared my insights on integrating Amplitude in React Native in my last blog post.

As technology evolves, so does the server-side rendering capabilities and techniques recommended by Next.js. Keeping up-to-date is crucial, and that’s why, almost a year later, I’m revisiting this blog to infuse it with the wealth of experience I’ve gained and leveling up to the app router and server components.

Here’s a disclaimer: this is my subjective approach to setting up Amplitude in a Next.js app (I’m not a part of Amplitude’s team, yet 😆). There were numerous hurdles initially, and a guide like this would have been a lifesaver. Hopefully, my experiences can smooth out your learning path. For newcomers, check out the official Amplitude documentation here.

I’m going to assume that you have already created an account and obtained an API code from Amplitude. If you need help, don’t hesitate to ask in the comments or through Github Discussions.

For a practical start, explore this resources:
- Example Repo 😺
- Online demo 👾

Setting up a Next.js Application

First, create a new Next.js application and install the Amplitude library with the following commands:

yarn create next-app
yarn add @amplitude/analytics-browser

You can also clone the repository that I made to explain this blog:

git clone git@github.com:Ianduha13/nextjs14-amplitude-integration.git

Next, create a .env file in your project's root directory and add your Amplitude API key:

NEXT_PUBLIC_AMPLITUDE_API_KEY=Your_Amplitude_API_Key

Implement Amplitude in your Code

To integrate Amplitude, certain functions need to be included in your code. This involves initializing the Amplitude SDK and setting up event tracking.

Initialize Amplitude SDK: 
Based on my experience, I recommend encapsulating the SDK initialization logic in a context. This is particularly beneficial with Next.js’s App Router components, which are Server Components by default but can freely utilize a client context provider. This approach enables you to wrap your entire application and provide custom methods for using the SDK across all your client components (note: the Amplitude SDK is only available on the client side).

"use client";
import { useEffect, createContext } from "react";
import { init, track } from "@amplitude/analytics-browser";

const AMPLITUDE_API_KEY = process.env.NEXT_PUBLIC_AMPLITUDE_API_KEY;

export const AmplitudeContext = createContext({});

const AmplitudeContextProvider = ({ children }) => {
  useEffect(() => {
    init(AMPLITUDE_API_KEY, undefined, {
      defaultTracking: {
        sessions: true,
      },
    });
  }, []);

The init method plays a critical role in initializing the Amplitude SDK within your project. It's essential to call this method only on the first render, or at the specific moment you wish to start tracking user interactions. This ensures that the SDK setup doesn't unnecessarily repeat, which could lead to performance issues or skewed analytics.

The configurations used in the init method should align with the recommendations from the Amplitude documentation. In this case, I utilized sessions between the defaultTrackingoptions. By tailoring these settings, you can fine-tune the analytics to match the specific needs of your application.

Custom Tracking Functions:
Incorporating the Amplitude SDK into a Next.js application can be greatly optimized by defining custom functions within your context. These functions serve as a simplified and reusable interface for tracking specific events, ensuring consistency and efficiency across your application. Here’s how you can set up a basic custom tracking function:

// ...AmplitudeContextProvider previous setup
const trackAmplitudeEvent = (eventName, eventProperties) => {
    track(eventName, eventProperties);
};

const value = { trackAmplitudeEvent };

return (
    <AmplitudeContext.Provider value={value}>
      {children}
    </AmplitudeContext.Provider>
  );
};

export default AmplitudeContextProvider;

Then, in your root layout.js import the context provider and wrap your application.

//...Other imports
import AmplitudeContextProvider from "@/context/AmplitudeContext";
 
//...Layout configs
export default function RootLayout({ children }) {
  return (
    <html lang="en">
      <body className={inter.className}>
        <AmplitudeContextProvider>
          {children}
        </AmplitudeContextProvider>
      </body>
    </html>
  );
}

Once you finished with the context setup, a good practice to interact with it is using a custom hook:

import { useContext } from "react";
import { AmplitudeContext } from "../context/AmplitudeContext";

const useAmplitudeContext = () => {
  const context = useContext(AmplitudeContext);
  if (context === undefined)
    throw new Error(
      "useAmplitudeContext must be used within a AmplitudeContextProvider"
    );
  return context;
};

export default useAmplitudeContext;

Now you can use all the functions defined on the context on every client component that instantiates this custom hook 👆.

Starting to Track Events:

Once you’ve completed the setup, you’re ready to implement your tracking strategy within your code. In this hands-on example, we’ve crafted a button that does more than just respond to clicks. It turns each click into a data point, capturing the action and sending a hardcoded text message as an event property. Event and users properties and tracking strategies are really interestings topics, and we’ll explore that in a future blog 😉. 
But for now, let’s focus on this example:

"use client";
import useAmplitudeContext from "@/hooks/useAmplitudeContext";

const EventButton = () => {
  const { trackAmplitudeEvent } = useAmplitudeContext();

  const clickHandler = () => {
    trackAmplitudeEvent("click", {
      text: "each click is a new event, and each star or like helps me a lot!",
    });
  };

  return (
    <button
      type="button"
      className="bg-[#e8378b] w-96 py-6 text-center font-semibold px-10 mx-auto rounded-xl hover:scale-95 active:scale-105 transition-all duration-100 ease-in-out"
      onClick={clickHandler}
    >
      Press me to trigger an event!
    </button>
  );
};

export default EventButton;

Breaking Down the Code:

  • The Custom Hook (useAmplitudeContext): This hook connects us to AmplitudeContext, housing our trackAmplitudeEvent custom function.
  • Event Tracking Function (trackAmplitudeEvent): This function requires two arguments: the event name and an object with event properties (the last one it’s optional).
  • Button Component (EventButton): Here, our UI element becomes interactive. The button, when clicked, activates the clickHandler, which in turn invokes trackAmplitudeEvent, dispatching the event information to Amplitude. 🚀

Note that this example is a simplified version of which could be a production level analytics tracking, you have a lot of methods on the SDK with diferent purposes that will help you to know more about the usage of your product.
It’s amazing the world of possibilities that working with event-driven analytics opens up for us as developers, plus Amplitude is hugely customizable.

Congratulations! You can now visualize your first events on Amplitude 🚀

To view the tracked events, head to your Amplitude dashboard and select user-lookup in your navbar. You should see something like this:

If you want to see the “user stream” made for a user, you can select the userID provided in that list.

Which will display the following profile card, here you can visualize many very interesting and customizable data that can be very helpful when evaluating the engagement of a certain feature:

And that’s it! When a user press the button on the page, it triggers an event in the Amplitude analytics log. With this data, you can create custom charts and dashboards to better understand how your product is being used, all in-lined with your specific business needs.

💡 Here I leave you an official source to practice with sample data in a premium environment: https://analytics.amplitude.com/demo/home

Bonus Track: Online demo

Here is the page we developed through this tutorial, complicated, isn’t it? 🤣

Jokes aside, here’s a link to the online demo: https://next-amplitude.vercel.app/

If you visit the link and press the button, you’ll witness a real-time change in the chart within the Amplitude public link provided in the second button. You’ll see something like this:

Apologies if the chart is somewhat condensed, but charts can’t be shared with full access links as editors on Amplitude’s free plan.

Thank you for reading my article! It was a great experience for me, and I hope you found it valuable.

As a JavaScript developer, I’ll be sharing more insights and updates on my journey. If you’re interested in staying updated with my future posts, you can follow me on the following links:

I look forward to connecting with other developers 😃

Warm regards,
Ian Duhamel CTO at Devink 🚀