Skip to main content

Migrate from Other CMPs

Migration Overview​

Migrating from an existing Consent Management Platform (CMP) to biskoui requires careful planning to ensure seamless user experience, compliance continuity, and minimal disruption to your website's functionality.

šŸŽÆ Why Migrate to biskoui?​

biskoui Advantages:
āœ… Swiss data residency and nFADP compliance
āœ… Simplified integration with automatic blocking
āœ… Enhanced performance and Core Web Vitals
āœ… Comprehensive developer tools and APIs
āœ… Google Consent Mode v2 built-in support
āœ… Transparent pricing and honest business model
āœ… Superior user experience and conversion rates

āš ļø Migration Challenges​

Common Migration Issues:
āŒ Consent data continuity gaps
āŒ Service mapping inconsistencies
āŒ Dual CMP conflicts during transition
āŒ Script execution race conditions
āŒ User experience disruption
āŒ Compliance audit trail breaks
āŒ Performance impact during transition

Pre-Migration Assessment​

šŸ“‹ Current State Analysis​

Before starting migration, conduct a comprehensive assessment:

Assessment Checklist:
āœ… Document current CMP configuration
āœ… Inventory all tracked services and categories
āœ… Export existing consent logs (if possible)
āœ… Map consent categories between systems
āœ… Identify custom scripts and integrations
āœ… Review compliance documentation needs
āœ… Plan user communication strategy

Current CMP Audit Script:​

// Run this script to audit your current CMP setup
function auditCurrentCMP() {
console.log('šŸ” Current CMP Audit Report');
console.log('==========================');

// Detect current CMP
const cmpDetection = {
'OneTrust': () => typeof window.OneTrust !== 'undefined' || typeof window.Optanon !== 'undefined',
'Cookiebot': () => typeof window.Cookiebot !== 'undefined',
'TrustArc': () => typeof window.truste !== 'undefined',
'Quantcast': () => typeof window.__qc !== 'undefined',
'CookieYes': () => typeof window.ckySettings !== 'undefined',
'Termly': () => typeof window.termly !== 'undefined',
'ConsentManager': () => typeof window.__cmp !== 'undefined',
'Google Funding Choices': () => typeof window.__gfc !== 'undefined'
};

let detectedCMP = 'Unknown';
Object.entries(cmpDetection).forEach(([name, detector]) => {
if (detector()) {
detectedCMP = name;
}
});

console.log('šŸ“ Detected CMP:', detectedCMP);

// Check for consent cookies
const consentCookies = document.cookie.split(';')
.filter(cookie =>
cookie.toLowerCase().includes('consent') ||
cookie.toLowerCase().includes('cookie') ||
cookie.toLowerCase().includes('privacy')
)
.map(cookie => cookie.trim());

console.log('šŸŖ Consent-related cookies:', consentCookies.length);
consentCookies.forEach(cookie => console.log(' ', cookie.split('=')[0]));

// Check for CMP scripts
const cmpScripts = Array.from(document.scripts)
.filter(script => {
const src = script.src.toLowerCase();
return src.includes('consent') ||
src.includes('cookie') ||
src.includes('privacy') ||
src.includes('onetrust') ||
src.includes('cookiebot') ||
src.includes('trustarc');
});

console.log('šŸ“œ CMP-related scripts:', cmpScripts.length);
cmpScripts.forEach(script => console.log(' ', script.src));

// Check current consent state
let currentConsent = 'Unable to determine';
try {
// OneTrust
if (window.OneTrust && window.OneTrust.getGeolocationData) {
currentConsent = 'OneTrust detected - check OneTrust.getGeolocationData()';
}
// Cookiebot
else if (window.Cookiebot && window.Cookiebot.consent) {
currentConsent = JSON.stringify(window.Cookiebot.consent);
}
// Generic CMP API
else if (window.__tcfapi) {
window.__tcfapi('getTCData', 2, (tcData) => {
currentConsent = 'TCF v2 - ' + tcData.purpose.consents;
});
}
} catch (error) {
currentConsent = 'Error reading consent: ' + error.message;
}

console.log('šŸŽÆ Current consent state:', currentConsent);

return {
detectedCMP,
consentCookies: consentCookies.length,
cmpScripts: cmpScripts.length,
currentConsent
};
}

