Výzva

Chcete otestovať rôzne dizajny alebo texty bannerov o súbore cookie s cieľom zvýšiť mieru súhlasu a zároveň zachovať súlad s nariadením GDPR.

Scenár

„Chcem otestovať náš banner o súboroch cookie pomocou A/B testovania, aby som zistil, či rôzne formulácie ovplyvňujú mieru súhlasu. Obávam sa však o súlad s nariadením GDPR, ak budem sledovať používateľov skôr, ako vyjadria súhlas.“

Prístup k A/B testovaniu v súlade s predpismi

Kľúčový princíp: Banner s informáciami o súboroch cookie môžete testovať BEZ sledovacích nástrojov, pričom použijete len striktne nevyhnutné súbory cookie.

Implementácia

// Create variant assignment (strictly necessary cookie)
function assignVariant() {
    let variant = getCookie('banner_test_variant');

    if (!variant) {
        // Randomly assign variant
        variant = Math.random() < 0.5 ? 'A' : 'B';

        // Store in strictly necessary cookie (doesn't require consent)
        document.cookie = banner_test_variant=${variant}; path=/; max-age=2592000; SameSite=Strict;
    }

    return variant;
}

// Configuration for Variant A (Control)
const configA = {
    "notice_banner_type": "simple",
    "website_name": "My Website",
    // ... other config
};

// Configuration for Variant B (Test)
const configB = {
    "notice_banner_type": "headline",
    "website_name": "My Site", // Shorter name
    // ... other config
};

// Initialize based on variant
document.addEventListener('DOMContentLoaded', function () {
    const variant = assignVariant();
    const config = variant === 'A' ? configA : configB;

    // Add callback to track results (only after consent)
    config.callbacks = {
        "i_agree_button_clicked": () => {
            // User accepted - log this (now they've consented to tracking)
            logConsentEvent(variant, 'accepted');
        },
        "i_decline_button_clicked": () => {
            // User declined - still log the action
            logConsentEvent(variant, 'declined');
        }
    };

    cookieconsent.run(config);
});

function logConsentEvent(variant, action) {
    // Send to your analytics (user has now consented)
    if (typeof gtag !== 'undefined') {
        gtag('event', 'cookie_consent', {
            'variant': variant,
            'action': action
        });
    }

    // Or send to backend
    fetch('/api/log-consent', {
        method: 'POST',
        headers: {'Content-Type': 'application/json'},
        body: JSON.stringify({
            variant: variant,
            action: action,
            timestamp: new Date().toISOString()
        })
    });
}

function getCookie(name) {
    const value = ; ${document.cookie};
    const parts = value.split(; ${name}=);
    if (parts.length === 2) return parts.pop().split(';').shift();
}

Testovacie premenné

Typ banneru

// Variant A: Simple banner
"notice_banner_type": "simple"

// Variant B: Headline banner
"notice_banner_type": "headline"

Farebná schéma

// Variant A: Light
"palette": "light"

// Variant B: Dark
"palette": "dark"

Text tlačidla (prostredníctvom vlastného CSS)

// Add CSS to change button text
const style = document.createElement('style');
style.textContent = variant === 'A'
    ? '.cc-nb-okagree::before { content: "Accept All"; }'
    : '.cc-nb-okagree::before { content: "I Agree"; }';
document.head.appendChild(style);

Meranie zobrazení súhlasu

// Backend endpoint to analyze results
// GET /api/consent-analytics

{
    "variant_A": {
        "impressions": 1000,
        "accepted": 650,
        "declined": 250,
        "no_action": 100,
        "acceptance_rate": 0.65
    },
    "variant_B": {
        "impressions": 1000,
        "accepted": 720,
        "declined": 200,
        "no_action": 80,
        "acceptance_rate": 0.72
    }
}

Súhlas medzi doménami

Problém

„Naša hlavná stránka je www.example.com a náš obchod je shop.example.com. Používatelia dostávajú banner s informáciami o súboroch cookie na OBIDVOCH stránkach, aj keď už na prvej stránke súhlasili. Je to otravné a strácame konverzie.“

Porozumenie výzvam medzi doménami

V predvolenom nastavení sú súbory cookie obmedzené na konkrétnu doménu, kde sú nastavené:

  • Súbor cookie nastavený na www.example.com → Nie je prístupný na shop.example.com
  • Súbor cookie nastavený na shop.example.com → Nie je prístupný na www.example.com

