JavaScript
GoogleAnalytics
GoogleTagManager

Tracking SPA application with Google Analytics / Google Tag Manager

*It may affect outer javascript and framework(like vue, angular, react etc...). I strongly recommend you use it in unavoidable case.


ga version (Google Analytics)

(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', 'https://www.google-analytics.com/analytics.js', 'ga');

ga ('create', 'UA-XXXXX', 'auto'); // replace XXXXX into your id
ga ('send', 'pageview');

function insertCallback(parent, funcname, callback, ...args) {
let oldFunc = parent[funcname] ? parent[funcname] : function (){}
parent[funcname] = function() {
oldFunc.apply(this, arguments)
return callback(...args)
}
}

function notify_analytics(l) {
let newPage = l.pathname + l.hash
ga('set', 'page', newPage)
ga('send', 'pageview')
}

insertCallback(window.history, "pushState", notify_analytics, location)
insertCallback(window.history, "replaceState", notify_analytics, location)


gtag version (Google Tag Manager)

<!-- replace XXXXX into your id -->

<script async src="https://www.googletagmanager.com/gtag/js?id=UA-XXXXX"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag() { dataLayer.push(arguments); }
gtag('js', new Date());
gtag('config', 'UA-XXXXX'); // replace XXXXX into your id

function insertCallback(parent, funcname, callback, ...args) {
let oldFunc = parent[funcname] ? parent[funcname] : function () { }
parent[funcname] = function () {
oldFunc.apply(this, arguments)
return callback(...args)
}
}

function notify_analytics(l) {
let newPage = l.pathname + l.hash
// replace XXXXX into your id
gtag('config', 'UA-XXXXX', { 'page_path': newPage });
}

insertCallback(window.history, "pushState", notify_analytics, location)
insertCallback(window.history, "replaceState", notify_analytics, location)
</script>

Explanation

Reference