Utiliser OpenReplay avec Next.js

Découvrez comment faire fonctionner le tracker sur votre application Next.js

Utiliser OpenReplay avec Next.js

Faire fonctionner le tracker sur une application Next.js est assez simple. Comme Next.js repose sur React, le processus est très similaire ; la principale difficulté provient des capacités de rendu côté serveur (Server Side Rendering) de Next.js.

Mais une fois que vous aurez compris comment elles fonctionnent et comment structurer votre code réservé au client, vous suivrez vos utilisateurs en un rien de temps.

Bien que vous puissiez obtenir une version à copier-coller du code directement depuis la plateforme lorsque vous créez un nouveau projet, ce code est trop sommaire et risque de ne pas respecter les bonnes pratiques attendues par votre équipe ou votre entreprise.

Cette méthode propose une approche minimaliste dans laquelle nous injectons le tracker dans l’application sous forme de composant, qui chargera la bibliothèque de manière dynamique.

App Router (v14+) - use client

Section titled App Router (v14+) - use client
'use client'
import { useEffect } from "react"
// note that you can manually import Tracker class if you want to handle the instance manually
import { tracker } from '@openreplay/tracker'

tracker.configure({
  projectKey: PROJECT_KEY,
  ingestPoint: "https://openreplay.mydomain.com/ingest", // when dealing with the self-hosted version of OpenReplay
})

const Openreplay = () => {
  useEffect(() => {
    if (typeof window !== 'undefined') {
      tracker.start()
    }
  }, [])

  return null
}

export default Openreplay 
App Router - importer dynamiquement l’instance du composant Openreplay dans le layout racine
Section titled App Router - importer dynamiquement l’instance du composant Openreplay dans le layout racine
import dynamic from "next/dynamic";

const OpenReplayNoSSR = dynamic(() => import('//import the Openreplay instance'), {
  ssr: false, //disables Server-side pre-rendering so window won't be undefined
})

export default function RootLayout({ children }) {
  return (
    <html lang="en" >
      <body>
        {children}
        <OpenReplayNoSSR />
      </body>
    </html >
  );
}

Composant classique (Next jusqu’à v13)

Section titled Composant classique (Next jusqu’à v13)
[...]

function TrackerComponent() {
const [tracker, setTracker] = React.useState(null);

  React.useEffect(() => {
    (async function () {
      const { tracker } = await import("@openreplay/tracker");
      tracker.configure({
        projectKey: PROJECT_KEY,
        ingestPoint: "https://openreplay.mydomain.com/ingest", // when dealing with the self-hosted version of OpenReplay
        __DISABLE_SECURE_MODE: true,
      });

      setTracker(tracker);
    })();
  }, []);
[...]

cette méthode vous permet de créer un contexte qui, à son tour, facilite le contrôle de l’état du tracker et l’appel de ses différentes API.

import { createContext } from "react"
import {v4 as uuidV4} from 'uuid'
import { useReducer } from "react"

export const TrackerContext = createContext()

function defaultGetUserId() {
   return uuidV4() 
}

async function newTracker(config) {
    // we use dynamic import to make sure that tracker is started inside browser env
    const { tracker } = await import("@openreplay/tracker");
    const getUserId = (config?.userIdEnabled && config?.getUserId) ? config.getUserId : defaultGetUserId
    let userId = null;

    const trackerConfig = {
        projectKey: config?.projectKey || process.env.NEXT_PUBLIC_OPENREPLAY_PROJECT_KEY
    }

    tracker.configure(trackerConfig);
    
    if(config?.userIdEnabled) {
        userId = getUserId()
        tracker.setUserID(userId)
    }
    return tracker

}

function reducer(state, action) {
        switch(action.type) {
            case 'init': {
                if(!state.tracker) {
                    console.log("Instantiaing the tracker for the first time...")
                    return {...state, tracker: newTracker(state.config)}
                }
                return state
            }
            case 'start': {
                console.log("Starting tracker...")
                state.tracker.start()
                return state
            }
        }
    }

export default function TrackerProvider({children, config = {}}) {
    let [state, dispatch] = useReducer(reducer, {tracker: null, config})
    let value = {
        startTracking: () => dispatch({type: 'start'}),
        initTracker: () => dispatch({type: 'init'})
    }

    return <TrackerContext.Provider value={value}>{children}</TrackerContext.Provider>
}

Ce provider met 2 méthodes à la disposition de l’utilisateur :

  • initTracker : qui instancie le tracker avec la configuration fournie.
  • startTracking : qui déclenche le démarrage du processus de suivi.

Ce provider accepte également un objet de « configuration » que vous pouvez étendre pour de futures fonctionnalités. Cet exemple vous montre comment activer, de manière facultative, la possibilité d’identifier les utilisateurs de façon unique. Vous pouvez utiliser un UUID par défaut qui serait unique pour chaque utilisateur à chaque fois qu’il visite la page. Vous pouvez également fournir une fonction getUserId personnalisée dans le cadre de la configuration.

Avec votre fonction personnalisée, vous pourriez fournir l’ID client de votre boutique, l’adresse e-mail de l’utilisateur ou tout ce qui identifie de manière unique l’utilisateur au sein de votre application. De cette façon, vous pouvez suivre les rejeux de leurs sessions au fil du temps au cas où ils rencontreraient un problème particulier que d’autres ne signalent pas.

Gérer le « projectKey » dans votre code

Section titled Gérer le « projectKey » dans votre code

À titre de remarque, le projectKey que vous configurez est celui fourni par la plateforme d’OpenReplay. Pour des raisons de sécurité, cette valeur ne devrait pas être stockée en dur (hardcoded) dans votre code, mais plutôt dans une sorte de fichier/système de configuration.

Pour cet exemple, je tire parti des fichiers .env de Next. Ce que vous devez comprendre, c’est que si vous ne préfixez pas la variable d’environnement par NEXT_PUBLIC, votre code client (le tracker) n’y aura pas accès.

Si cela n’est pas acceptable, vous pouvez utiliser getStaticProps depuis la première page que vos utilisateurs visitent pour récupérer cette valeur avant d’instancier le tracker. Vous pouvez voir les deux exemples ci-dessous.

Utiliser le contexte du tracker

Section titled Utiliser le contexte du tracker

Importez et enveloppez votre application avec le TrackerProvider que nous avons créé précédemment, comme ceci :

import '../styles/globals.css'
import TrackerProvider from '../context/trackerContext'

function MyApp({ Component, pageProps }) {

  return <TrackerProvider>
        <Component {...pageProps} />
    </TrackerProvider>
}

export default MyApp

Il s’agit du fichier _app.js, qui sert de point d’entrée pour l’ensemble de l’application.

Ensuite, vous pouvez déclencher le suivi depuis n’importe quel composant de votre choix, comme ceci :

import { useContext, useEffect } from 'react'
import { TrackerContext } from '../context/trackerContext'
import styles from '../styles/Home.module.css'

export default function YourComponent({projectKey}) {
    
    const {initTracker, startTracking} = useContext(TrackerContext)
    
    useEffect( () => {
       initTracker()
       startTracking()
    }, [])
//.... rest of your code
}

Si vous n’avez pas besoin d’autant de contrôle, vous pouvez réunir les deux, le « message init » et le « message start tracking », de sorte que vous n’ayez à appeler qu’une seule fonction pour démarrer le suivi.

Pour consulter le code complet d’une application fonctionnelle basée sur Next, vous pouvez consulter ce dépôt.

Si vous rencontrez des problèmes pour configurer le tracker sur votre projet basé sur Next, contactez-nous sur notre communauté Slack et posez vos questions directement à nos développeurs !