Suche
Kolumne: Webentwicklung mit Angular

So funktioniert Google Analytics mit Angular-Anwendungen

Karsten Sitterberg

(c) Shutterstock / grmarc

Wie interagieren Nutzer mit der eigenen Webanwendung? Antworten auf diese Frage bieten Web-Performance-Tools wie Google Analytics. Karsten Sitterberg beschreibt in dieser Kolumne, wie sich Angular-Anwendungen mit Google Analytics verbinden lassen.

Um Anwendungen verbessern zu können, benötigt man eine Datenbasis, mit der man Veränderungen objektiv messen und bewerten kann. Ein erfolgversprechender Weg ist, mit Hilfe von spezieller Statistiksoftware Nutzungsdaten zu erheben. Auf Basis definierter Ziele kann dann analysiert werden, welche Schritte im Prozess optimiert oder wie die Oberfläche verbessert werden kann und ob Veränderungen die gewünschten Effekte erzielen.

Google Analytics

Google bietet mit Google Analytics ein kostenloses Produkt zur Erhebung und Auswertung solcher Nutzungsdaten an. Google Analytics wird in diesem Artikel zur Veranschaulichung verwendet, da es jedem Leser prinzipiell ohne große Hürden für eigene Experimente zur Verfügung steht.

Dabei dient die konkrete Verwendung von Google Analytics auch zur Demonstration allgemeiner Konzepte zur Nutzung von JavaScript APIs von Drittanbietern mit Angular Services.

Zum besseren Verständnis werfen wir zuerst einen Blick auf Google Analytics und dessen Einsatz in Webseiten.

Google Analytics besteht aus zwei Teilen: Der erste ist der Server, zu dem Daten gesendet werden und auf dem auch die Auswertung der Daten stattfindet. Der Server stellt zudem die üblicherweise eingesetzte Oberfläche zur Nutzung der Auswertungsfunktionen bereit. Der andere Teil ist eine JavaScript-Bibliothek, die in Webseiten eingebunden wird und ein eigenes JavaScript API bereitstellt. Über dieses API lässt sich genau steuern, wann und welche Daten an den Analytics Server gesendet werden.

Die gesendeten Daten werden als Events bezeichnet. Google Analytics unterstützt unterschiedliche Event-Typen, der einfachste ist die Navigation von einer URL zur nächsten. Auf einer normalen Webseite wird der reguläre Google Analytics Code so eingebunden, dass er die benötigten JavaScript-Anteile lädt, initialisiert und den URL-Aufruf als Event signalisiert. Diese drei Schritte sehen dann zusammengefasst in einem Skriptblock so aus:

