M365 Dev Blog

Add Google Analytics to SharePoint modern pages

ga-sp

I had a client requirement to help them add Google Analytics to a modern SharePoint site. The objective was to track all SharePoint page views within the site.

The first thing that came to my mind was to look for a solution available online. As this is a fairly common scenario, I assumed it would be easy to find one for my requirements. But this was also what the client had tried to do before calling us, and they got stuck with some limitations on the solutions that they have found.
There are plenty of solutions available online for using Google Analytics with SharePoint modern pages. From complete implementations, to blog posts with the relevant code snippets. But I was also unable to find one that was able to track full and partial page loads. And so I decided to tweak one to work on the scenarios.

Base solution

The code below is based on the original solution provided by João Ferreira on this blog post. He uses an SPFx application customizer to load the Google Analytics script on every SharePoint page. When testing it, we found that it was not tracking all the page loads, so we updated it slightly.

Additionally, the this.context.application.navigatedEvent event currently has a known bug and fires twice. The workaround provided by jonthenerd worked fine in this scenario.
2019-03-01 update: The bug on the navigatedEvent seems to be fixed now, so I have updated the code below. I have also sent a PR with the changes to the original repository (by João Ferreira). You can find a full implementation project on his post.

Code

The following code uses the approach provided by Google Analytics for tracking Single Page Applications, like SharePoint pages that only load partially..

Hope you fins this useful, and feel free to leave comments or provide feedback.

export default class AnalyticsApplicationCustomizer
  extends BaseApplicationCustomizer<IAnalyticsApplicationCustomizerProperties> {

  private isInitialLoad = true;

  private getFreshCurrentPage(): string {
    return window.location.pathname + window.location.search;
  }


  private navigatedEvent(): void {

    let trackingID: string = this.properties.trackingID;
    if (!trackingID) {
      Log.info(LOG_SOURCE, `${strings.MissingID}`);
    } else {

      if (this.isInitialLoad) {
        this.initialNavigatedEvent(trackingID);
        this.isInitialLoad = false;

      }
      else {
        this.partialNavigatedEvent(trackingID);
      }
    }
  }

  private initialNavigatedEvent(trackingID: string): void {

    console.log("Tracking full page load...");

    var gtagScript = document.createElement("script");
    gtagScript.type = "text/javascript";
    gtagScript.src = `https://www.googletagmanager.com/gtag/js?id=${trackingID}`;
    gtagScript.async = true;
    document.head.appendChild(gtagScript);

    eval(`
          window.dataLayer = window.dataLayer || [];
          function gtag(){dataLayer.push(arguments);}
          gtag('js', new Date());
          gtag('config',  '${trackingID}');
        `);
  }

  private partialNavigatedEvent(trackingID: string): void {

    console.log("Tracking partial page load...");

    eval(`
        if(ga) {
          ga('create', '${trackingID}', 'auto');
          ga('set', 'page', '${this.getFreshCurrentPage()}');
          ga('send', 'pageview');
        }
        `);
  }

  @override
  public onInit(): Promise<void> {

    this.context.application.navigatedEvent.add(this, this.navigatedEvent);

    return Promise.resolve();
  }
}
Exit mobile version