Instantly share code, notes, and snippets.

Embed
What would you like to do?
Minimal Analytics Snippet
(function (context, trackingId, options) {
const history = context.history;
const doc = document;
const nav = navigator || {};
const storage = localStorage;
const encode = encodeURIComponent;
const pushState = history.pushState;
const typeException = 'exception';
const generateId = () => Math.random().toString(36);
const getId = () => {
if (!storage.cid) {
storage.cid = generateId()
}
return storage.cid;
};
const serialize = (obj) => {
var str = [];
for (var p in obj) {
if (obj.hasOwnProperty(p)) {
if(obj[p] !== undefined) {
str.push(encode(p) + "=" + encode(obj[p]));
}
}
}
return str.join("&");
};
const track = (
type,
eventCategory,
eventAction,
eventLabel,
eventValue,
exceptionDescription,
exceptionFatal
) => {
const url = 'https://www.google-analytics.com/collect';
const data = serialize({
v: '1',
ds: 'web',
aip: options.anonymizeIp ? 1 : undefined,
tid: trackingId,
cid: getId(),
t: type || 'pageview',
sd: options.colorDepth && screen.colorDepth ? `${screen.colorDepth}-bits` : undefined,
dr: doc.referrer || undefined,
dt: doc.title,
dl: doc.location.origin + doc.location.pathname + doc.location.search,
ul: options.language ? (nav.language || "").toLowerCase() : undefined,
de: options.characterSet ? doc.characterSet : undefined,
sr: options.screenSize ? `${(context.screen || {}).width}x${(context.screen || {}).height}` : undefined,
vp: options.screenSize && context.visualViewport ? `${(context.visualViewport || {}).width}x${(context.visualViewport || {}).height}` : undefined,
ec: eventCategory || undefined,
ea: eventAction || undefined,
el: eventLabel || undefined,
ev: eventValue || undefined,
exd: exceptionDescription || undefined,
exf: typeof exceptionFatal !== 'undefined' && !!exceptionFatal === false ? 0 : undefined,
});
if(nav.sendBeacon) {
nav.sendBeacon(url, data)
} else {
var xhr = new XMLHttpRequest();
xhr.open("POST", url, true);
xhr.send(data);
}
};
const trackEvent = (category, action, label, value) => track('event', category, action, label, value);
const trackException = (description, fatal) => track(typeException, null, null, null, null, description, fatal);
history.pushState = function (state) {
if (typeof history.onpushstate == "function") {
history.onpushstate({ state: state });
}
setTimeout(track, options.delay || 10);
return pushState.apply(history, arguments);
}
track();
context.ma = {
trackEvent,
trackException
}
})(window, "XX-XXXXXXXXX-X", {
anonymizeIp: true,
colorDepth: true,
characterSet: true,
screenSize: true,
language: true
});
@tudou-wp

This comment has been minimized.

Copy link

tudou-wp commented Dec 14, 2018

Before I saw this, I always host ga.js locally to improve performance. I'm thinking post action to GA with nginx in the back-end.
I have the same problem like you with GTM, thank you for making this!
Could this method be used to track speed, events and goals too?

@DavidKuennen

This comment has been minimized.

Copy link
Owner Author

DavidKuennen commented Dec 14, 2018

@tudou-wp currently not, but I got a lot of feature requests exposing a function to add events. It shouldn't add any significant size.

For all those who want to create their own version, here is the official documentation of this GA endpoint: https://developers.google.com/analytics/devguides/collection/protocol/v1/reference

I'm using https://babeljs.io/en/repl to minify and convert it to a snippet.

@brandonmcconnell

This comment has been minimized.

Copy link

brandonmcconnell commented Dec 16, 2018

Any way to add the Optimize snippet to this code?

@DavidKuennen

This comment has been minimized.

Copy link
Owner Author

DavidKuennen commented Dec 16, 2018

Improvements:

  • Using navigator.sendBeacon if available
  • Ability to track events
  • Ability to track exceptions
@neodigm

This comment has been minimized.

Copy link

neodigm commented Dec 17, 2018

Hi David, I find this useful. Thanks.

@nikrowell

This comment has been minimized.

Copy link

nikrowell commented Dec 18, 2018

Clever! Would be interested in seeing this on npm, obviously with the mga.init({...}) abstracted out.
Thanks for sharing!

@webmasterish

This comment has been minimized.

Copy link

webmasterish commented Dec 23, 2018

Great idea! Just used it to make a VuePress plugin.

@Lexicality

This comment has been minimized.

Copy link

Lexicality commented Dec 23, 2018

What's the onpushstate bit for?

@javiercasares

This comment has been minimized.

Copy link

javiercasares commented Dec 26, 2018

To compliance with the GDPR and similar, we have 2 options:

ga('create', 'UA-123456789-1');
ga('set', 'allowAdFeatures', false);
ga('set', 'anonymizeIp', true);
ga('send', 'pageview');

This supports "anonymizeIp"... is it possible to support "allowAdFeatures"?

@javiercasares

This comment has been minimized.

Copy link

javiercasares commented Dec 27, 2018

FYI, I've launched a WordPress plugin based on your code... https://wordpress.org/plugins/minimal-analytics/

@standoski

This comment has been minimized.

Copy link

standoski commented Jan 6, 2019

  1. Thanks for sharing this implementation!

  2. Please add somewhere on the https://minimalanalytics.com/ the time when was last updated the snippet code from there.

  3. Could you make a version that have implemented the "timing" features?
    https://developers.google.com/analytics/devguides/collection/protocol/v1/parameters#timing

Thanks!

@nwellnhof

This comment has been minimized.

Copy link

nwellnhof commented Jan 14, 2019

Support for custom parameters, for example to implement custom dimensions, would be great.

@waqasy

This comment has been minimized.

Copy link

waqasy commented Jan 21, 2019

How to send pageview hit?

ma('pageview', pageURL); ??

EDIT: I think only track(); will record pageview hit. I need to record pageview on quick view products.

@pau-ker

This comment has been minimized.

Copy link

pau-ker commented Jan 28, 2019

Will this work with the 'ga-disable-UA-XXXXXXX-X' OptOut Cookie?

@martpie

This comment has been minimized.

Copy link

martpie commented Feb 8, 2019

Awesome script!

I am running into a similar problem than @nwellnhof, I am using it as a Nuxt plugin (similarly as https://nuxtjs.org/faq/google-analytics#how-to-use-google-analytics-), but it seems that when changing routes, no even is recorded.

Typically, Nuxt tells us to add something like

  app.router.afterEach((to, from) => {
    /*
    ** We tell Google Analytics to add a `pageview`
    */
    ga('set', 'page', to.fullPath)
    ga('send', 'pageview')
  })

Also works for single page applications made with the likes of react and vue.js.

Did someone verify it?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment