DEV Community

Cover image for Integrating Amplitude Analytics with NextJS App: A Comprehensive Guide
Rodion Chachura
Rodion Chachura

Posted on • Originally published at radzion.com

Integrating Amplitude Analytics with NextJS App: A Comprehensive Guide

Watch on YouTube | 🐙 GitHub | 🎮 Demo

Let's add Amplitude analytics to a NextJS app!

In the example below, we will track page views by calling the trackEvent method on the analytics instance from the useEffect hook:

function MyApp({ Component, pageProps }: AppProps) {
  const { pathname } = router
  useEffect(() => {
    analytics.trackEvent("Visit page", { pathname })
  }, [pathname])

  return <p>my app</p>
}

export default MyApp
Enter fullscreen mode Exit fullscreen mode

This is how you create the analytics instance for your app:

import { isProduction } from "shared"
import { shouldBeDefined } from "@increaser/utils/shouldBeDefined"
import { AmplitudeAnalytics } from "@increaser/ui/analytics/AmplitudeAnalytics"
import { LocalAnalytics } from "@increaser/ui/analytics/LocalAnalytics"

export const analytics = isProduction
  ? new AmplitudeAnalytics(
      shouldBeDefined(process.env.NEXT_PUBLIC_AMPLITUDE_API_KEY)
    )
  : new LocalAnalytics()
Enter fullscreen mode Exit fullscreen mode

First, we check if the environment is set to production. We want to avoid sending analytics events in development or testing environments.

export const isProduction = process.env.NODE_ENV === "production"
Enter fullscreen mode Exit fullscreen mode

The shouldBeDefined function will throw an error if the value is undefined. This is useful to ensure we never forget to set the environment variable.

export function shouldBeDefined<T>(
  value: T | undefined,
  valueName: string = "value"
): T {
  if (value === undefined) {
    throw new Error(`${valueName} is undefined`)
  }

  return value
}
Enter fullscreen mode Exit fullscreen mode

Both AmplitudeAnalytics and LocalAnalytics adhere to the same interface, which should include:

  • setUser: used to associate the user with the analytics events. This would only be used if your app or website has authenticated users.
  • trackEvent: used to track events. Extra info can be passed into the second argument, such as the name of the page in our previous example.
export interface Analytics {
  setUser: (id: string) => void
  trackEvent: (name: string, data?: Record<string, any>) => void
}
Enter fullscreen mode Exit fullscreen mode

Here's how you would implement AmplitudeAnalytics:

import { Analytics } from "./Analytics"
import * as amplitude from "@amplitude/analytics-browser"

export class AmplitudeAnalytics implements Analytics {
  apiKey: string
  isInitialized: boolean = false

  constructor(apiKey: string) {
    this.apiKey = apiKey
  }

  private initialize() {
    if (!this.isInitialized) {
      amplitude.init(this.apiKey)
      this.isInitialized = true
    }
  }

  setUser(id: string) {
    this.initialize()
    amplitude.setUserId(id)
  }

  trackEvent(name: string, data?: Record<string, any>) {
    this.initialize()
    amplitude.track(name, data)
  }
}
Enter fullscreen mode Exit fullscreen mode

It requires the @amplitude/analytics-browser package to be installed and an apiKey to be passed as a constructor argument. We don't initialize Amplitude immediately; instead, we only do so the first time setUser or trackEvent is called. This ensures that requests are only sent to Amplitude upon tracking.

Here's how you can implement LocalAnalytics:

import { Analytics } from "./Analytics"

export class LocalAnalytics implements Analytics {
  constructor() {
    console.log("Initialize local analytics")
  }

  setUser(id: string) {
    console.log("Set user for analytics: ", id)
  }

  trackEvent(name: string, data?: Record<string, any>) {
    console.log("Track event: ", name, data)
  }
}
Enter fullscreen mode Exit fullscreen mode

This merely logs the events to the console. It's useful for debugging events during development.

Top comments (0)