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ā
š Recommended Migration Approachā
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();
});
Consent Data Portabilityā
š Consent Log Export/Importā
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.