Skip to content

Instantly share code, notes, and snippets.

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 = (
) => {
const url = '';
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 +,
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();"POST", url, true);
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(); = {
})(window, "XX-XXXXXXXXX-X", {
anonymizeIp: true,
colorDepth: true,
characterSet: true,
screenSize: true,
language: true
Copy link

jahilldev commented Jun 1, 2022

@wpsumo I haven't been able to find official documentation (it must exist, somewhere..) about doing this programmatically, only via GTM, which is obviously not ideal given the "minimal" goals of this.

After profiling the official GA4 library, I've discovered there's another default event type of click, which you can use in conjunction with event params, e.g ?ep.custom_param=lorem or if it's a number, ?epn.price=5.

If you're using @minimal-analytics/ga4, and you want a custom click event, you'll need to add an event handler to the element, something like this:

import { track } from '@minimal-analytics/ga4';

const button = document.querySelector('button'); // use relevant selector

button.addEventListener('click', () => track({ type: 'click', event: { 'epn.product_id': 12345 } }));

The above assumes you're using a node build tool or environment to generate your site. There currently isn't a way to access track(); without this. Open to feature requests though...

I am in the process of implementing automatic anchor and button click tracking in @minimal-analytics/ga4, which is another "out of the box" event provided by the official GA4 library. That will trigger a click event with a series of event params when a user clicks an anchor or button element.

Hope that helps!

Copy link

wpsumo commented Jun 28, 2022

@jahilldev Thanks for your answer, no not using any node environment. I run wordpress so php environment, I wish to be able to continue using inlined event similar to how I've used onclick today as I have a better structure there than track all click via class or ID.

As you say I did not find anything online or in the official documentation regarding this. Hopefully it will come before 2023 :D and then it can be added into minimal GA4 as well. For now if you know a solution or find, please share.

I'm not a fan of tracking all links external or internal. In this case I prefer to write them static in the html while they are dynamic via php. So it looks more like below in structure.

The only custom params I need to create if I prefer is "converted" but not necessary the rest is values which should be unlimited. The problem I see if trying to do it inline. But I have not spent hours into GA4 as I haven't seen this being supported in the official documentation yet... so no point to trying GA4 out for me right now, waiting for it though.

Converted/CTA (Category - Static)
Which CTA on the page (Action - dynamic php)
Where did the CTA go/slug (Label - dynamic php)

Copy link

jahilldev commented Jun 28, 2022

@wpsumo One solution to this would be to add track to the window in @minimal-analytics/ga4, that way you'd be able to call the function in the same way you've been doing with Universal Analytics.

I'm not super keen about blanket window pollution, but maybe I could add a config option that would do this.

What do you think?

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