// Run the audit
auditCurrentCMP();

Platform-Specific Migration Guides​

šŸ”— OneTrust to biskoui Migration​

Step 1: Export OneTrust Configuration​

// Export OneTrust settings (run in browser console)
function exportOneTrustConfig() {
if (typeof window.OneTrust === 'undefined') {
console.error('OneTrust not detected');
return;
}

const config = {
// Basic configuration
geolocation: window.OneTrust.getGeolocationData(),
domainData: window.OneTrust.GetDomainData(),

// Consent groups (categories)
groups: [],

// Current consent state
currentConsent: {}
};

// Extract consent groups
try {
const groups = window.OneTrust.GetDomainData().Groups;
config.groups = groups.map(group => ({
id: group.CustomGroupId,
name: group.GroupName,
description: group.GroupDescription,
isEssential: group.Status === 'always active'
}));
} catch (error) {
console.error('Error extracting groups:', error);
}

// Get current consent
try {
const activeGroups = window.OneTrust.getGeolocationData().country !== 'US' ?
window.OnetrustActiveGroups.split(',') : [];
config.currentConsent = activeGroups;
} catch (error) {
console.error('Error getting current consent:', error);
}

console.log('OneTrust Configuration Export:', config);
return config;
}

Step 2: Map OneTrust Categories to biskoui​

OneTrust → biskoui Category Mapping:
ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¬ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”
│ OneTrust Category │ biskoui Category │
ā”œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¼ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¤
│ Strictly Necessary │ functional │
│ Performance Cookies │ analytics │
│ Functional Cookies │ functional │
│ Targeting Cookies │ marketing │
│ Social Media Cookies │ social │
│ Analytics │ analytics │
│ Advertising │ marketing │
ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”“ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜

Step 3: OneTrust Migration Implementation​

<!-- Phase 1: Parallel implementation -->
<script>
// Disable OneTrust auto-show
window.OptanonWrapper = function() {
// Don't show OneTrust banner
console.log('OneTrust loaded but banner suppressed');
};
</script>

<!-- Keep OneTrust for consent reading -->
<script src="https://cdn.cookielaw.org/consent/YOUR_DOMAIN_ID/OtAutoBlock.js"></script>

<!-- Add biskoui -->
<script src="https://cdn.biskoui.com/v2/script.js"
data-site-id="site_1234567890abcdef"
data-auto-show="false">
</script>

<script>
// Migration bridge script
class OneTrustToBiskouiMigration {
constructor() {
this.migrationComplete = false;
this.setupMigration();
}

setupMigration() {
// Wait for both systems to load
Promise.all([
this.waitForOneTrust(),
this.waitForBiskoui()
]).then(() => {
this.performMigration();
});
}

waitForOneTrust() {
return new Promise(resolve => {
if (window.OneTrust) {
resolve();
} else {
const interval = setInterval(() => {
if (window.OneTrust) {
clearInterval(interval);
resolve();
}
}, 100);
}
});
}

waitForBiskoui() {
return new Promise(resolve => {
if (window.biskoui && window.biskoui.isReady()) {
resolve();
} else {
window.biskoui?.on('ready', resolve);
}
});
}

performMigration() {
// Read OneTrust consent
const oneTrustConsent = this.readOneTrustConsent();

// Map to biskoui categories
const biskouiConsent = this.mapConsentCategories(oneTrustConsent);

// Set biskoui consent without showing banner
if (biskouiConsent.length > 0) {
window.biskoui.updateConsent(biskouiConsent);
console.log('āœ… Migrated consent from OneTrust to biskoui:', biskouiConsent);
} else {
// No existing consent, show biskoui banner
window.biskoui.showBanner();
}

this.migrationComplete = true;
this.disableOneTrust();
}

readOneTrustConsent() {
try {
const activeGroups = window.OnetrustActiveGroups?.split(',') || [];
return activeGroups.filter(group => group.length > 0);
} catch (error) {
console.error('Error reading OneTrust consent:', error);
return [];
}
}

mapConsentCategories(oneTrustGroups) {
const categoryMap = {
'C0001': 'functional', // Strictly Necessary
'C0002': 'analytics', // Performance
'C0003': 'functional', // Functional
'C0004': 'marketing', // Targeting
'C0005': 'social' // Social Media
};

const biskouiCategories = new Set(['functional']); // Always include functional

oneTrustGroups.forEach(group => {
const category = categoryMap[group];
if (category) {
biskouiCategories.add(category);
}
});

return Array.from(biskouiCategories);
}

disableOneTrust() {
// Hide OneTrust banner if visible
const otBanner = document.getElementById('onetrust-banner-sdk');
if (otBanner) {
otBanner.style.display = 'none';
}

// Disable OneTrust script loading
window.OptanonWrapper = function() {
console.log('OneTrust disabled after migration');
};
}
}

