How to Integrate Analytics into a React/NextJS Application

radzion

Radzion Chachura

Posted on July 22, 2024

How to Integrate Analytics into a React/NextJS Application

šŸ™ GitHub

Integrating Analytics into a React Application

In this article, we'll explore a reusable method for integrating analytics into a React application. We'll use Amplitude analytics within a Next.js app as our example, but the same principles can be applied to any React app and analytics provider. All the reusable code for this article can be found in the RadzionKit repository.

In our app, we'll use two main functions to handle analytics:

  • setUser - This function sets the user ID for tracking purposes.
  • trackEvent - This function tracks events. It takes the event name and an optional data object, allowing us to pass any additional information about the event we want to track.
import { createContextHook } from "@lib/ui/state/createContextHook"
import { createContext } from "react"

export type AnalyticsContextState = {
  setUser: (id: string) => void
  trackEvent: (name: string, data?: Record<string, any>) => void
}

export const AnalyticsContext = createContext<
  AnalyticsContextState | undefined
>(undefined)

export const useAnalytics = createContextHook(
  AnalyticsContext,
  "AnalyticsContext"
)
Enter fullscreen mode Exit fullscreen mode

Using React Context API for Analytics Integration

We'll use React's context API to provide these functions to our components. The decision to use the context API instead of utility functions will become clearer when we examine the PageVisitTracker component. At Increaser, we use this component to track page visits on both the website and the app. The PageVisitTracker doesn't need to know which analytics tool we're using. It's the responsibility of the app and website projects to wrap the PageVisitTracker in the appropriate context provider.

import { useAnalytics } from "@lib/analytics-ui/AnalyticsContext"
import { useRouter } from "next/router"
import { useEffect } from "react"

export const PageVisitTracker = () => {
  const { pathname } = useRouter()
  const { trackEvent } = useAnalytics()

  useEffect(() => {
    trackEvent("Visit page", { pathname })
  }, [trackEvent, pathname])

  return null
}
Enter fullscreen mode Exit fullscreen mode

Local and Amplitude Analytics Providers

When running the app locally, we don't need to spam our analytics provider with events. For local development, we use the LocalAnalyticsProvider, which simply logs the events to the console.

import { ComponentWithChildrenProps } from "@lib/ui/props"
import { AnalyticsContext, AnalyticsContextState } from "./AnalyticsContext"

const localAnalytics: AnalyticsContextState = {
  setUser: (id) => {
    console.log("Set user for analytics: ", id)
  },
  trackEvent: (name, data) => {
    console.log("Track event: ", name, data)
  },
}

export const LocalAnalyticsProvider = ({
  children,
}: ComponentWithChildrenProps) => {
  return (
    <AnalyticsContext.Provider value={localAnalytics}>
      {children}
    </AnalyticsContext.Provider>
  )
}
Enter fullscreen mode Exit fullscreen mode

Our AmplitudeAnalyticsProvider offers the setUser and trackEvent functions using the Amplitude analytics library. We initialize the Amplitude library with the provided API key when the component mounts.

import { useEffect } from "react"
import * as amplitude from "@amplitude/analytics-browser"
import { AnalyticsContext, AnalyticsContextState } from "./AnalyticsContext"
import { ComponentWithChildrenProps } from "@lib/ui/props"

type AmplitudeAnalyticsProviderProps = ComponentWithChildrenProps & {
  apiKey: string
}

const amplitudeAnalytics: AnalyticsContextState = {
  setUser: (id) => {
    amplitude.setUserId(id)
  },
  trackEvent: (name, data) => {
    amplitude.track(name, data)
  },
}

export const AmplitudeAnalyticsProvider = ({
  apiKey,
  children,
}: AmplitudeAnalyticsProviderProps) => {
  useEffect(() => {
    amplitude.init(apiKey)
  }, [apiKey])

  return (
    <AnalyticsContext.Provider value={amplitudeAnalytics}>
      {children}
    </AnalyticsContext.Provider>
  )
}
Enter fullscreen mode Exit fullscreen mode

Integrating the Analytics Provider into a Next.js App

Now, let's see how we put it all together within our Next.js app. First, we create an AnalyticsProvider component that checks if the app is running in production. If it is, we use the AmplitudeAnalyticsProvider with the API key taken from environment variables. Otherwise, we use the LocalAnalyticsProvider.

import { shouldBeDefined } from "@lib/utils/assert/shouldBeDefined"
import { ComponentWithChildrenProps } from "@lib/ui/props"
import { AmplitudeAnalyticsProvider } from "@lib/analytics-ui/AmplitudeAnalyticsProvider"
import { LocalAnalyticsProvider } from "@lib/analytics-ui/LocalAnalyticsProvider"

export const AnalyticsProvider = ({ children }: ComponentWithChildrenProps) => {
  if (process.env.NODE_ENV === "production") {
    return (
      <AmplitudeAnalyticsProvider
        apiKey={shouldBeDefined(process.env.NEXT_PUBLIC_AMPLITUDE_API_KEY)}
      >
        {children}
      </AmplitudeAnalyticsProvider>
    )
  }

  return <LocalAnalyticsProvider>{children}</LocalAnalyticsProvider>
}
Enter fullscreen mode Exit fullscreen mode

Finally in the _app.tsx file, we wrap our app with the AnalyticsProvider component and place the PageVisitTracker component inside it. This way, we can track page visits across the entire app.

import { AnalyticsProvider } from "../analytics/AnalyticsProvider"
import { PageVisitTracker } from "@lib/next-ui/PageVisitTracker"

function MyApp() {
  return (
    <AnalyticsProvider>
      <PageVisitTracker />
      // ...
    </AnalyticsProvider>
  )
}

export default MyApp
Enter fullscreen mode Exit fullscreen mode
šŸ’– šŸ’Ŗ šŸ™… šŸš©
radzion
Radzion Chachura

Posted on July 22, 2024

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related