How to Integrate Analytics into a React/NextJS Application

RMAG news

🐙 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
)

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
}

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>
)
}

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>
)
}

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>
}

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

Please follow and like us:
Pin Share