// Initialize migration
const migration = new OneTrustToBiskouiMigration();
</script>

šŸ¤– Cookiebot to biskoui Migration​

Cookiebot Category Mapping:​

Cookiebot → biskoui Category Mapping:
ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¬ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”
│ Cookiebot Category │ biskoui Category │
ā”œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¼ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¤
│ necessary │ functional │
│ preferences │ functional │
│ statistics │ analytics │
│ marketing │ marketing │
ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”“ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜

Cookiebot Migration Script:​

// Cookiebot to biskoui migration
class CookiebotToBiskouiMigration {
constructor() {
this.setupMigration();
}

setupMigration() {
// Wait for both systems
Promise.all([
this.waitForCookiebot(),
this.waitForBiskoui()
]).then(() => {
this.performMigration();
});
}

waitForCookiebot() {
return new Promise(resolve => {
if (window.Cookiebot) {
resolve();
} else {
const interval = setInterval(() => {
if (window.Cookiebot) {
clearInterval(interval);
resolve();
}
}, 100);
}
});
}

waitForBiskoui() {
return new Promise(resolve => {
if (window.biskoui?.isReady()) {
resolve();
} else {
window.biskoui?.on('ready', resolve);
}
});
}

performMigration() {
const cookiebotConsent = this.readCookiebotConsent();
const biskouiConsent = this.mapCookiebotConsent(cookiebotConsent);

if (biskouiConsent.length > 1) { // More than just functional
window.biskoui.updateConsent(biskouiConsent);
console.log('āœ… Migrated Cookiebot consent to biskoui:', biskouiConsent);
} else {
window.biskoui.showBanner();
}

this.disableCookiebot();
}

readCookiebotConsent() {
try {
return {
necessary: window.Cookiebot.consent.necessary,
preferences: window.Cookiebot.consent.preferences,
statistics: window.Cookiebot.consent.statistics,
marketing: window.Cookiebot.consent.marketing
};
} catch (error) {
console.error('Error reading Cookiebot consent:', error);
return {};
}
}

mapCookiebotConsent(cookiebotConsent) {
const categories = ['functional']; // Always include functional

if (cookiebotConsent.preferences) categories.push('functional');
if (cookiebotConsent.statistics) categories.push('analytics');
if (cookiebotConsent.marketing) categories.push('marketing');

return [...new Set(categories)]; // Remove duplicates
}

disableCookiebot() {
// Hide Cookiebot banner
const cookiebotDialog = document.getElementById('CybotCookiebotDialog');
if (cookiebotDialog) {
cookiebotDialog.style.display = 'none';
}
}
}

// Initialize Cookiebot migration
const cookiebotMigration = new CookiebotToBiskouiMigration();

šŸ›”ļø TrustArc to biskoui Migration​

TrustArc Migration Implementation:​

