Zadanie niby proste ale nie do końca. Zacznijmy od początku, dodawanie skryptu Google Analytics do statycznej stony nie należy do najtrudniejszych, polega ono na skopiowaniu kodu ze strony Google Analytics i wklejeniu go na samym początku znacznika <head>. Jednak jeśli chcemy to zrobić w aplikacja z Angularem, robi się ciut trudniej.
Kod dostępny jest na naszej stronie Google Analytics po wejściu w zakładkę „Administracja -> Informacja o śledzeniu -> Kod śledzenia”
Przykład:
<!-- Global site tag (gtag.js) - Google Analytics -->
<script async src="https://www.googletagmanager.com/gtag/js?id=twoj-kod-Google-Analytics"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'twój-kod-Google-Analytics');
</script>
Stety niestetety w naszym przypadku sprawa trochę się komplikuję ponieważ strony w Angularze przełączane za pomocą serwisu Angular Router działają jak Single Page Application tzn. „podstawa” czyli między innymi znacznik <head> ładowany jest tylko raz przy pierwszym załadowaniu strony. Wtedy też za pomocą gtag('config', 'twój-kod-Google-Analytics');
wysyłamy informacje do Google Analytics. Podczas routingu zmienia się treść na stronie, „podstawa” nie przeładowuje się co skutkuje brakiem informacji o ruchach użytkownika w naszej aplikacji.
Jak to naprawiać? Musimy zaimplementować odpowiedni mechanizm który będzie wysyłał do Google Analytics informację o poczynaniach użytkownika. Wykorzystamy do tego metodę navigationEnd
z serwisu Angular Router oraz jej propertkę urlAfterRedirects
. Dzięki temu uzyskamy każdą zmianę adresu url. Aby wychwycić wszystkie ruchy użytkownika proponuję zaimplementować metodę w app.component.ts:
declare let gtag: Function; export class AppComponent { constructor(public router: Router){ this.router.events.subscribe(event => { if(event instanceof NavigationEnd){ gtag('config', 'twój-kod-Google-Analytics', {'page_path': event.urlAfterRedirects} ); } } )} }
[Aktualizacja 12.05.2021] Powyższy kod może powodować błąd „gtag is not defined”. Występuje on ponieważ dynamicznie generowany skrypt (opisany poniżej) może się załadować po komponencie AppComponent
. Jak to naprawiać? Najlepiej przenieść naszą metodę wysyłającą do nowego serwisu:
import {Injectable} from '@angular/core';
declare let gtag: Function;
@Injectable({
providedIn: 'root'
})
export class GoogleAnalyticsService {
pageChange(googleAnalyticsCode: string, pagePath: string): void {
gtag('config', googleAnalyticsCode, {'page_path': pagePath});
}
}
Dzięki temu zyskamy na przejrzystości kodu i wyeliminujemy wspomniany błąd. Przykład wywołania:
this.router.events.subscribe(event => {
if (event instanceof NavigationEnd && this.googleAnalyticsCode) {
this.googleAnalyticsService.pageChange(this.googleAnalyticsCode, event.urlAfterRedirects);
}
});
Dodatkowo do strony index.html należy dodać wcześniej już wspomniany skrypt ze stronny Google Analytics:
<!-- Global site tag (gtag.js) - Google Analytics -->
<script async src="https://www.googletagmanager.com/gtag/js?id=twoj-kod-Google-Analytics"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
</script>
Jednak już bez gtag('config', 'twój-kod-Google-Analytics')
ponieważ tą funkcję wysyłania mamy zaimplementowaną w app.components.ts
. Nie zapomnijmy o dopisaniu w src pierwszego znacznik script naszego kodu Google Analytics.
I gotowe. Poprawność konfiguracji możemy łatwo zweryfikować wchodząc na nasze konto na stronie Google Analytics lub sprawdzić czy requesty są wysyłane prawidłowo np. w inspektorze Mozilla Firefox w zakładce „Sieć”:

Implementacja z dynamicznym kodem Google Analytics
Scenariusz przedstawiony powyżej zakłada, że kod śledzenia Google Analytics jest zahardcodowany, a co w przypadku jeśli chcielibyśmy, żeby był on przypisywany ze zmiennej?
W tym celu przygotujemy specjalną metodą, która wygeneruje skrypt taki sam jak dołączony w znaczniku head:
loadGoogleAnalytics(trackingID: string): void {
const gtagScript = document.createElement('script');
gtagScript.setAttribute('async', 'true');
gtagScript.setAttribute('src', `https://www.googletagmanager.com/gtag/js?id=${ trackingID }`);
const gtagScript2 = document.createElement('script');
gtagScript2.innerText = `window.dataLayer = window.dataLayer || [];function gtag(){dataLayer.push(arguments);}gtag(\'js\', new Date());`;
document.documentElement.firstChild.appendChild(gtagScript);
document.documentElement.firstChild.appendChild(gtagScript2);
}
Przyjrzyjmy się dokładniej fragmentowi document.documentElement
– ta propertka daje nam dostęp do elementu nadrzędnego co przekłada się także na dostęp do elementu <head>
<html lang="pl">
<head>...</head>
<body>...</body>
</html>
Dzięki propertce firstChild
dostajemy się do elementu <head> a następnie poprzez metodę appendChild()
dodajemy nasze wcześniej przygotowany skrypty. Voilà!
Nie zapomnijmy jeszcze na zakończenie wywołać metody loadGoogleAnalytics() w odpowiednim momencie, np. zaraz na początku konstruktora app.components.ts
. Całość prezentuje się następująco:
See the Pen Angular Google Analytics by MichalZmu (@michalzmu) on CodePen.
To by było na tyle, jeśli mój mały poradnik wydał się Tobie interesujący lub masz inny pomysł jak rozwiązać opisany problem, daj znać w komentarzach!
Sprawdź inne moje wpisy: