gdpr/index.html
Ole-Morten Duesund 2d693605cf Add GDPR compliant optional tracking solution
- Complete demo with privacy-first hero section and live status indicator
- Production-ready integration examples for React, Vue, WordPress, and vanilla JS
- Comprehensive documentation covering API, customization, and legal compliance
- GDPR compliant by default with enhanced tracking only on explicit consent

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-08 12:59:47 +02:00

552 lines
No EOL
18 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>🍪 Privacy-First Demo | GDPR Compliant Tracking</title>
<style>
* {
box-sizing: border-box;
}
body {
margin: 0;
padding: 0;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
color: #333;
}
.hero {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
min-height: 100vh;
text-align: center;
padding: 2rem;
position: relative;
}
.hero::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(255, 255, 255, 0.95);
backdrop-filter: blur(10px);
}
.hero-content {
position: relative;
z-index: 1;
max-width: 800px;
}
.hero h1 {
font-size: 3.5rem;
font-weight: 700;
margin: 0 0 1rem 0;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
.hero .subtitle {
font-size: 1.4rem;
color: #666;
margin-bottom: 2rem;
font-weight: 300;
}
.privacy-badge {
display: inline-flex;
align-items: center;
gap: 8px;
background: #e8f5e8;
color: #2e7d2e;
padding: 8px 16px;
border-radius: 20px;
font-size: 14px;
font-weight: 600;
margin-bottom: 2rem;
box-shadow: 0 2px 8px rgba(46, 125, 46, 0.1);
}
.demo-info {
background: white;
padding: 2rem;
border-radius: 16px;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
margin-top: 2rem;
text-align: left;
}
.demo-info h2 {
color: #333;
margin-top: 0;
display: flex;
align-items: center;
gap: 8px;
}
.feature-list {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 1rem;
margin: 1.5rem 0;
}
.feature {
display: flex;
align-items: center;
gap: 12px;
padding: 1rem;
background: #f8f9fa;
border-radius: 8px;
border-left: 4px solid #667eea;
}
.feature-icon {
font-size: 1.5rem;
min-width: 24px;
}
.tracking-status {
position: fixed;
top: 20px;
left: 20px;
background: rgba(255, 255, 255, 0.9);
backdrop-filter: blur(10px);
padding: 12px 20px;
border-radius: 25px;
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1);
z-index: 999;
display: flex;
align-items: center;
gap: 8px;
font-weight: 600;
font-size: 14px;
}
.status-dot {
width: 8px;
height: 8px;
border-radius: 50%;
background: #4caf50;
}
.status-dot.minimal {
background: #ff9800;
}
@media (max-width: 768px) {
.hero h1 {
font-size: 2.5rem;
}
.hero .subtitle {
font-size: 1.2rem;
}
.demo-info {
padding: 1.5rem;
}
.tracking-status {
position: static;
margin-bottom: 2rem;
}
}
.tracking-consent-container {
position: fixed;
bottom: 20px;
right: 20px;
z-index: 1000;
}
.tracking-consent-btn {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
border: none;
padding: 12px 24px;
border-radius: 25px;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
font-size: 14px;
font-weight: 600;
cursor: pointer;
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2);
transition: all 0.3s ease;
display: flex;
align-items: center;
gap: 8px;
}
.tracking-consent-btn:hover {
transform: translateY(-2px);
box-shadow: 0 6px 20px rgba(0, 0, 0, 0.3);
}
.tracking-consent-btn:active {
transform: translateY(0);
}
.tracking-consent-btn.enabled {
background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
}
.tracking-consent-btn.enabled::after {
content: "✓";
margin-left: 4px;
}
.tracking-icon {
font-size: 16px;
}
.consent-modal {
display: none;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.5);
z-index: 1001;
justify-content: center;
align-items: center;
}
.consent-modal-content {
background: white;
padding: 30px;
border-radius: 12px;
max-width: 500px;
margin: 20px;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3);
}
.consent-modal h3 {
margin: 0 0 16px 0;
color: #333;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
}
.consent-modal p {
margin: 0 0 20px 0;
color: #666;
line-height: 1.5;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
}
.consent-modal-buttons {
display: flex;
gap: 12px;
justify-content: flex-end;
}
.consent-btn {
padding: 10px 20px;
border: none;
border-radius: 6px;
font-weight: 600;
cursor: pointer;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
}
.consent-btn.primary {
background: #667eea;
color: white;
}
.consent-btn.secondary {
background: #f5f5f5;
color: #333;
}
.consent-btn:hover {
opacity: 0.9;
}
</style>
</head>
<body>
<div class="tracking-status" id="trackingStatus">
<div class="status-dot minimal" id="statusDot"></div>
<span id="statusText">Privacy Mode: Minimal Tracking</span>
</div>
<div class="hero">
<div class="hero-content">
<div class="privacy-badge">
🔒 <span>GDPR Compliant by Default</span>
</div>
<h1>Privacy-First Demo</h1>
<p class="subtitle">
Experience truly optional tracking. Your privacy is protected by default,<br>
with enhanced features available only when <em>you</em> choose to enable them.
</p>
<div class="demo-info">
<h2>🎯 How It Works</h2>
<p>This demo shows how modern websites can respect your privacy while still providing great experiences:</p>
<div class="feature-list">
<div class="feature">
<span class="feature-icon">🔒</span>
<div>
<strong>Default: Privacy Protected</strong><br>
<small>Only essential cookies, anonymized analytics</small>
</div>
</div>
<div class="feature">
<span class="feature-icon">📊</span>
<div>
<strong>Optional: Enhanced Tracking</strong><br>
<small>Detailed analytics, personalization when you opt-in</small>
</div>
</div>
<div class="feature">
<span class="feature-icon">🎚️</span>
<div>
<strong>Full Control</strong><br>
<small>Toggle anytime with the button below</small>
</div>
</div>
<div class="feature">
<span class="feature-icon">🍪</span>
<div>
<strong>Smart Cookie Management</strong><br>
<small>Automatic cleanup when disabled</small>
</div>
</div>
</div>
<p><strong>Try it out!</strong> Click the colorful button in the bottom-right corner to see the consent flow in action. 👇</p>
</div>
</div>
</div>
<div class="tracking-consent-container">
<button id="trackingConsentBtn" class="tracking-consent-btn">
<span class="tracking-icon">📊</span>
<span id="btnText">Plz trac me!</span>
</button>
</div>
<div id="consentModal" class="consent-modal">
<div class="consent-modal-content">
<h3>Optional Enhanced Tracking</h3>
<p>
We respect your privacy! By default, we only use essential cookies and basic analytics.
If you'd like to help us improve our service with enhanced tracking (detailed analytics,
personalization, marketing cookies), you can opt in below.
</p>
<p>
<strong>What we'll track:</strong><br>
• Detailed page interactions<br>
• User preferences for personalization<br>
• Marketing campaign effectiveness<br>
• Enhanced usage analytics
</p>
<p>You can change your mind anytime by clicking the tracking button again.</p>
<div class="consent-modal-buttons">
<button class="consent-btn secondary" onclick="closeConsentModal()">No, thanks</button>
<button class="consent-btn primary" onclick="enableTracking()">Yes, track me!</button>
</div>
</div>
</div>
<script>
class GDPRTrackingConsent {
constructor() {
this.storageKey = 'gdpr-tracking-consent';
this.isTrackingEnabled = this.getConsentStatus();
this.init();
}
init() {
this.updateButtonState();
this.setupEventListeners();
if (this.isTrackingEnabled) {
this.enableEnhancedTracking();
} else {
this.enableMinimalTracking();
}
}
setupEventListeners() {
const btn = document.getElementById('trackingConsentBtn');
btn.addEventListener('click', () => {
if (this.isTrackingEnabled) {
this.showDisableConfirm();
} else {
this.showConsentModal();
}
});
const modal = document.getElementById('consentModal');
modal.addEventListener('click', (e) => {
if (e.target === modal) {
this.closeConsentModal();
}
});
}
getConsentStatus() {
const stored = localStorage.getItem(this.storageKey);
return stored === 'true';
}
setConsentStatus(status) {
localStorage.setItem(this.storageKey, status.toString());
this.isTrackingEnabled = status;
}
updateButtonState() {
const btn = document.getElementById('trackingConsentBtn');
const btnText = document.getElementById('btnText');
const statusText = document.getElementById('statusText');
const statusDot = document.getElementById('statusDot');
if (this.isTrackingEnabled) {
btn.classList.add('enabled');
btnText.textContent = 'Tracking ON';
statusText.textContent = 'Privacy Mode: Enhanced Tracking';
statusDot.className = 'status-dot';
} else {
btn.classList.remove('enabled');
btnText.textContent = 'Plz trac me!';
statusText.textContent = 'Privacy Mode: Minimal Tracking';
statusDot.className = 'status-dot minimal';
}
}
showConsentModal() {
document.getElementById('consentModal').style.display = 'flex';
}
closeConsentModal() {
document.getElementById('consentModal').style.display = 'none';
}
showDisableConfirm() {
if (confirm('Disable enhanced tracking? We\'ll switch back to minimal analytics only.')) {
this.disableTracking();
}
}
enableTracking() {
this.setConsentStatus(true);
this.updateButtonState();
this.closeConsentModal();
this.enableEnhancedTracking();
this.showNotification('Enhanced tracking enabled! Thanks for helping us improve.');
}
disableTracking() {
this.setConsentStatus(false);
this.updateButtonState();
this.enableMinimalTracking();
this.showNotification('Switched to minimal tracking. Your privacy is protected.');
}
enableMinimalTracking() {
console.log('🔒 GDPR Mode: Minimal tracking enabled');
if (typeof gtag !== 'undefined') {
gtag('consent', 'update', {
'analytics_storage': 'denied',
'ad_storage': 'denied',
'personalization_storage': 'denied',
'functionality_storage': 'granted'
});
}
this.cleanupEnhancedCookies();
this.fireCustomEvent('trackingModeChanged', { mode: 'minimal' });
}
enableEnhancedTracking() {
console.log('📊 Enhanced tracking enabled');
if (typeof gtag !== 'undefined') {
gtag('consent', 'update', {
'analytics_storage': 'granted',
'ad_storage': 'granted',
'personalization_storage': 'granted',
'functionality_storage': 'granted'
});
}
this.initEnhancedAnalytics();
this.fireCustomEvent('trackingModeChanged', { mode: 'enhanced' });
}
initEnhancedAnalytics() {
if (typeof gtag !== 'undefined') {
gtag('event', 'enhanced_tracking_enabled', {
'event_category': 'privacy',
'event_label': 'user_opted_in'
});
}
}
cleanupEnhancedCookies() {
const cookiesToRemove = ['_ga', '_gid', '_gat', '_fbp', '_fbc'];
cookiesToRemove.forEach(cookie => {
document.cookie = `${cookie}=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/`;
document.cookie = `${cookie}=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/; domain=.${window.location.hostname}`;
});
}
fireCustomEvent(eventName, data) {
const event = new CustomEvent(eventName, { detail: data });
document.dispatchEvent(event);
}
showNotification(message) {
const notification = document.createElement('div');
notification.style.cssText = `
position: fixed;
top: 20px;
right: 20px;
background: #4caf50;
color: white;
padding: 12px 20px;
border-radius: 6px;
z-index: 1002;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
box-shadow: 0 4px 12px rgba(0,0,0,0.2);
`;
notification.textContent = message;
document.body.appendChild(notification);
setTimeout(() => {
notification.remove();
}, 3000);
}
}
function closeConsentModal() {
window.trackingConsent.closeConsentModal();
}
function enableTracking() {
window.trackingConsent.enableTracking();
}
document.addEventListener('DOMContentLoaded', () => {
window.trackingConsent = new GDPRTrackingConsent();
});
document.addEventListener('trackingModeChanged', (e) => {
console.log('Tracking mode changed to:', e.detail.mode);
});
</script>
</body>
</html>