class TrustArcToBiskouiMigration {
constructor() {
this.setupMigration();
}

setupMigration() {
Promise.all([
this.waitForTrustArc(),
this.waitForBiskoui()
]).then(() => {
this.performMigration();
});
}

waitForTrustArc() {
return new Promise(resolve => {
if (window.truste) {
resolve();
} else {
const interval = setInterval(() => {
if (window.truste) {
clearInterval(interval);
resolve();
}
}, 100);
}
});
}

waitForBiskoui() {
return new Promise(resolve => {
if (window.biskoui?.isReady()) {
resolve();
} else {
window.biskoui?.on('ready', resolve);
}
});
}

performMigration() {
// TrustArc consent reading is more complex
const trustArcConsent = this.readTrustArcConsent();
const biskouiConsent = this.mapTrustArcConsent(trustArcConsent);

if (biskouiConsent.length > 1) {
window.biskoui.updateConsent(biskouiConsent);
console.log('āœ… Migrated TrustArc consent to biskoui:', biskouiConsent);
} else {
window.biskoui.showBanner();
}
}

readTrustArcConsent() {
try {
// TrustArc stores consent in cookies
const consentCookie = document.cookie
.split(';')
.find(cookie => cookie.trim().startsWith('notice_preferences'));

if (consentCookie) {
const consentValue = consentCookie.split('=')[1];
return this.parseTrustArcConsent(consentValue);
}
} catch (error) {
console.error('Error reading TrustArc consent:', error);
}

return {};
}

parseTrustArcConsent(consentValue) {
// TrustArc consent format varies, this is a simplified example
try {
const decoded = decodeURIComponent(consentValue);
const parsed = JSON.parse(decoded);
return parsed;
} catch (error) {
return {};
}
}

mapTrustArcConsent(trustArcConsent) {
const categories = ['functional'];

// Map based on TrustArc structure (varies by implementation)
if (trustArcConsent.analytics) categories.push('analytics');
if (trustArcConsent.advertising) categories.push('marketing');
if (trustArcConsent.social) categories.push('social');

return [...new Set(categories)];
}
}

Transition Strategy​

Phase 1: Preparation (1-2 weeks)​

Preparation Tasks:
āœ… Set up biskoui account and configuration
āœ… Map consent categories between systems
āœ… Test biskoui on staging environment
āœ… Prepare user communication materials
āœ… Create rollback plan
āœ… Schedule migration during low-traffic period

Phase 2: Parallel Implementation (1 week)​

Parallel Phase:
āœ… Deploy biskoui alongside existing CMP
āœ… Suppress old CMP banner display
āœ… Migrate existing consent to biskoui
āœ… Test all functionality thoroughly
āœ… Monitor for conflicts or issues

Phase 3: Switch and Cleanup (1 week)​

Cleanup Phase:
āœ… Remove old CMP scripts and configuration
āœ… Clean up residual cookies and data
āœ… Update documentation and procedures
āœ… Monitor performance and user feedback
āœ… Complete compliance documentation

šŸ› ļø Migration Helper Script​

