Angular 2をフロントエンドとして使用して新しいサイトを構築しました。すべてがプッシュ状態を介して行われるため、通常はページビューを送信するGoogleアナリティクスコードをトリガーするページ読み込みはありません。 Googleのサーバー。
自分のサイトのどのユーザーが閲覧しているかを追跡できるように、ページビューイベントをGoogleに手動で送信するにはどうすればよいですか?
ルーターの変更をサブスクライブし、ルートが実際に変更されたことを確認して(一部のルートで複数のイベントを取得していた)、新しいパスを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')
});
}
}
}
さらに、angular2アプリをロードする前に、メインのインデックスファイルにGoogleアナリティクスコードを含めて、グローバルga
オブジェクトが存在するようにする必要がありますが、初期ビューを2回送信する必要はありません。これを行うには、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>
サードパーティのライブラリを使用する
GA自分で実装する代わりに、ライブラリ Angulartics2 は、GA追跡を実装するための一般的なツールであり、他の分析ベンダーも同様です。
Ianの答えを拡大します。 Rxの組み込み機能を使用して、現在のルートと新しいルートの区別を処理できます。
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);
});
}
}
DistinctUntilChanged演算子を使用して、オブザーバーがNavigationEnd型のアイテムのみを発行し、以前に発行されたアイテムと同じルートを持たないようにします。
2017年8月以降にこの問題に直面している場合、おそらく gtag.js (Google Universal Analytics Global Siteタグ) analytics.js の代わりに。 analytics.jsからgtag.jsへの移行 ページと シングルページアプリケーションでのgtag.jsの動作 の両方の違いを確認することをお勧めします。
Google Analyticsからコードスニペットを取得すると、次のようになります。
<!-- 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>
スクリプトの最後の行を削除して、残りをindex.html
に追加する必要があります。
次に、上記のスクリプトから削除した行をコードに追加し、トラックにページを追加する必要があります。基本的に、上記のanalytics.js
に対して提案されたものとほぼ同じですが、今はgtag.js
関数を使用しています。
たとえば、ここで開くすべてのページを追跡する場合のサンプルコードは次のとおりです。
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});
});
}
}
gtag.js
のドキュメントを読んだ場合は、追跡オプションが多数ある可能性があることを知っていますが、ここでは最も基本的な使用法に焦点を当てています。
Angular 6で、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
});
}
});
}
}
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>
Angular: https://angular.io/guide/set-document-title によって提供されるタイトルサービスを使用して、ページのタイトルを管理できます。
すべてのAngular Routeはapp.routing.ts
:
{
path: 'shop',
component: ShopComponent,
data: {
title: ' == This is Shop Component Title =='
},
canActivate: [AuthGuard]
},
前述のソリューションでは、Googleアナリティクスレポートの各ルートに同じページタイトルが引き続き表示されます。対応するAngularルートタイトル(index.htmlの代わりに<title>
タグコンテンツを常に)、以下のコードを使用して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');
}
});
...ここでgetPageTitle
メソッドは次のとおりです。
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;
};
注:このソリューションは、Anguler 5以下に適用されます。 Angular 6では、 TitleService を使用することもできます
this.router.events.subscribe(event => {
if (event instanceof NavigationEnd) {
ga('set','page', event.urlAfterRedirects);
ga('send', 'pageview');
}
});