rybbit/server/public/analytics.js
2025-01-24 20:49:01 -08:00

82 lines
2.2 KiB
JavaScript

// Frogstats Analytics Script
(function () {
// Get the script tag that loaded this script
const scriptTag = document.currentScript;
const ANALYTICS_HOST = scriptTag
.getAttribute("src")
.split("/analytics.js")[0];
// Get debounce duration from data attribute or default to 300ms
const debounceDuration = scriptTag.getAttribute("data-debounce")
? Math.max(0, parseInt(scriptTag.getAttribute("data-debounce")))
: 500;
// Debounce function
function debounce(func, wait) {
let timeout;
return (...args) => {
clearTimeout(timeout);
timeout = setTimeout(() => func.apply(this, args), wait);
};
}
// Track pageview (core functionality)
const trackPageview = () => {
const url = new URL(window.location.href);
const payload = {
hostname: url.hostname,
pathname: url.pathname,
querystring: url.search,
screenWidth: window.innerWidth,
screenHeight: window.innerHeight,
language: navigator.language,
page_title: document.title,
referrer: document.referrer,
};
fetch(`${ANALYTICS_HOST}/track/pageview`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(payload),
mode: "cors",
keepalive: true,
}).catch(console.error);
};
// Create debounced version with configured duration
const debouncedTrackPageview =
debounceDuration > 0
? debounce(trackPageview, debounceDuration)
: trackPageview;
// History API override
const originalPushState = history.pushState;
const originalReplaceState = history.replaceState;
history.pushState = function (...args) {
console.info("pushState");
originalPushState.apply(this, args);
debouncedTrackPageview();
};
history.replaceState = function (...args) {
console.info("replaceState");
originalReplaceState.apply(this, args);
debouncedTrackPageview();
};
// Handle navigation events
window.addEventListener("popstate", debouncedTrackPageview);
// Expose API
window.frogstats = {
trackPageview: debouncedTrackPageview,
// Add direct access to non-debounced version if needed
_trackImmediately: trackPageview,
};
// Initial pageview
trackPageview();
})();