// Universal CMP migration helper
class CMPMigrationHelper {
constructor() {
this.supportedCMPs = ['OneTrust', 'Cookiebot', 'TrustArc', 'Quantcast'];
this.migrationLog = [];
}

async performMigration() {
this.log('šŸš€ Starting CMP migration to biskoui');

try {
// Step 1: Detect current CMP
const currentCMP = this.detectCurrentCMP();
this.log(`šŸ“ Detected CMP: ${currentCMP}`);

// Step 2: Read current consent
const currentConsent = await this.readCurrentConsent(currentCMP);
this.log(`šŸ“Š Current consent: ${JSON.stringify(currentConsent)}`);

// Step 3: Wait for biskoui
await this.waitForBiskoui();
this.log('āœ… biskoui ready');

// Step 4: Map and transfer consent
const biskouiConsent = this.mapConsentToBiskoui(currentConsent, currentCMP);
this.log(`šŸ”„ Mapped consent: ${JSON.stringify(biskouiConsent)}`);

// Step 5: Set biskoui consent
if (biskouiConsent.length > 1) {
window.biskoui.updateConsent(biskouiConsent);
this.log('āœ… Consent migrated successfully');
} else {
window.biskoui.showBanner();
this.log('šŸ“¢ No existing consent, showing biskoui banner');
}

// Step 6: Clean up old CMP
this.cleanupOldCMP(currentCMP);
this.log('🧹 Old CMP cleaned up');

this.log('šŸŽ‰ Migration completed successfully');
return true;

} catch (error) {
this.log(`āŒ Migration failed: ${error.message}`);
console.error('Migration error:', error);
return false;
}
}

detectCurrentCMP() {
const detectors = {
'OneTrust': () => window.OneTrust || window.Optanon,
'Cookiebot': () => window.Cookiebot,
'TrustArc': () => window.truste,
'Quantcast': () => window.__qc,
'CookieYes': () => window.ckySettings,
'Termly': () => window.termly
};

for (const [name, detector] of Object.entries(detectors)) {
if (detector()) {
return name;
}
}

return 'Unknown';
}

async readCurrentConsent(cmp) {
switch (cmp) {
case 'OneTrust':
return this.readOneTrustConsent();
case 'Cookiebot':
return this.readCookiebotConsent();
case 'TrustArc':
return this.readTrustArcConsent();
default:
return this.readGenericConsent();
}
}

readOneTrustConsent() {
try {
const activeGroups = window.OnetrustActiveGroups?.split(',') || [];
return { type: 'OneTrust', groups: activeGroups };
} catch (error) {
return { type: 'OneTrust', groups: [] };
}
}

readCookiebotConsent() {
try {
return {
type: 'Cookiebot',
consent: {
necessary: window.Cookiebot.consent.necessary,
preferences: window.Cookiebot.consent.preferences,
statistics: window.Cookiebot.consent.statistics,
marketing: window.Cookiebot.consent.marketing
}
};
} catch (error) {
return { type: 'Cookiebot', consent: {} };
}
}

readTrustArcConsent() {
// Implementation depends on TrustArc configuration
return { type: 'TrustArc', consent: {} };
}

readGenericConsent() {
// Try to read from common consent cookies
const consentCookies = document.cookie.split(';')
.filter(cookie => cookie.toLowerCase().includes('consent'))
.map(cookie => cookie.trim());

return { type: 'Generic', cookies: consentCookies };
}

mapConsentToBiskoui(consent, cmp) {
const categories = new Set(['functional']); // Always include functional

switch (cmp) {
case 'OneTrust':
consent.groups.forEach(group => {
if (group.includes('C0002') || group.includes('performance')) categories.add('analytics');
if (group.includes('C0004') || group.includes('targeting')) categories.add('marketing');
if (group.includes('C0005') || group.includes('social')) categories.add('social');
});
break;

case 'Cookiebot':
if (consent.consent.statistics) categories.add('analytics');
if (consent.consent.marketing) categories.add('marketing');
break;

// Add other CMP mappings as needed
}

return Array.from(categories);
}

waitForBiskoui() {
return new Promise(resolve => {
if (window.biskoui?.isReady()) {
resolve();
} else {
window.biskoui?.on('ready', resolve);
}
});
}

cleanupOldCMP(cmp) {
switch (cmp) {
case 'OneTrust':
this.cleanupOneTrust();
break;
case 'Cookiebot':
this.cleanupCookiebot();
break;
case 'TrustArc':
this.cleanupTrustArc();
break;
}
}

cleanupOneTrust() {
// Hide banner
const banner = document.getElementById('onetrust-banner-sdk');
if (banner) banner.style.display = 'none';

// Disable future loading
window.OptanonWrapper = () => console.log('OneTrust disabled');
}

cleanupCookiebot() {
// Hide dialog
const dialog = document.getElementById('CybotCookiebotDialog');
if (dialog) dialog.style.display = 'none';
}

cleanupTrustArc() {
// Hide TrustArc elements
const elements = document.querySelectorAll('[id*="truste"], [class*="truste"]');
elements.forEach(el => el.style.display = 'none');
}

log(message) {
const timestamp = new Date().toISOString();
const logEntry = `${timestamp}: ${message}`;
this.migrationLog.push(logEntry);
console.log(logEntry);
}

getMigrationLog() {
return this.migrationLog;
}
}

// Initialize migration helper
const migrationHelper = new CMPMigrationHelper();

// Auto-start migration when page loads
window.addEventListener('load', () => {
migrationHelper.performMigration();
});

What Data Can Be Ported:​

Portable Data:
āœ… Consent categories and timestamps
āœ… User choice patterns and preferences
āœ… Geographic and legal basis information
āœ… Banner interaction history (limited)

Non-Portable Data:
āŒ Internal user IDs and tracking identifiers
āŒ CMP-specific configuration data
āŒ Detailed behavioral analytics
āŒ Third-party service integration data

Export Script for Common CMPs:​