Použite parameter cookie_domain na zdieľanie súhlasu medzi subdoménami:

cookieconsent.run({
    "consent_type": "express",
    "website_name": "My Website",
    "website_privacy_policy_url": "https://www.example.com/privacy",
    "cookie_domain": ".example.com", // Note the leading dot!
    "page_load_consent_levels": ["strictly-necessary"]
});

Dôležité! Úvodná bodka (.example.com) sprístupňuje súbor cookie na:

  • example.com
  • www.example.com
  • shop.example.com
  • blog.example.com
  • Akejkoľvek subdoméne example.com

Kompletný príklad medzi doménami

Na všetkých doménach/subdoménach použite identickú konfiguráciu:

<!-- On www.example.com -->
<script type="text/javascript" src="//www.termsfeed.com/public/cookie-consent/4.2.0/cookie-consent.js"></script>
<script type="text/javascript">
document.addEventListener('DOMContentLoaded', function () {
    cookieconsent.run({
        "notice_banner_type": "headline",
        "consent_type": "express",
        "palette": "light",
        "language": "en",
        "website_name": "Example",
        "website_privacy_policy_url": "https://www.example.com/privacy",
        "open_preferences_center_selector": "#changePreferences",
        "page_load_consent_levels": ["strictly-necessary"],
        "cookie_domain": ".example.com", // Shared across all subdomains
        "cookie_secure": true // Recommended for production
    });
});
</script>
<!-- On shop.example.com - SAME configuration -->
<script type="text/javascript" src="//www.termsfeed.com/public/cookie-consent/4.2.0/cookie-consent.js"></script>
<script type="text/javascript">
document.addEventListener('DOMContentLoaded', function () {
    cookieconsent.run({
        // EXACT SAME CONFIG as main domain
        "notice_banner_type": "headline",
        "consent_type": "express",
        "palette": "light",
        "language": "en",
        "website_name": "Example",
        "website_privacy_policy_url": "https://www.example.com/privacy",
        "open_preferences_center_selector": "#changePreferences",
        "page_load_consent_levels": ["strictly-necessary"],
        "cookie_domain": ".example.com", // Same domain!
        "cookie_secure": true
    });
});
</script>

Otestujte nastavenie medzi doménami

  1. Navštívte www.example.com
  2. Prijmite súbory cookie
  3. Otvorte DevTools → Aplikácia → Cookies
  4. Overte, či doména súboru cookie zobrazuje .example.com (s bodkou na začiatku)
  5. Prejdite na shop.example.com
  6. Overte, či sa banner NEZOBRAZUJE (súhlas už bol udelený)

Bežné problémy s medzi doménami

Problém 1: Banner sa stále zobrazuje na subdoménach

Problém

„Nastavil som cookie_domain na ‚.example.com‘, ale banner sa stále zobrazuje na každej subdoméne.“

Príčina

Prehliadač blokuje súbory cookie tretích strán.

Riešenie

Uistite sa, že pre stránky HTTPS je nastavenie cookie_secure na hodnotu true.

// Make sure cookie_secure is true for HTTPS sites
"cookie_secure": true,

// Also verify in DevTools that cookie is actually being set
// Check: Application → Cookies → Look for cookie_consent_level
// Domain should show: .example.com (not www.example.com)

Problém 2: Rozdielny súhlas na rôznych subdoménach

Problém:

Používateľ udelí súhlas na hlavnej doméne, ale preferencie sa líšia na subdoméne.

Príčina:

Konfigurácie nie sú identické vo všetkých doménach.

Riešenie:

Použite zdieľaný konfiguračný súbor alebo premennú.

// shared-config.js (include on all domains)
const SHARED_COOKIE_CONFIG = {
    "notice_banner_type": "headline",
    "consent_type": "express",
    "palette": "light",
    "language": "en",
    "website_name": "Example",
    "website_privacy_policy_url": "https://www.example.com/privacy",
    "open_preferences_center_selector": "#changePreferences",
    "page_load_consent_levels": ["strictly-necessary"],
    "cookie_domain": ".example.com",
    "cookie_secure": true
};

// Then on each domain:
cookieconsent.run(SHARED_COOKIE_CONFIG);

Viac domén (rôzne TLD)

Problém:

