Add Google Analytics 4 with cookie consent integration
All checks were successful
Build and Push Docker Image / build-and-push (push) Successful in 1m2s

- Add GA4 measurement ID to config (default: G-J0PCVT14NY)
- Add /api/config endpoint to expose GA ID to frontend
- Update cookie consent with Analytics category (opt-in)
- Load GA4 only after user consents to analytics cookies
- Update CSP to allow Google Analytics domains

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Tudor
2026-01-11 15:19:05 +00:00
parent 1f6b2dd773
commit 9cd36a0b15
3 changed files with 60 additions and 5 deletions

View File

@@ -354,6 +354,38 @@
</footer>
<script src="/static/app.js"></script>
<!-- Google Analytics (loaded conditionally after consent) -->
<script>
var GA_MEASUREMENT_ID = null;
// Fetch GA ID from server config
fetch('/api/config')
.then(function(response) { return response.json(); })
.then(function(config) {
if (config.ga_measurement_id) {
GA_MEASUREMENT_ID = config.ga_measurement_id;
}
})
.catch(function(err) { console.warn('Failed to load config:', err); });
function loadGoogleAnalytics() {
if (window.gaLoaded || !GA_MEASUREMENT_ID) return;
window.gaLoaded = true;
var script = document.createElement('script');
script.async = true;
script.src = 'https://www.googletagmanager.com/gtag/js?id=' + GA_MEASUREMENT_ID;
document.head.appendChild(script);
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
window.gtag = gtag;
gtag('js', new Date());
gtag('config', GA_MEASUREMENT_ID);
}
</script>
<!-- Cookie Consent Banner -->
<script src="https://cdn.jsdelivr.net/gh/silktide/consent-manager@main/silktide-consent-manager.js"></script>
<script>
@@ -365,14 +397,26 @@
description: 'Essential cookies required for the website to function properly.',
required: true,
defaultValue: true
},
{
id: 'analytics',
label: 'Analytics',
description: 'Help us understand how visitors use our site so we can improve it.',
required: false,
defaultValue: false
}
],
text: {
title: 'Cookie Preferences',
description: 'This website does not use tracking cookies. We only use essential cookies required for the site to function.',
acceptAll: 'Accept',
description: 'We use cookies to improve your experience. Analytics cookies help us understand how you use the site.',
acceptAll: 'Accept All',
rejectAll: 'Reject All',
save: 'Save Preferences'
},
onConsentChange: function(consent) {
if (consent.analytics) {
loadGoogleAnalytics();
}
}
});
</script>