web-dev-qa-db-fra.com

Suivi des pages vues de Google Analytics dans Angular2

J'ai construit un nouveau site en utilisant Angular 2 comme front-end. Comme tout est effectué via l'état Push, il n'y a pas de chargement de page qui déclenche généralement le code de Google Analytics pour envoyer une page à ses serveurs.

Comment puis-je envoyer manuellement des événements d'affichage de page à Google afin de pouvoir suivre les activités des utilisateurs de mon site?

40
Ian Belcher

J'ai réussi à le faire fonctionner en m'abonnant aux modifications du routeur, en vérifiant que l'itinéraire avait réellement changé (je recevais parfois plusieurs événements sur certains itinéraires), puis en envoyant le nouveau chemin à Google. 

app.component.ts

import { ... } from '...';

// Declare ga function as ambient
declare var ga:Function;

@Component({ ... })

export class AppComponent {
    private currentRoute:string;

    constructor(_router:Router) {
        // Using Rx's built in `distinctUntilChanged ` feature to handle url change c/o @dloomb's answer
        router.events.distinctUntilChanged((previous: any, current: any) => {
            // Subscribe to any `NavigationEnd` events where the url has changed
            if(current instanceof NavigationEnd) {
                return previous.url === current.url;
            }
            return true;
        }).subscribe((x: any) => {
            ga('set', 'page', x.url);
            ga('send', 'pageview')
        });
      }
    }
}

Vous devez également inclure le code Google Analytics dans votre fichier d’index principal avant de charger votre application angular2 afin que l’objet global ga existe, mais vous ne souhaitez pas envoyer la vue initiale deux fois. Pour ce faire, supprimez la ligne suivante du script GA

index.html

<script>
  (function(i,s,o,g,r,a,m){...})(window,document,'script','https://www.google-analytics.com/analytics.js','ga');

  ga('create', 'UA-XXXXXXXX-X', 'auto');
  // Remove this line to avoid sending the first page view twice.
  //ga('send', 'pageview');

</script>
<!-- 
    Load your ng2 app after ga. 
    This style of deferred script loading doesn't guarantee this will happen
    but you can use Promise's or what works for your particular project. 
-->
<script defer type="text/javascript" src="/app.js"></script>

Utilisation d'une bibliothèque tierce

Comme alternative à la mise en œuvre de GA vous-même, la bibliothèque Angulartics2 est également un outil populaire pour la mise en oeuvre du suivi GA et s'intègre également à d'autres fournisseurs d'analyse.

50
Ian Belcher

Développer la réponse de Ian. Vous pouvez utiliser les fonctionnalités intégrées de Rx pour gérer la distinction entre les itinéraires actuels et les nouveaux.

import { NavigationEnd, Router } from '@angular/router';

declare var ga: any;

export class AppComponent {
        constructor(public router: Router) {
            router.events.distinctUntilChanged((previous: any, current: any) => {
                if(current instanceof NavigationEnd) {
                    return previous.url === current.url;
                }
                return true;
            }).subscribe((x: any) => {
                console.log('router.change', x);
                ga('send', 'pageview', x.url);
            });
        }
    }

Nous utilisons l'opérateur distinctUntilChanged pour que l'observateur n'émette que des éléments de type NavigationEnd et ne suivent pas le même itinéraire que l'élément précédemment émis.

33
dloomb

Si vous rencontrez ce problème après août 2017, vous devrez probablement utiliser gtag.js (balise de site globale de Google Universal Analytics) au lieu de l'ancien analytics.js . Je vous suggère de vérifier la différence entre les deux dans Migrez analytics.js vers gtag.js page, ainsi que Comment gtag.js fonctionne dans les applications Une page avant de continuer.

Lorsque vous récupérez votre extrait de code auprès de Google Analytics, il se présente comme suit:

<!-- Global site tag (gtag.js) - Google Analytics -->
<script async src="https://www.googletagmanager.com/gtag/js?id=<%= GOOGLE_ANALYTICS_ID %>"></script>
<script>
  window.dataLayer = window.dataLayer || [];
  function gtag(){dataLayer.Push(arguments);}
  gtag('js', new Date());

  gtag('config', '<%= GOOGLE_ANALYTICS_ID %>'); <!-- Remove that one -->
</script>