// Universal consent data export
function exportConsentData() {
const exportData = {
timestamp: new Date().toISOString(),
domain: window.location.hostname,
cmp: 'Unknown',
consent: {},
cookies: {},
localStorage: {}
};

// Detect and export from OneTrust
if (window.OneTrust) {
exportData.cmp = 'OneTrust';
exportData.consent = {
geolocation: window.OneTrust.getGeolocationData(),
activeGroups: window.OnetrustActiveGroups?.split(',') || [],
domainData: window.OneTrust.GetDomainData()
};
}

// Detect and export from Cookiebot
else if (window.Cookiebot) {
exportData.cmp = 'Cookiebot';
exportData.consent = {
necessary: window.Cookiebot.consent.necessary,
preferences: window.Cookiebot.consent.preferences,
statistics: window.Cookiebot.consent.statistics,
marketing: window.Cookiebot.consent.marketing
};
}

// Export relevant cookies
document.cookie.split(';').forEach(cookie => {
const [name, value] = cookie.trim().split('=');
if (name.toLowerCase().includes('consent') ||
name.toLowerCase().includes('cookie') ||
name.toLowerCase().includes('privacy')) {
exportData.cookies[name] = value;
}
});

// Export relevant localStorage
Object.keys(localStorage).forEach(key => {
if (key.toLowerCase().includes('consent') ||
key.toLowerCase().includes('cookie') ||
key.toLowerCase().includes('privacy')) {
exportData.localStorage[key] = localStorage.getItem(key);
}
});

console.log('Consent Data Export:', exportData);

// Download as JSON file
const blob = new Blob([JSON.stringify(exportData, null, 2)],
{ type: 'application/json' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `consent-export-${exportData.domain}-${Date.now()}.json`;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);

return exportData;
}

// Import consent data into biskoui
function importConsentData(exportedData) {
if (!window.biskoui) {
console.error('biskoui not available for import');
return false;
}

try {
// Map exported data to biskoui categories
const biskouiCategories = mapExportedConsent(exportedData);

// Set consent in biskoui
window.biskoui.updateConsent(biskouiCategories);

console.log('āœ… Consent data imported successfully:', biskouiCategories);
return true;

} catch (error) {
console.error('āŒ Failed to import consent data:', error);
return false;
}
}

function mapExportedConsent(exportedData) {
const categories = new Set(['functional']);

switch (exportedData.cmp) {
case 'OneTrust':
exportedData.consent.activeGroups?.forEach(group => {
if (group.includes('C0002')) categories.add('analytics');
if (group.includes('C0004')) categories.add('marketing');
if (group.includes('C0005')) categories.add('social');
});
break;

case 'Cookiebot':
if (exportedData.consent.statistics) categories.add('analytics');
if (exportedData.consent.marketing) categories.add('marketing');
break;
}

return Array.from(categories);
}

User Communication Strategy​

šŸ“¢ Migration Communication Templates​

User Notification Email:​

Subject: Important Update: New Privacy Experience

Dear [Customer Name],

We're upgrading our website's privacy management system to provide you with a better, more transparent experience.

What's Changing:
āœ… Improved privacy controls and transparency
āœ… Faster website performance
āœ… Enhanced compliance with Swiss and EU privacy laws
āœ… More granular consent options

What This Means for You:
• Your existing privacy preferences will be preserved
• You may see a brief consent notification on your next visit
• No action is required unless you want to update your preferences

When: [Migration Date]

If you have any questions, please contact our support team at [contact email].

Best regards,
[Your Team]

Website Banner During Migration:​

<div class="migration-notice">
<div class="notice-content">
<span class="notice-icon">šŸ”„</span>
<div class="notice-text">
<strong>Privacy System Update</strong>
<p>We're upgrading our privacy management. Your preferences will be preserved.</p>
</div>
<button onclick="this.parentElement.parentElement.remove()" class="notice-close">Ɨ</button>
</div>
</div>

<style>
.migration-notice {
position: fixed;
top: 0;
left: 0;
right: 0;
background: #2196F3;
color: white;
z-index: 10000;
padding: 0;
}

.notice-content {
display: flex;
align-items: center;
padding: 12px 20px;
max-width: 1200px;
margin: 0 auto;
}

.notice-icon {
font-size: 24px;
margin-right: 15px;
}

.notice-text {
flex: 1;
}

.notice-text strong {
display: block;
margin-bottom: 4px;
}

.notice-text p {
margin: 0;
font-size: 14px;
opacity: 0.9;
}

.notice-close {
background: none;
border: none;
color: white;
font-size: 20px;
cursor: pointer;
padding: 5px;
margin-left: 15px;
}
</style>

Post-Migration Validation​

āœ… Migration Success Checklist​

Validation Checklist:
āœ… biskoui banner displays correctly
āœ… Consent choices are preserved from old CMP
āœ… All third-party scripts respect new consent
āœ… Performance metrics are improved or maintained
āœ… No console errors related to CMP conflicts
āœ… Compliance documentation is updated
āœ… User feedback is positive
āœ… Analytics data shows no significant drops

šŸ” Migration Validation Script​

// Post-migration validation
function validateMigration() {
console.log('šŸ” Post-Migration Validation Report');
console.log('===================================');

const validation = {
biskouiLoaded: false,
oldCMPRemoved: true,
consentWorking: false,
scriptsBlocked: false,
performanceOK: false,
errors: []
};

// Check biskoui
if (window.biskoui && window.biskoui.isReady()) {
validation.biskouiLoaded = true;
console.log('āœ… biskoui loaded and ready');
} else {
validation.errors.push('biskoui not loaded or not ready');
console.error('āŒ biskoui not loaded or not ready');
}

// Check for old CMP remnants
const oldCMPDetectors = {
'OneTrust': () => document.getElementById('onetrust-banner-sdk')?.style.display !== 'none',
'Cookiebot': () => document.getElementById('CybotCookiebotDialog')?.style.display !== 'none',
'TrustArc': () => document.querySelector('[id*="truste"]')?.style.display !== 'none'
};

Object.entries(oldCMPDetectors).forEach(([cmp, detector]) => {
if (detector()) {
validation.oldCMPRemoved = false;
validation.errors.push(`${cmp} banner still visible`);
console.warn(`āš ļø ${cmp} banner still visible`);
}
});

if (validation.oldCMPRemoved) {
console.log('āœ… Old CMP properly removed');
}

// Check consent functionality
if (validation.biskouiLoaded) {
try {
const consent = window.biskoui.getConsent();
validation.consentWorking = Array.isArray(consent);
console.log('āœ… Consent reading works:', consent);
} catch (error) {
validation.errors.push('Consent reading failed: ' + error.message);
console.error('āŒ Consent reading failed:', error);
}
}

// Check script blocking
const blockedScripts = document.querySelectorAll('[data-biskoui-category]');
if (blockedScripts.length > 0) {
validation.scriptsBlocked = true;
console.log('āœ… Script blocking active:', blockedScripts.length, 'elements');
} else {
console.warn('āš ļø No blocked scripts detected');
}

// Basic performance check
const perfTiming = performance.getEntriesByType('navigation')[0];
if (perfTiming) {
const loadTime = perfTiming.loadEventEnd - perfTiming.loadEventStart;
validation.performanceOK = loadTime < 3000; // 3 second threshold
console.log(`⚔ Page load time: ${loadTime}ms ${validation.performanceOK ? 'āœ…' : 'āš ļø'}`);
}

// Overall assessment
const criticalChecks = [validation.biskouiLoaded, validation.consentWorking];
const migrationSuccess = criticalChecks.every(check => check) && validation.errors.length === 0;

console.log('\nšŸ“Š Migration Validation Summary:');
console.log('Success:', migrationSuccess ? 'āœ…' : 'āŒ');
console.log('Errors:', validation.errors.length);

if (validation.errors.length > 0) {
console.log('Issues to address:');
validation.errors.forEach(error => console.log(' -', error));
}

return validation;
}

// Run validation 5 seconds after page load
window.addEventListener('load', () => {
setTimeout(validateMigration, 5000);
});

šŸ’” Pro Tip: Always perform migration during low-traffic periods and have a rollback plan ready. Monitor user behavior and site performance closely for the first week after migration to catch any issues early.