Skip to content

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
});
@martpie
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?

@vnglst
Copy link

vnglst commented Mar 16, 2019

I've created an npm packages for this, mainly for personal use: https://www.npmjs.com/package/minimal-analytics

I'm also thinking about creating an even more minimal version of analytics, that does the bare minimum of tracking (i.e. only pageviews + ip) just like StatCounter in the old day.

@curtisbelt
Copy link

curtisbelt commented Mar 26, 2019

@martpie any luck with Nuxt.js integration? I'm in the same boat as you, just found this.

@JoseeWouters
Copy link

JoseeWouters commented May 12, 2019

Great script, thanks!

@curtisbelt @martpie I've got it working with Nuxt.js. I've put the code in a separate js file in my static folder and included it in the head property in my nuxt.config.js file. Analytics is showing the slugs of the pages I visited.

@jcuenod
Copy link

jcuenod commented Jun 2, 2019

I'm with @waqasy: Is it possible to do something like ma.trackPageview(pageURL)? It looks like some old pageview code was removed...

@kaknut
Copy link

kaknut commented Jun 20, 2019

Can anyone who uses this please tell me whether it only tracks pageviews or other basic stuffs like sessions and number of users?

@midudev
Copy link

midudev commented Aug 11, 2019

Hi @kaknut! Yes, pageviews are tracked correctly as well as session and number of users. Example of something that's not being tracked: RUM performance.

@bkarlson
Copy link

bkarlson commented Oct 9, 2019

Fantastic script! You can probably make it support hashed routes out of the box by adding + doc.hash @ L47

@bkarlson
Copy link

bkarlson commented Oct 17, 2019

any idea how to implement sampleRate in this script?

@bkarlson
Copy link

bkarlson commented Dec 6, 2019

btw, I just realized this fails in Safari incognito mode due to localStorage not available

(DOM Exception 22): The quota has been exceeded.

@janispritzkau
Copy link

janispritzkau commented Feb 24, 2020

I created one that's compatible with the cookie format of the Google analytics.js script. It's very minimal, just under 700 bytes when minified

https://gist.github.com/janispritzkau/c9fe29242af53fd1b10a847da78b3406

@brielov
Copy link

brielov commented Mar 24, 2020

What about using URLSearchParams instead of serialize?

@janispritzkau
Copy link

janispritzkau commented Mar 25, 2020

Yep. It would make sense if you're only targeting browsers that support ES6 and newer. I used it in my tiny analytics script

@wpsumo
Copy link

wpsumo commented May 28, 2020

How do I track event with inline js in minimal analytics?
Is it just Event: onClick="ma.trackEvent('Category', 'Action', 'Label', 'Value');" instead of onClick="ga('send', 'event', 'category', 'action', 'label', value);"

@winston0410
Copy link

winston0410 commented Jun 15, 2020

How do I make this script work with Turbolinks? It seems like it cannot capture pageview if I am using Turbolinks with it.

@idarek
Copy link

idarek commented Sep 7, 2020

Hello, can somebody advise:

  1. which code is up-to-date? the above minimal-analytics-snippet.js or https://minimalanalytics.com/ as there are differences hence not sure which one to use in the first place.
  2. If I understand correctly, this will only send information when the user will visit the site and will not work in the background to measure the time spent on the website (session duration)?

@WesCook
Copy link

WesCook commented Sep 7, 2020

@idarek, the code above is in its original form. The version on https://minimalanalytics.com/ is minified. Use the minified version in production to produce a smaller page.

@idarek
Copy link

idarek commented Sep 8, 2020

Anybody about the other part? Is it possible to add timings?

  1. If I understand correctly, this will only send information when the user will visit the site and will not work in the background to measure the time spent on the website (session duration)?

@brielov
Copy link

brielov commented Sep 8, 2020

@idarek The snippet is very well thought but you can use it as a template to build your own and even convert it to a function and call it whenever you want, I've used this as a base for my react projects and converted it as a hook.