<script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||
function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new
Date();a=s.createElement(o),
m=s.getElementsByTagName(o)
[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','//www.google-analytics.com/
analytics.js','ga');
  ga('create', 'UA-XXXXX-Y', 'auto');
  ga('send', 'pageview');
</script>

Der Einstiegspunkt in das Google Analytics API ist das global bereitgestellte Property ga, welches durch die Einbindung von analytics.js  erzeugt wird. Der Aufruf ga-create initialisiert das API und ordnet folgende Aufrufe einer Instanz zu, die mit UA-XXXXX-Y benannt ist. Die Verwaltung der Instanzen erfolgt über den Google Analytics Server. Der Aufruf zur Initialisierung soll – und darf – nur einmal pro aufgerufener Webseite erfolgen. Der Aufruf ga-send schließlich übermittelt einen “pageview”, also einen Seitenaufruf an den Google Analytics Server.

Da Angular-Anwendungen sogenannte Single-Page-Anwendungen sind, findet kein echtes Laden von verschiedenen Webseiten statt. Stattdessen tauscht der Angular Router einzelne Views gegeneinander aus. Damit gilt es also folgende Anforderungen zu erfüllen:

  1. (Einmaliges) Initialisieren des Google Analytics API
  2. Senden von “pageview” Events nach jedem erfolgten Routing innerhalb der Anwendung
  3. Optional: Übermittlung zusätzlicher Daten. Diese können dazu dienen, ein Kundensegment zuzuordnen oder den Besucher in einem A/B-Test einer der beiden Gruppen zuzuweisen

Initialisierung

Zur Initialisierung wird auch in einer Angular-Anwendung eine Tracking-ID benötigt. Diese sollte konfigurierbar und nicht fest im Angular Code eingebaut sein. Daher erfolgt die Konfiguration im Beispiel durch ein globales “analytics” Objekt, das die Konfigurationswerte bereitstellt und in der index.html definiert wird, die auch die Angular-Anwendung enthält.

Der wichtigste Wert für die Konfiguration ist die zu verwendende Tracking-ID, weitere Parameter kommen später noch dazu. Daher wird die Konfiguration als Objekt angelegt:

<html>
...
<script>
var analytics = {trackingId = “UA-XXXXX-Y”};
</script>
...
</html>

Zur Umsetzung in Angular wird ein Service entwickelt, der die Initialisierung des Google Analytics API übernimmt und dabei auch sicherstellt, dass keine mehrfache Initialisierung stattfindet. Wird kein Konfigurations-Objekt gefunden, so werden die Aufrufe des Services einfach ignoriert. Darüber lässt sich dann beispielsweise für die lokale Entwicklung die Verwendung von Google Analytics vollständig deaktivieren. Da Angular Services dem Singleton-Entwurfsmuster folgen, eignen sich diese bestens dazu, mehrfache Instanziierungen oder Initialisierungen externer JavaScript-Bibliotheken zu verhindern.

Für das Beispiel erfolgt der Zugriff auf die Konfigurationswerte ohne dezidierten Konfiguration-Service, sondern direkt über das globale “analytics” Property, sodass sich der Analytics Service im Entwurf wie folgt darstellt:

exports class AnalyticsService {
  constructor() {
   this.initializeAnalytics();
 }
  private initializeAnalytics() {
    if (!analytics || !analytics.trackingId) {
      return;
    }
    (function (i, s, o, g, r, a?, m?) {
     i['GoogleAnalyticsObject'] = r;
     i[r] = i[r] || function () {
           (i[r].q = i[r].q || []).push(arguments)
       }, i[r].l = 1 * <any>new Date();
     a = s.createElement(o),
     m = s.getElementsByTagName(o)[0];
     a.async = 1;
     a.src = g;
     m.parentNode.insertBefore(a, m)
   })(window, document, 'script',   '//www.google-analytics.com/analytics.js', 'ga');
  }
}

 

Entwicklung

Damit auch zum Entwicklungszeitpunkt Daten übermittelt werden, zum Beispiel von “localhost”, ist es erforderlich, die “cookieDomain” zu deaktivieren.


ga('create', 'UA-XXXX-Y', {
'cookieDomain': 'none'
});

Die zugehörige (globale) Konfiguration wird daher so festgelegt:

analytics.cookieDomain = ‘none’;

Werfen wir einen Blick auf das Thema Diagnose: Gerade am Anfang der Implementierung ist es sinnvoll, die Debug-Ausgabe von Google Analytics aktivieren zu können. Dazu wird eine spezielle Debug-Version des Google Analytics JavaScript API geladen, die von dieser URL stammt:

https://www.google-analytics.com/analytics_debug.js

Anschließend kann durch das globale Property “ga_debug” die Debug-Ausgabe aktiviert werden, bevor der “create”-Aufruf erfolgt. Im regulären JavaScript sieht das wie folgt aus:


window.ga_debug = {trace: true};
ga('create', 'UA-XXXXX-Y');

Auch dieses Verhalten soll in den Angular Google Analytics Service aufgenommen werden und sich durch die globale Konfiguration steuern lassen. Als Einstellung wird dazu dann analytics.debug = true; gewählt. Diese beiden Konfigurationsschritte werden ebenfalls in die initializeAnalytics()-Methode des Angular Service aufgenommen:

export class AnalyticsService {
  private active: boolean = false;
  private initializeAnalytics() {
    /* ... */
    if (analytics.debug) {
      window['ga_debug'] = {trace: true};
    }
    if (analytics.cookieDomain) {
      ga('create', analytics.trackingId, {
        'cookieDomain': analytics.cookieDomain
      });
    } else {
      ga('create', analytics.trackingId, 'auto');
    }
        this.active = true;
  }

Um nachzuprüfen, ob die Initialisierung des Services über das globale analytics-Objekt erfolgreich war, wird das Property active eingeführt, welches am Ende des Initialisierungsprozesses auf true gesetzt wird.

Tracking

Damit am Ende eines jeden Routing-Vorgangs innerhalb der Anwendung ein Google Analytics Event gefeuert wird, kann auf die Routing-Events des Angular-Routers gelauscht werden. In diesem Beispiel wird zunächst überprüft, ob das Event vom Typ NavigationEnd ist, welches am Ende eines jeden Navigationsvorganges gefeuert wird. Dann wird der AnalyticsService aufgerufen, welcher das Tracking der momentanen URL übernimmt.


export class AppComponent implements OnInit{
  constructor(
    private router: Router,
    private analytics: AnalyticsService ) {}
  ngOnInit(){
    this.router.events
      .subscribe(event => {
        if (event instanceof NavigationEnd) {
          this.analytics.trackPageView(event.urlAfterRedirects);
        }
      });
  }
}

Die Methode trackPageView() bekommt die URL der momentanen Route als String übergeben. Zunächst wird dem Google Analytics-Skript die neue URL übergeben, um diese dann als “pageview” an Google zu senden.

exports class AnalyticsService {
/*...*/
  public trackPageView(page: string) {
        if (!this.active) {
            return;
        }
        ga('set', 'page', page);
        ga('send', 'pageview');
  }
}

Mit eingeschaltetem Debug-Modus sollte dann beim Routing innerhalb der Seite eine Ausgabe auf der Browserconsole sichtbar werden, die in etwa folgendem Bild entspricht:

Die korrekte Einbindung und auch die einzelnen Zustände und Ereignisse lassen sich mit den Logausgaben überprüfen bzw. nachvollziehen. Ergänzend dazu kann über die Google-Analytics-Echtzeitansicht kontrolliert werden, ob Daten bei den Trackingservern ankommen und korrekt zugeordnet werden.

Event Tracking

Will man nicht nur einfache Pageviews tracken, sondern auch dezidierte Events als Reaktionen auf Interaktionen, die der User auf der Website tätigt, so kann dies ebenfalls über das bereitgestellte API erreicht werden. Der AnalyticsService stellt dafür die sendEvent()-Methode zur Verfügung. Mit dieser Methode wird ein Event erzeugt, das einstellbare Parameterkategorien, Actions und Label hat. Die Methode beinhaltet auch eine Überprüfung, ob die Initialisierung erfolgreich war und Events generiert werden sollen, indem der Wert des “active” Property geprüft wird.

export class AnalyticsService {
  /* ... */
  public sendEvent(value: {category: string, action: string, label?: string}) {
    if (!this.active) {
      return;
    }
    ga('send', {
      hitType: 'event',
      eventCategory: value.category,
      eventAction: value.action,
      eventLabel: value.label
    });
  }
}

Aufgerufen wird diese Methode an passender Stelle, wobei ein entsprechendes Event-Objekt übergeben werden muss. Der Aufruf ist in folgendem Quelltext zu sehen:

this.analytics.sendEvent({
  category: 'Videos',
  action: 'play',
  label: 'General Teaser'
});
this.analytics.sendEvent({
  category: 'Videos',
  action: 'finished',
  label: 'General Teaser'
});

Custom Dimension

In einer tiefergehenden Analyse einer Seite ist es oft nicht ausreichend, Seitenaufrufe lediglich einem Nutzer zuzuordnen. Stattdessen werden zusätzliche Informationen benötigt, beispielsweise die EAN-Nummer des Produktes in einer Shop-Anwendung, welches einen Klickpfad ausgelöst hat; oder welcher Gruppe in einem A/B-Test ein Nutzer zugeordnet wird.

Dies lässt sich mit Google Analytics über eigene “Dimensionen” abbilden, die man den Aufrufen hinzufügen kann. Der JavaScript-Aufruf von Google Analytics sieht dabei folgendermaßen aus:

ga('set', 'dimension1', 'ean:123');

Der AnalyticsService sollte diese Funktionaliät ebenfalls bereitstellen. Dafür wird die Methode setDimension() angeboten, welche den zur Dimension passenden Wert übergeben bekommt und den Aufruf schließlich an Analytics weiter delegiert.

export class AnalyticsService {
/* ... */
  public setDimension(value: string) {
        if (!this.active) {
          return;
        }
        ga('set', 'dimension1', value);
  }
}

Fazit und Ausblick

Das prinzipielle Vorgehen zur Einbindung einer JavaScript Library in ein Angular (2+) Projekt wurde aufgezeigt, um basierend darauf einen produktionsreifen Service zu entwickeln. Die Konfiguration des Dienstes erfolgt im Beispiel über die Properties aus der index.html-Datei, könnte jedoch auch über jede andere Quelle, wie beispielsweise ein spezielles Config-API, erfolgen.

Einige wünschenswerten Funktionen fehlen der Lösung noch, beispielsweise die deklarative Angabe von auszulösenden Ereignissen aus Templates heraus oder die Unterstützung mehrerer Analytics-Dienste. Hier bietet das Projekt Angulartics eine deutlich umfangreichere Lösung mit einem einheitlichen API für verschiedene Analytics-Anbieter an. Der Einsatz von bestehenden Lösungen sollte grundsätzlich evaluiert werden, bevor die Entscheidung zur Eigenentwicklung gefällt wird. Angulartics ist unter https://github.com/angulartics/angulartics2 bzw. via npm Open Source verfügbar.

Verwandte Themen:

Geschrieben von
Karsten Sitterberg
Karsten Sitterberg
Karsten Sitterberg ist als freiberuflicher Entwickler, Trainer und Berater für Java und Webtechnologien tätig. Karsten ist Physiker (MSc) und Oracle-zertifizierter Java Developer. Seit 2012 arbeitet er mit trion zusammen.
Kommentare

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.