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
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()
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"
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
}
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
}
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)
}
}
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)
}
}
This merely logs the events to the console. It's useful for debugging events during development.