@idarek
Copy link

idarek commented Oct 3, 2020

Installed on my website without any modification. Firstly though that will lose insight into average session duration (i know that is not accurate but always something) but I didn't which is great. Nice improvement recorded for the website as well. Great job!

@huseyinkogo
Copy link

huseyinkogo commented Dec 15, 2020

Thanks for this great Snippet!

Wondering when will GA4 be available ?

@luminarious
Copy link

luminarious commented Dec 15, 2020

@ihorvorotnov
Copy link

ihorvorotnov commented Dec 16, 2020

Depends when the newer API is finalized, currently in alpha.. 🤔

Is it?

https://developers.google.com/analytics/devguides/reporting/core/v4/migration#v4_1

@idarek
Copy link

idarek commented Jan 2, 2021

I see that the last David response was 2 years ago. Is that project dead?

@DavidKuennen
Copy link
Author

DavidKuennen commented Jan 6, 2021

Thanks for all the responses and sorry for not responding sooner. I don't have the capacity to improve this snipped further, but you can fork/use it as you like.

@einleid2506
Copy link

einleid2506 commented Jan 14, 2021

Hello. Please help me.
I used to track my bounce rate with the following code:
setTimeout(function(){ga('send', 'event', 'Bonuce-Rate', 'time_on_page_more_than_15_sec', location.pathname);}, 15000);
Now I am using your script as the site is much faster.
But I don’t understand programming and don’t know how to adjust the bounce rate to take into account visits where the time spent on the page is more than 15 seconds.
There is such a line in your code, but I don’t know whether it’s this or not?
setTimeout(track, options.delay || 10);

or before </script> i need to add something like this:
setTimeout("ma.trackEvent('Bonuce-Rate', 'time_on_page_more_than_15_sec')", 15000);

?

@idarek
Copy link

idarek commented Jan 19, 2021

Thanks for all the responses and sorry for not responding sooner. I don't have the capacity to improve this snipped further, but you can fork/use it as you like.

Thanks David,

ps. to people looking into v4. As I read, this is totally new Analytics and when moved into that, previous data is not transferred hence don't see the point to migrate from Universal to v4 unless you need to.

For current version, I would be interested in finding some workaround for blocking /collect by various scripts and adblockers.

Even Google web.dev website reporting as follow

/collect (www.google-analytics.com) | Failed to load resource: net::ERR_BLOCKED_BY_CLIENT.Inspector

@dmitrizzle
Copy link

dmitrizzle commented May 2, 2021

For those looking to send pageviews, here are the changes to the above code:

const track = (
    type,
    eventCategory,
    eventAction,
    eventLabel,
    eventValue,
    exceptionDescription,
    exceptionFatal,
    pageviewPathname // update function signature to accept pathname
  ) => {
      dl:
        doc.location.origin +
        (pageviewPathname ||
          doc.location.pathname + doc.location.search), // optionally add pathname when provided
  const trackEvent = (category, action, label, value) =>
    track("event", category, action, label, value);
  const trackException = (description, fatal) =>
    track(typeException, null, null, null, null, description, fatal);
  const trackPageview = pathname => // add paveview track function
    track("pageview", null, null, null, null, null, null, pathname);
context.ma = {
    trackEvent,
    trackException,
    trackPageview, // add trackPageview function to the utility object
  };

In use:

window.ma.trackPageview( "/my-page")

Note that the above changes do not cancel the initial pageview or window.history events. The function parameter accepts relative pathnames without the domain name.

@rmoscuba
Copy link

rmoscuba commented Sep 16, 2021

Hi. I am trying to get the clientId, but the cookie set by google is taking tooo long for appear. Is there a way to set this mannually? Isnt it just random numbers? Thanks.

@filz51
Copy link

filz51 commented Nov 11, 2021

How should I modify the snippet to record Page Load Time plt?

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