Máte example.com A example.co.uk, teda úplne odlišné domény.

Riešenie:

Súbory cookie NEMOŽNO zdieľať medzi rôznymi doménami najvyššej úrovne z dôvodu zabezpečenia prehliadača.

Máte dve možnosti:

Možnosť 1: Akceptovať viacero bannerov.

  • Používateľ vidí banner na každej doméne najvyššej úrovne
  • Udelený súhlas platí individuálne pre každú doménu, súhlas sa nezdieľa
  • Toto je pravdepodobne najviac vyhovujúci prístup

Možnosť 2: Použite synchronizáciu na pozadí (pre prihlásených používateľov)

// On example.com - user accepts
"callbacks": {
    "user_consent_saved": () => {
        if (isUserLoggedIn()) {
            // Sync to backend
            fetch('https://api.example.com/sync-consent', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                    'Authorization': 'Bearer ' + getUserToken()
                },
                body: JSON.stringify({
                    consent: getConsentState(),
                    domains: ['example.com', 'example.co.uk']
                })
            });
        }
    }
}

// On example.co.uk - check backend first
async function checkBackendConsent() {
    if (isUserLoggedIn()) {
        const response = await fetch('https://api.example.com/get-consent', {
            headers: {'Authorization': 'Bearer ' + getUserToken()}
        });
        const data = await response.json();
        if (data.hasConsent) {
            // Set cookie locally
            setCookieConsent(data.consentLevel);
        }
    }
}

Obnovenie stránky po udelení súhlasu

Problém

„Po tom, čo používateľ prijme súbory cookie, znovu načítajú stránku pomocou window.location.reload(), aby sa uistili, že sa načítajú skripty na sledovanie. To však spôsobuje, že Google Analytics stratí pôvodný zdroj odkazujúcej stránky a všetku návštevnosť zobrazuje ako „Priama“.“

K tomu dochádza, pretože pri opätovnom načítaní stránky:

  1. Prehliadač vymaže informácie o referrerovi
  2. Načítanie novej stránky vyzerá, ako keby pochádzalo z tej istej domény
  3. Google Analytics ju zaradí do kategórie „Priama“ návštevnosť
  4. Stratíte údaje o atribúcii

Riešenie 1: Neobnovujte stránku (odporúčané)

Použite spätné volania na dynamické načítanie skriptov namiesto opätovného načítania:

cookieconsent.run({
    "notice_banner_type": "headline",
    "consent_type": "express",
    "palette": "light",
    "language": "en",
    "website_name": "My Site",
    "website_privacy_policy_url": "https://mysite.com/privacy",
    "page_load_consent_levels": ["strictly-necessary"],

    "callbacks": {
        "scripts_specific_loaded": (level) => {
            // Scripts are NOW loaded - no reload needed!
            console.log("Scripts loaded for: " + level);

            if (level === 'tracking') {
                // Analytics is now active
                // Send initial page view if needed
                if (typeof gtag !== 'undefined') {
                    gtag('event', 'page_view', {
                        'page_location': window.location.href,
                        'page_referrer': document.referrer
                    });
                }
            }
        }
    },
    "callbacks_force": true
});

Riešenie 2: Zachovajte referrer pri opätovnom načítaní stránky

Ak MUSÍTE stránku načítať znovu, zachovajte referrer:

cookieconsent.run({
    // ... config ...
    "callbacks": {
        "i_agree_button_clicked": () => {
            // Store referrer and source before reload
            sessionStorage.setItem('original_referrer', document.referrer);
            sessionStorage.setItem('landing_page', window.location.href);

            // Get URL parameters (utm_source, etc.)
            const urlParams = new URLSearchParams(window.location.search);
            if (urlParams.has('utm_source')) {
                sessionStorage.setItem('utm_source', urlParams.get('utm_source'));
                sessionStorage.setItem('utm_medium', urlParams.get('utm_medium'));
                sessionStorage.setItem('utm_campaign', urlParams.get('utm_campaign'));
            }

            // Now reload
            window.location.reload();
        }
    }
});

// After reload, restore attribution
document.addEventListener('DOMContentLoaded', function() {
    const savedReferrer = sessionStorage.getItem('original_referrer');
    const utmSource = sessionStorage.getItem('utm_source');

    if (savedReferrer && typeof gtag !== 'undefined') {
        // Send page view with preserved referrer
        gtag('event', 'page_view', {
            'page_location': window.location.href,
            'page_referrer': savedReferrer
        });

        // Send campaign data if available
        if (utmSource) {
            gtag('event', 'campaign_details', {
                'campaign_source': utmSource,
                'campaign_medium': sessionStorage.getItem('utm_medium'),
                'campaign_name': sessionStorage.getItem('utm_campaign')
            });
        }

        // Clear storage
        sessionStorage.removeItem('original_referrer');
        sessionStorage.removeItem('utm_source');
        // ... clear others
    }
});

Riešenie 3: Použite režim súhlasu Google (osvedčená prax)

S režimom súhlasu V2 nie je potrebné stránku načítať znovu:

<!-- 1. Set default consent to denied -->
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('consent', 'default', {
    'ad_storage': 'denied',
    'ad_user_data': 'denied',
    'ad_personalization': 'denied',
    'analytics_storage': 'denied'
});
</script>

<!-- 2. Load Google Analytics (runs in consent mode) -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-XXXXXXXXXX"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'G-XXXXXXXXXX');
</script>

<!-- 3. Cookie Consent with callbacks -->
<script src="//www.termsfeed.com/public/cookie-consent/4.2.0/cookie-consent.js"></script>
<script>
document.addEventListener('DOMContentLoaded', function () {
    cookieconsent.run({
        "consent_type": "express",
        "website_name": "My Site",
        "page_load_consent_levels": ["strictly-necessary"],
        "callbacks": {
            "scripts_specific_loaded": (level) => {
                // Update consent mode - NO RELOAD!
                switch (level) {
                    case 'tracking':
                        gtag('consent', 'update', {
                            'analytics_storage': 'granted'
                        });
                        break;
                    case 'targeting':
                        gtag('consent', 'update', {
                            'ad_storage': 'granted',
                            'ad_user_data': 'granted',
                            'ad_personalization': 'granted'
                        });
                        break;
                }
            }
        },
        "callbacks_force": true
    });
});
  </script>


Vložený obsah a iFrames

Problém

„Na našej stránke máme vložené videá z YouTube. Mali by sme blokovať rámce iFrame, kým používatelia neprijmú súbory cookie? Ako to môžeme implementovať pomocou TermsFeed?“

Riešenie

Riešením je integrácia zástupného symbolu a použitie dynamického načítania.

Krok 1: Vytvorenie HTML zástupného symbolu

<!-- Instead of directly embedding iframe -->
<div class="video-placeholder" data-video-id="dQw4w9WgXcQ" data-consent-type="targeting">
    <div class="placeholder-content">
        <img src="/images/video-thumbnail.jpg" alt="Video thumbnail">
        <div class="placeholder-overlay">
            <button class="accept-and-load" onclick="loadVideo(this)">
                 Accept cookies to watch this video
            </button>
            <p>This video is hosted by YouTube and requires marketing cookies.</p>
            <a href="#" onclick="openCookiePreferences(); return false;">
                Change cookie preferences
            </a>
        </div>
    </div>
</div>

<style>
.video-placeholder {
    position: relative;
    width: 100%;
    padding-bottom: 56.25%; // 16:9 aspect ratio
    background: #000;
}

.placeholder-content {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
}

.placeholder-content img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.placeholder-overlay {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background: rgba(0,0,0,0.7);
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    color: white;
    text-align: center;
    padding: 20px;
}

.accept-and-load {
    background: #ff0000;
    color: white;
    border: none;
    padding: 15px 30px;
    font-size: 16px;
    border-radius: 5px;
    cursor: pointer;
    margin-bottom: 15px;
}
</style>

Krok 2: Načítanie iFrame po udelení súhlasu

// Check if user has already consented
function hasConsent(consentType) {
    const consentCookie = getCookie('cookie_consent_level');
    if (!consentCookie) return false;

    // Parse consent levels
    const levels = JSON.parse(decodeURIComponent(consentCookie));
    return levels.includes(consentType);
}

