A/B testování bannerů pro souhlas s používáním souborů cookie
Výzva
Chcete otestovat různé návrhy bannerů pro souhlas s cookies nebo jejich texty, abyste zvýšili míru souhlasu a zároveň zachovali soulad s GDPR.
Scénář
„Chci provést A/B testování našeho banneru s informacemi o souborech cookie, abych zjistil, zda různé formulace ovlivňují míru přijetí. Mám však obavy ohledně souladu s GDPR, pokud budu sledovat uživatele předtím, než udělí souhlas.“
Přístup k A/B testování v souladu s předpisy
Klíčový princip: Cookie bannery můžete testovat BEZ sledovacích nástrojů, pouze s použitím nezbytně nutných cookies.
Implementace
// 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();
}
Testovací proměnné
Typ banneru
// Variant A: Simple banner
"notice_banner_type": "simple"
// Variant B: Headline banner
"notice_banner_type": "headline"
Barevné schéma
// Variant A: Light
"palette": "light"
// Variant B: Dark
"palette": "dark"
Text tlačítka (prostřednictvím 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);
Měření zobrazení souhlasu
// 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
}
}
Souhlas napříč doménami
Problém
„Naše hlavní stránka je www.example.com a náš obchod je shop.example.com. Uživatelům se zobrazuje banner s informacemi o souborech cookie na OBOU stránkách, i když již na první z nich souhlasili. Je to nepříjemné a přicházíme tak o konverze.“
Porozumění problémům s více doménami
Ve výchozím nastavení se soubory cookie vztahují pouze na konkrétní doménu, kde jsou nastaveny:
- Cookie nastavený na
www.example.com→ Není přístupný nashop.example.com - Cookie nastavený na
shop.example.com→ Není přístupný nawww.example.com
Řešení: parametr cookie_domain
Použijte parametr cookie_domain pro sdílení souhlasu napříč 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í tečka (.example.com) zpřístupňuje soubor cookie pro:
example.comwww.example.comshop.example.comblog.example.com- Jakékoli subdoméně
example.com
Kompletní příklad napříč doménami
Na všech doménách/subdoménách použijte identickou konfiguraci:
<!-- 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 nastavení mezi doménami
- Navštivte
www.example.com - Přijměte soubory cookie
- Otevřete DevTools → Aplikace → Soubory cookie
- Ověřte, zda doména souboru cookie zobrazuje
.example.com(s tečkou na začátku) - Přejděte na
shop.example.com - Ověřte, že se banner NEZOBRAZUJE (souhlas již byl udělen)
Časté problémy s mezidoménovým přístupem
Problém 1: Banner se stále zobrazuje na subdoménách
Problém
„Nastavil jsem cookie_domain na ‚.example.com‘, ale banner se stále zobrazuje na všech subdoménách.“
Příčina
Prohlížeč blokuje soubory cookie třetích stran.
Řešení
Ujistěte se, že cookie_secure je nastaveno na hodnotu true pro weby HTTPS.
// 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: Rozdílný souhlas na různých subdoménách
Problém:
Uživatel udělí souhlas na hlavní doméně, ale preference se liší na subdoméně.
Příčina:
Konfigurace nejsou napříč doménami identické.
Řešení:
Použijte sdílený konfigurační soubor nebo proměnnou.
// 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);
Více domén (různé TLD)
Problém
Máte example.com A example.co.uk, tedy zcela odlišné domény.
Řešení
Soubory cookie NELZE sdílet mezi různými doménami nejvyšší úrovně z důvodu zabezpečení prohlížeče.
Máte dvě možnosti:
Možnost 1: Přijmout více bannerů.
- Uživatel vidí banner na každé doméně nejvyšší úrovně
- Udělený souhlas platí individuálně pro každou doménu, souhlas není sdílen
- Toto je pravděpodobně nejvíce vyhovující přístup
Možnost 2: Použijte synchronizaci na pozadí (pro přihlášené uživatele)
// 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);
}
}
}
Obnovení stránky po udělení souhlasu
Problém
„Poté, co uživatel přijme soubory cookie, znovu načtu stránku pomocí window.location.reload(), abych se ujistil, že se načtou skripty pro sledování. To však způsobuje, že Google Analytics ztratí původní zdroj odkazu a zobrazí veškerý provoz jako ‚Přímý‘.“
K tomu dochází, protože při obnovení stránky:
- Prohlížeč vymaže informace o zdroji odkazu
- Nové načtení stránky vypadá, jako by pocházelo ze stejné domény
- Google Analytics ji zařadí do kategorie „Přímý“ provoz
- Ztratíte data o přiřazení
Řešení 1: Neobnovujte stránku (doporučeno)
Místo načítání stránky znovu použijte zpětná volání k dynamickému načtení skriptů:
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
});
Řešení 2: Zachovejte referrer při načtení stránky
Pokud MUSÍTE stránku znovu načíst, zachovejte 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
}
});
Řešení 3: Použijte režim souhlasu Google (osvědčený postup)
S režimem souhlasu V2 není načtení stránky nutné:
<!-- 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šem webu máme vložená videa z YouTube. Měli bychom blokovat rámce iFrame, dokud uživatelé nepřijmou soubory cookie? Jak to implementujeme pomocí TermsFeed?“
Řešení
Řešením je integrace zástupného symbolu a použití dynamického načítání.
Krok 1: Vytvořte HTML zástupný symbol
<!-- 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čtení iFrame po udělení souhlasu
// 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();
}
}
Příklad pro další vložení
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žení sociálních 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>