- Here you can test if your umami installation works. Open the network tab in your browser's
+ Here you can test if your umami installation works. Open the network tab in your browser
developer console and watch for requests to the url collect . The links below should
trigger page views. Clicking on the button should trigger an event.
@@ -40,6 +46,10 @@ export default function Test() {
>
Button
+ Manual trigger
+
+ Button
+
>
);
diff --git a/rollup.snippet.config.js b/rollup.snippet.config.js
deleted file mode 100644
index c5925988..00000000
--- a/rollup.snippet.config.js
+++ /dev/null
@@ -1,19 +0,0 @@
-import 'dotenv/config';
-import buble from '@rollup/plugin-buble';
-import replace from '@rollup/plugin-replace';
-import resolve from '@rollup/plugin-node-resolve';
-import { terser } from 'rollup-plugin-terser';
-
-export default {
- input: 'tracker/snippet.js',
- output: {
- file: 'public/snippet.js',
- format: 'iife',
- },
- plugins: [
- replace({ __DNT__: !!process.env.ENABLE_DNT }),
- resolve(),
- buble(),
- terser({ compress: { evaluate: false } }),
- ],
-};
diff --git a/rollup.tracker.config.js b/rollup.tracker.config.js
index ea5f709f..e836955f 100644
--- a/rollup.tracker.config.js
+++ b/rollup.tracker.config.js
@@ -1,6 +1,5 @@
import 'dotenv/config';
import buble from '@rollup/plugin-buble';
-import replace from '@rollup/plugin-replace';
import resolve from '@rollup/plugin-node-resolve';
import { terser } from 'rollup-plugin-terser';
@@ -10,10 +9,5 @@ export default {
file: 'public/umami.js',
format: 'iife',
},
- plugins: [
- replace({ __DNT__: !!process.env.ENABLE_DNT }),
- resolve(),
- buble(),
- terser({ compress: { evaluate: false } }),
- ],
+ plugins: [resolve(), buble(), terser({ compress: { evaluate: false } })],
};
diff --git a/tracker/index.js b/tracker/index.js
index 28b8dfca..e3cb4fe4 100644
--- a/tracker/index.js
+++ b/tracker/index.js
@@ -13,44 +13,25 @@ import { removeTrailingSlash } from '../lib/url';
} = window;
const script = document.querySelector('script[data-website-id]');
+ const attr = key => script && script.getAttribute(key);
- // eslint-disable-next-line no-undef
- if (!script || (__DNT__ && doNotTrack())) return;
+ const website = attr('data-website-id');
+ const hostUrl = attr('data-host-url');
+ const autoTrack = attr('data-auto-track') !== 'false';
+ const dnt = attr('data-do-not-track') === 'true';
+
+ if (!script || (dnt && doNotTrack())) return;
- const website = script.getAttribute('data-website-id');
- const hostUrl = script.getAttribute('data-host-url');
- const skipAuto = script.getAttribute('data-skip-auto');
const root = hostUrl
? removeTrailingSlash(hostUrl)
: new URL(script.src).href.split('/').slice(0, -1).join('/');
const screen = `${width}x${height}`;
const listeners = [];
-
let currentUrl = `${pathname}${search}`;
let currentRef = document.referrer;
- /* Handle events */
+ /* Collect metrics */
- const removeEvents = () => {
- listeners.forEach(([element, type, listener]) => {
- element && element.removeEventListener(type, listener, true);
- });
- listeners.length = 0;
- };
-
- const loadEvents = () => {
- document.querySelectorAll('[class*=\'umami--\']').forEach(element => {
- element.className.split(' ').forEach(className => {
- if (/^umami--([a-z]+)--([a-z0-9_]+[a-z0-9-_]+)$/.test(className)) {
- const [, type, value] = className.split('--');
- const listener = () => collectEvent(type, value);
-
- listeners.push([element, type, listener]);
- element.addEventListener(type, listener, true);
- }
- });
- });
- };
const collect = (type, params, uuid) => {
const payload = {
website: uuid,
@@ -70,17 +51,56 @@ import { removeTrailingSlash } from '../lib/url';
payload,
});
};
- const pageView = (url = currentUrl, referrer = currentRef, uuid = website) => collect('pageview', {
- url,
- referrer,
- }, uuid);
- /* Collect metrics */
- const pageViewWithAutoEvents = (url, referrer) => pageView(url, referrer).then(() => setTimeout(loadEvents, 300));
+ const pageView = (url = currentUrl, referrer = currentRef, uuid = website) =>
+ collect(
+ 'pageview',
+ {
+ url,
+ referrer,
+ },
+ uuid,
+ );
+
+ const pageEvent = (event_value, event_type = 'custom', url = currentUrl, uuid = website) =>
+ collect(
+ 'event',
+ {
+ event_type,
+ event_value,
+ url,
+ },
+ uuid,
+ );
+
+ /* Handle events */
+
+ const loadEvents = () => {
+ document.querySelectorAll("[class*='umami--']").forEach(element => {
+ element.className.split(' ').forEach(className => {
+ if (/^umami--([a-z]+)--([a-z0-9_]+[a-z0-9-_]+)$/.test(className)) {
+ const [, type, value] = className.split('--');
+ const listener = () => pageEvent(value, type);
+
+ listeners.push([element, type, listener]);
+ element.addEventListener(type, listener, true);
+ }
+ });
+ });
+ };
+
+ const removeEvents = () => {
+ listeners.forEach(([element, type, listener]) => {
+ element && element.removeEventListener(type, listener, true);
+ });
+ listeners.length = 0;
+ };
+
+ /* Handle history changes */
- /* Handle history */
const handlePush = (state, title, url) => {
removeEvents();
+
currentRef = currentUrl;
const newUrl = url.toString();
@@ -91,38 +111,27 @@ import { removeTrailingSlash } from '../lib/url';
currentUrl = newUrl;
}
- pageViewWithAutoEvents(currentUrl, currentRef);
+ pageView(currentUrl, currentRef);
+
+ setTimeout(loadEvents, 300);
};
- const collectEvent = (event_type, event_value, url = currentUrl, uuid = website) => collect('event', {
- url,
- event_type,
- event_value,
- }, uuid);
+ /* Global */
- const registerAutoEvents = () => {
- history.pushState = hook(history, 'pushState', handlePush);
- history.replaceState = hook(history, 'replaceState', handlePush);
- return pageViewWithAutoEvents(currentUrl, currentRef);
- };
+ if (!window.umami) {
+ const umami = event_value => pageEvent(event_value);
+ umami.pageView = pageView;
+ umami.pageEvent = pageEvent;
-
- const umamiFunctions = { collect, pageView, collectEvent, registerAutoEvents };
- const scheduledCalls = window.umami.calls;
-
- window.umami = event_value => collect('event', { event_type: 'custom', event_value });
- Object.keys(umamiFunctions).forEach((key) => {
- window.umami[key] = umamiFunctions[key];
- });
-
- if (scheduledCalls) {
- scheduledCalls.forEach(([fnName, ...params]) => {
- window.umami[fnName].apply(window.umami, params);
- });
+ window.umami = umami;
}
/* Start */
- if (!skipAuto) {
- registerAutoEvents().catch(e => console.error(e));
+
+ if (autoTrack) {
+ history.pushState = hook(history, 'pushState', handlePush);
+ history.replaceState = hook(history, 'replaceState', handlePush);
+
+ pageView(currentUrl, currentRef);
}
})(window);
diff --git a/tracker/snippet.js b/tracker/snippet.js
deleted file mode 100644
index df1a8eb5..00000000
--- a/tracker/snippet.js
+++ /dev/null
@@ -1,43 +0,0 @@
-(window => {
- const umami = window.umami = window.umami || [];
- if (!umami.registerAutoEvents) {
- if (umami.invoked) {
- window.console && console.error && console.error('Umami snippet included twice.');
- } else {
- umami.invoked = true;
- umami.calls = [];
- umami.methods = ['registerAutoEvents', 'event', 'pageView'];
- umami.factory = t => {
- return function() {
- const e = Array.prototype.slice.call(arguments);
- e.unshift(t);
- umami.calls.push(e);
- return umami;
- };
- };
- for (let t = 0; t < umami.methods.length; t++) {
- let e = umami.methods[t];
- umami[e] = umami.factory(e);
- }
- umami.load = function(umamiScript, umamiUUID, skipAuto) {
- const scriptElement = document.createElement('script');
- scriptElement.type = 'text/javascript';
- scriptElement.defer = true;
- scriptElement.async = true;
- scriptElement.setAttribute('data-website-id', umamiUUID);
- if (skipAuto) {
- scriptElement.setAttribute('data-skip-auto', 'true');
- }
- scriptElement.src = umamiScript;
- const otherScript = document.getElementsByTagName('script')[0];
- otherScript.parentNode.insertBefore(scriptElement, otherScript);
- };
-
- umami.load('[HOST]/umami.js', '[UMAMI_UUID]', false);
- }
- }
-})(window);
-// This snippet is for more advanced use case of Umami. If you want to track custom events,
-// and not worry about having blocking script in the header,
-// use this snippet (compiled version available in /public/snippet.js).
-// Just remember to replace [HOST] and [UMAMI_UUID] when pasting it.
\ No newline at end of file