// Load video dynamically
function loadVideo(button) {
    const placeholder = button.closest('.video-placeholder');
    const videoId = placeholder.dataset.videoId;
    const consentType = placeholder.dataset.consentType;

    // Check if user has consent
    if (!hasConsent(consentType)) {
        // Request consent
        if (typeof cookieconsent !== 'undefined' && cookieconsent.openPreferencesCenter) {
            cookieconsent.openPreferencesCenter();
        } else {
            alert('Please accept marketing cookies to view this content');
        }
        return;
    }

    // Create iframe
    const iframe = document.createElement('iframe');
    iframe.src = https://www.youtube.com/embed/${videoId};
    iframe.width = '100%';
    iframe.height = '100%';
    iframe.frameBorder = '0';
    iframe.allow = 'accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture';
    iframe.allowFullscreen = true;

    // Replace placeholder with iframe
    placeholder.innerHTML = '';
    placeholder.appendChild(iframe);
}

// Auto-load videos if consent already given
document.addEventListener('DOMContentLoaded', function() {
    document.querySelectorAll('.video-placeholder').forEach(placeholder => {
        const consentType = placeholder.dataset.consentType;
        if (hasConsent(consentType)) {
            // Auto-load - user already consented
            const videoId = placeholder.dataset.videoId;
            const iframe = document.createElement('iframe');
            iframe.src = https://www.youtube.com/embed/${videoId};
            iframe.width = '100%';
            iframe.height = '100%';
            iframe.frameBorder = '0';
            iframe.allow = 'accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture';
            iframe.allowFullscreen = true;
            placeholder.innerHTML = '';
            placeholder.appendChild(iframe);
        }
    });
});

// Listen for consent updates
document.addEventListener('DOMContentLoaded', function() {
    cookieconsent.run({
        // ... config ...
        "callbacks": {
            "scripts_specific_loaded": (level) => {
                // When user accepts targeting cookies, load all pending videos
                if (level === 'targeting') {
                    document.querySelectorAll('.video-placeholder').forEach(placeholder => {
                        if (placeholder.dataset.consentType === 'targeting') {
                            loadVideo(placeholder.querySelector('.accept-and-load'));
                        }
                    });
                }
            }
        }
    });
});

function getCookie(name) {
    const value = ; ${document.cookie};
    const parts = value.split(; ${name}=);
    if (parts.length === 2) return parts.pop().split(';').shift();
}

function openCookiePreferences() {
    if (typeof cookieconsent !== 'undefined' && cookieconsent.openPreferencesCenter) {
        cookieconsent.openPreferencesCenter();
    }
}

Príklad pre ďalšie vloženia

Google Maps

<div class="map-placeholder" data-consent-type="functionality" data-location="New York, NY">
    <div class="placeholder-overlay">
        <p>️ Accept functional cookies to view map</p>
        <button onclick="loadMap(this)">Load Map</button>
    </div>
</div>

<script>
function loadMap(button) {
    const placeholder = button.closest('.map-placeholder');
    const location = placeholder.dataset.location;

    if (!hasConsent('functionality')) {
        cookieconsent.openPreferencesCenter();
        return;
    }

    const iframe = document.createElement('iframe');
    iframe.src = https://www.google.com/maps/embed/v1/place?key=YOUR_API_KEY&q=${encodeURIComponent(location)};
    iframe.width = '100%';
    iframe.height = '450';
    iframe.style.border = '0';
    iframe.allowFullscreen = true;
    iframe.loading = 'lazy';

    placeholder.innerHTML = '';
    placeholder.appendChild(iframe);
}
</script>

Vloženia zo sociálnych médií (X, Instagram, Facebook)

<div class="social-placeholder" data-consent-type="targeting" data-platform="twitter" data-url="https://twitter.com/user/status/123">
    <div class="placeholder-overlay">
        <p> Accept marketing cookies to view this tweet</p>
        <button onclick="loadSocialEmbed(this)">Load Tweet</button>
    </div>
</div>

<script>
function loadSocialEmbed(button) {
    const placeholder = button.closest('.social-placeholder');
    const platform = placeholder.dataset.platform;
    const url = placeholder.dataset.url;

    if (!hasConsent('targeting')) {
        cookieconsent.openPreferencesCenter();
        return;
    }

    // Load platform SDK
    if (platform === 'twitter' && !window.twttr) {
        const script = document.createElement('script');
        script.src = 'https://platform.twitter.com/widgets.js';
        script.onload = () => {
            twttr.widgets.createTweet(
                url.split('/').pop(),
                placeholder,
                { theme: 'light' }
            );
        };
        document.head.appendChild(script);
    }
    // Add other platforms as needed
}
</script>