15-Dec

JavaScript, React

Azure Application Insights using Javascript SDK in Next.js

Do you need help with the Javascript SDK for Application Insights? Look no further! This guide will help you go from zero to hero in no time 📈

3 min read

·

By Toralf Frich

·

December 15, 2022

Enabling the Javascript SDK for enabling Application Insights in a Next.js application is not as easy as it may sound. This guide will show you how to do it (so that you don’t have to spend as much time as I did on it) ⏳.

Next.js has a problem with not enabling execution of code prior to starting your application (unless you create your own custom server). Hence, there are no obvious files to place the code that is needed to create an Application Insights-instance in you app.

In this article, a small workaround is presented along with a step-by-step guide on how to enable Application Insights in your Next.js application 🚶.

Step-by-step guide🚶

  1. Install @microsoft/applicationinsights-web using npm or yarn
  2. Create a file where you can initialise and retrieve an appInsights-instance.
  3. Create a component that uses a useEffect to only initialise the appInsights-instance once.
  4. Retrieve the environment variables needed to initialise the appInsights-instance and ensure that the instance is set up the first time a user navigates to any application page.
  5. Track what you want! 🎉

Step 1:

Install @microsoft/applicationinsights-web in node_modules using npm or yarn (I use yarn below) 💻:

yarn add @microsoft/applicationinsights-web

Step 2:

Create a file that initialises an appInsights-instance and returns the initialised appInsights-instance when you need it for tracking.

Below is the code that is given to us in the azure documentation 📄

import { ApplicationInsights } from '@microsoft/applicationinsights-web'

const appInsights = new ApplicationInsights({ config: {
  connectionString: 'Copy connection string from Application Insights Resource Overview'
  /* ...Other Configuration Options... */
} });

appInsights.loadAppInsights();

But! Where to place this code? If you place it in _app.js, it will be run every time a file in the pages directory is loaded, moreover, creating new appInsights instances all the time! This is bad. We want it to run only once (because otherwise we would be creating a lot of unnecessary appInsights-instances) 🤔.

Hence, we create this modified version where it is possible to run initAI to initialise the appInsights-instance and get the appInsights-instance by running getAppInsights:

import { ApplicationInsights } from '@microsoft/applicationinsights-web';

let ai: ApplicationInsights;

export const ai = () => {
    const initAI = (cS: string) => {
        ai = new ApplicationInsights({ config: { connectionString: cS } });
        ai.loadAppInsights();
    };

    return { ai, initAI };
};

export const getAppInsights = () => ai;

Step 3:

Ensure that we only initialise the appInsights-instance once.

We do this by making use of a useEffect, creating a file with a react component looking something like below.

import { useEffect, useState } from 'react';
import { ai } from './appInsightsSetup';

interface AppInsightsProps {
    connectionString?: string;
    children?: React.ReactNode;
}
const AppInsights = ({ children, connectionString }: AppInsightsProps) => {
  const [activated, setActivated] = useState<boolean>(false);
  
  useEffect(() => {
      if (!activated && connectionString) { 
          ai().initAI(connectionString);
          setActivated(true);
      }
  }, [activated, connectionString]);
  
  return <>{children}</>;
};

Step 4:

Retrieving the connectionString from the environment-variables so that the appInsights-instance can be initialised.

As all the code that we have written is client-side, we do not have access to the connectionString (as it is most likely an environment variable). Hence, we need to retrieve it and then drill it down to the component and the functions that we have created — allowing us to initialise the appInsights-instance 🙌.

Below, we use Next.Js’ getInitialProps to retrieve the connectionString-environment-variable (this might change with the introduction of Next.Js 13).

import App from 'next/app';
import AppInsightsProvider from '../utils/appInsights/AppInsightsProvider';

function MyApp({ Component, pageProps, environment, cS }) {
    return (
        <div>
            <AppInsightsProvider connectionString={cS}>
                    <Component {...pageProps} />
            </AppInsightsProvider>
        </div>
    );
}

MyApp.getInitialProps = async (appContext) => {
    const appProps = await App.getInitialProps(appContext);
    return { 
      ...appProps, 
      cS: process.env.CONNECTION_STRING as string;
    };
};

export default MyApp;

Step 5:

That should be it! You can now track whatever you want.

E.g., tracking a page view 📄 👀

import { getAppInsights } from 'utils/appInsights/appInsightsSetup';

const appInsights = getAppInsights();
appInsights.trackPageView({ name: page });

The end

That should be it. And your resulting file structure should look something like this:

- Pages
  - _app.js
- utils
  - appInsights
    - appInsightsHelpers.ts
    - appInsightsSetup.ts
    - AppInsights.tsx


Bye 👋