Vous devez supprimer la dernière ligne du script et ajouter le reste à votre index.html.

Vous devez ensuite ajouter la ligne que vous avez supprimée du script ci-dessus à votre code et ajouter la page à suivre. En gros, c'est presque le même que les types ci-dessus suggérés pour analytics.js, mais vous utilisez maintenant la fonction gtag.js.

Par exemple, si vous souhaitez suivre toutes les pages que vous ouvrez, voici l'exemple de code:

import { Component, OnInit } from '@angular/core';
import { Router, NavigationEnd } from '@angular/router';
import 'rxjs/add/operator/distinctUntilChanged';

// This still has to be declared
declare var gtag: Function;

@Component({
    moduleId: module.id,
    selector: 'my-app',
    templateUrl: 'app.component.html',
    styleUrls: ['app.component.css'],
})
export class AppComponent implements OnInit {

    constructor(private router: Router) { }

    ngOnInit() {
        this.router.events.distinctUntilChanged((previous: any, current: any) => {
            // Subscribe to any `NavigationEnd` events where the url has changed
            if(current instanceof NavigationEnd) {
                return previous.url === current.url;
            }
            return true;
        }).subscribe((x: any) => {
            gtag('config', '<%= GOOGLE_ANALYTICS_ID %>', {'page_path': x.url});
        });
    }
}

Si vous avez lu la documentation du gtag.js, vous savez qu'il pourrait y avoir une multitude d'options de suivi, mais je me concentre sur l'utilisation la plus élémentaire ici.

17
nyxz

Dans Angular 6, je suggère pour les app.component.ts:

import { Component, OnInit } from '@angular/core';
import { Router, NavigationEnd } from '@angular/router'
import { Title } from '@angular/platform-browser';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})

export class AppComponent {

  constructor(
    private router: Router,
    private titleService: Title
  ){ }

  ngOnInit() {
     this.router.events.subscribe(event => {
      if (event instanceof NavigationEnd) {
        (<any>window).gtag('config', '<%= GOOGLE_ANALYTICS_ID %>', {
          'page_title' : this.titleService.getTitle(),
          'page_path': event.urlAfterRedirects
        });
      }
    });
  }

}

Pour l'index.html:

  <!-- Global site tag (gtag.js) - Google Analytics -->
  <script async src="https://www.googletagmanager.com/gtag/js?id=<%= GOOGLE_ANALYTICS_ID %>"></script>
  <script>
    window.dataLayer = window.dataLayer || [];
    function gtag() { dataLayer.Push(arguments); }
    gtag('js', new Date());
  </script>

Vous pouvez gérer le titre de vos pages avec le service Title fourni par Angular: https://angular.io/guide/set-document-title

1
Cyril Blanchet

En supposant que chaque route angulaire a son propre titre dans app.routing.ts:

   {
    path: 'shop',
    component: ShopComponent,
    data: {
      title: ' == This is Shop Component Title =='
    },
    canActivate: [AuthGuard]
  },

Les solutions précédemment mentionnées affichent toujours le même titre de page pour chaque itinéraire sur Google Analytics Report. Pour utiliser les titres correspondants de Route angulaire (au lieu du contenu de la balise index.html <title>), utilisez le code ci-dessous dans app.component.ts

  this.router.events.subscribe(event => {

  if (event instanceof NavigationEnd) {
    (<any>window).ga('set', 'page', event.urlAfterRedirects);

    // ----------
    //use the following 3 lines of code to use
    //correnct titles for routes        
    // ----------

    let currentRoute = this.route.root;
    let title = this.getPageTitle(currentRoute);
    (<any>window).ga('set', 'title', title);

    (<any>window).ga('send', 'pageview');

  }
});

... où la méthode getPageTitle est la suivante:

getPageTitle = function (currentRoute: ActivatedRoute) {
  let data;
    do {
      const childrenRoutes = currentRoute.children;
      currentRoute = null;
      childrenRoutes.forEach(route => {

      if (route.outlet === 'primary') {
        currentRoute = route;
        data = route.snapshot.data;
      }
    });
  } while (currentRoute);
  return data.title;
};

Remarque: cette solution s’applique à Anguler 5 et inférieur. Dans Angular 6, vous pouvez également utiliser TitleService

0
Omer Gurarslan