Documentation

VB consent manager

DEMO

https://consent-manager.vb-tool.de/

Changelog

changelog

Setup

There are two options to integrate the consent manager to your project.

  1. integrate javascript and css into your existing frontend package. (There is a build configuration using gulp and webpack in this project)
  2. load prebuild js and css files in your site and init the consent manager

For both of these cases you need to adapt your templates and embeds, integrate the frontend code part of the consent manager and finally initialize the consent manager.

Adapt your templates

The goal is to disable all execution and loading of external scripts or other sources that the user did not consent to.

there is a few different options to load a script:

  1. <script src="[external source]"></script>
  2. <script>[script code]</script>
  3. <iframe src="[external source]"></script>
  4. <link href="[external source]"></link>
  5. <style>[css code]</link>

All of those need to be changed in order to not load anything by default. most of that can be done by adding an attribute type="x-script/vbcn" or setting the src/href attribute to data-src/data-href

Examples for that can be found in /patterns/objects

You need a placeholder to represent the content while it is blocked. Examples for these placeholders can also be found in the files in /patterns/objects.

an example:

<!-- container where fb script will put hidden logic when activated -->
<div id="fb-root"></div>

<!-- script with data-type 'facebook' will only be executed when that option in the consent manager is set. See consent configuration. -->
<script type="x-script/vbcn" data-type="facebook">(function(d, s, id) {
    var js, fjs = d.getElementsByTagName(s)[0];
    if (d.getElementById(id)) return;
    js = d.createElement(s); js.id = id;
    js.src = 'https://connect.facebook.net/de_DE/sdk.js[…]';
    fjs.parentNode.insertBefore(js, fjs);
}(document, 'script', 'facebook-jssdk'));</script>

<!-- placeholder for the facebook container -->
<div class="vbcn-placeholder js-vbcn-placeholder vbcn-placeholder-type-facebook">
    <div class="vbcn-placeholder-content">

        <h4 class="vbcn-placeholder-headline">Externer Inhalt - Facebook Feed</h4>

        <p>
            An dieser Stelle finden Sie Inhalte eines Drittanbieters, die Sie mit einem Klick anzeigen lassen können.
        </p>

        <p class="vbcn-text-small">
            Dadurch können personenbezogene Daten an den Drittanbieter übermittelt werden. Mehr Informationen finden Sie in unseren <a href="/datenschutz">Datenschutzbestimmungen</a>.
        </p>

        <div class="vbcn-placeholder-actions">
            <button class="vbcn-execute vbcn-button primary js-vbcn-execute" data-type="facebook">Inhalte anzeigen</button>
        </div>
    </div>
</div>

Integrate consent manager frontend code

Integrated Version

see src/js/demo.js

Javascript

Copy src/js/vbcn/ into the components folder of your frontend js source files

include the module in your main.js (or default or similar) file by import initConsentManager from "./components/vbcn";

add the module with initConsentManager(options); to your onload-Listener

CSS/Sass

include the file src/sass/components/_vbcn.scss into your scss components folder

add the import of that module to the main scss file

Standalone Version

load <link rel="stylesheet" href="build/vbcn.css"> and <script src="build/vbcn.js" defer></script> in the of your page.

Configure and load VBCN

A configuration object could look like this:

sets is mandatory. So is texts[lang_key].explanationText.

const options = {
    notice: {
        ignoredPages: [
            '/no-data', 
            '/data-privacy'
        ],
        ignoredHashes: [
            '#hide-my-hash',
        ],
        showHashes: [
            '#show-vbcn'
        ],
        backdropColor: 'blue'
    },
    sets: {
        "de": [
          {
            id: 'mandatory',
            name: 'Notwendige Cookies',
            description: 'Diese Cookies sind für die einwandfreie Funktion und das Design unserer Seiten nötig. Sie speichern keine personenbezogenen Daten.',
            mandatory: true,
            mandatory_text: "Diese Cookies sind notwendig, um Ihre Einstellungen zu speichern."
          },
        ],
        "en": [
          {
            id: 'mandatory',
            name: 'Essential cookies',
            description: 'Cookies that ensure the functionality and the design of our webpages. No personal data are collected. These cookies are required to save your session settings.',
            mandatory: true,
            mandatory_text: "These cookies are mandatory."
          }
        ]
    },
    texts: {
        "de": {
          explanationText: "Nach Ihrer Zustimmung verwenden wir Cookies um die Anzeige zu optimieren. \n\n " +
            "Zur Analyse der Zugriffe auf unsere Website verwenden wir [[ Google Analytics / Matomo Analytics ]]. \n\n" +
            "Außerdem binden wir Skripte von [[ YouTube, Vimeo, Google Maps, Mapbox, Facebook, Twitter, Instagram, ...]] ein. \n\n" +
            "Dabei können personenbezogene Daten an diese Anbieter übermittelt werden. Bitte klicken Sie <a href='/datenschutz'>hier</a>, um Informationen zum Datenschutz zu erhalten.",
        },
        "en": {
          explanationText: "On your consent cookies are set to optimize your experience on our website. \n\n" +
            "We use [[ Google Analytics / Matomo Analytics ]] to analyze the usage  of our website. \n\n" +
            "We embed scripts from these third party service providers: [[ YouTube, Vimeo, Google Maps, Mapbox, Facebook, Twitter, Instagram, ... ]] \n\n" +
            "On activation of one or more of these services personal data might be forwarded to these partners. Further information you find <a href='/datenschutz'>here</a> in our privacy statement.",
        }
    }
}

It can then be used like this:

import init from "./vbcn";
init(options);

or like this for standalone:

document.addEventListener("DOMContentLoaded", function() {
    new VBCN(options)
});

configured options will be merged the options set in vbcn/defaults.js. Only sets will be completely overridden.

Languages

The consent manager uses the language defined in the html tag e.g. <html lang="en">. Your configuration should contain texts and sets for all possible languages of your site. In the default configuration there is 'de' and 'en' available. Everything else you need to configure yourself.

All available options

const options = {
    // settings for the cookie itself
    // mostly irrelevant with the default localstorage usage.
    cookie: {
        cookiename: "vbcn_settings", // also of the localstorage key
        cookieLifeTime: 1, // * lifeTimeUnit
        lifeTimeUnit: 'month', // month | day | session
        secure: true, // only set cookie in secure connections (e.g. https)
    },
    notice: {
        centerMode: true,
        // replaces `centerMode`
        // Applies classes
        // Options are: 'centered', 'center-bottom'. 
        displayMode: null,
        // page slugs on that the notice will not be shown
        ignoredPages: [
            '/datenschutz',
        ],
        // hashes that prevent the notice overlay. Can be useful for visual testing 
        ignoredHashes: [
            '#hide-vbcn'
        ],
        // hashes that force the notice overlay.
        showHashes: [
            '#show-vbcn'
        ],
        hasDeclineButton: true,
        // if set the decline button will no be rendered and can be placed in the text
        hasCustomDeclineButton: false,
        // if set the customize button will no be rendered and can be placed in the text
        hasCustomCustomizeButton: false, 
        // if set to 'session' or an integer will set the mandatory cookies for the set time so the user is not bugged for that time. 
        // consider changing the wording of the decline button in that case (e.g. "decline and save")
        declineMode: 'full', // 'full', 'session', 1 (day)
        // the base of which the z-index is checked. Increase to have the backdrop overlay things that are rendered later than the consent overlay.
        baseZIndex: 0,
        useBackdrop: true,
        backdropColor: '#333',
        backdropOpacity: '0.8',
        // if set to true will do the same as the decline button, else it will just hide the consent manager
        declineOnBackdropClick: false,
        // if set checks the checkboxes for the mandatory options on initialization
        preEnableMandatory: false,
        // automatically enable sets that are set as 'mandatory' on interaction with other checkboxes
        autoEnableMandatory: false,
        // if false mandatory options are checked and set to disabled
        mandatoryCanBeUnchecked: true,
        // automatically enable sets that are set as 'mandatory' on 'show content' on placeholders
        autoEnableMandatoryOnPlaceholder: true,
        // if set will place the explanation text (configuration_explanation_headline, configuration_explanation_text) at the top of the customize view
        useConfigurationExplanation: false,
        // if set will place the addtional info text (configuration_additional_headline, configuration_additional_info) at the bottom of the customize view below the option checkboxes
        useConfigurationAdditionalInfo: false,
        // shortcut to save a decline for 30 days and not bother the user again.
        // equal to {declineMode: 30, preEnableMandatory: true, autoEnableMandatory: true, mandatoryCanBeUnchecked: false}
        saveDecline: true,
        // show overlay on init. If false, the overlay will be shown if the user has not yet made a decision
        showOverlayOnInit: true,
        // if showOverlayOnInit is set you can decide to show the customize screen on first.
        showCustomizeMode: false, 
        // analytics settings 
        analytics: {
            // activate analytics insertion 
            addInfo: false,
            // a class to distinguish analytics relevant links
            analyticsClass: 'js-analytics-track',
            // name for the category in the analytics tool (matomo, ga, ...)
            categoryName: 'consent',
            // names for the actions in the analytics tool
            actions: {
                acceptPreset: 'accept-preset',
                decline: 'decline',
                customize: 'customize',
                save: 'save'
            },
            // names for the labels in the analytics tool
            labels: {
                acceptPreset: 'accept-preset consent',
                decline: 'decline consent',
                customize: 'customize consent',
                save: 'save consent'
            }
        }
    }, 

    // see placeholders in 'explanationText'
    texts: {
        "de": {
            initialHeadline: 'Cookies, externe Dienste & Datenschutz',
            customizeHeadline: 'Ihre Datenschutz-Einstellungen',
            explanationText: "",
            configuration_explanation_headline: "",
            configuration_explanation_text: "",
            configuration_additional_headline: "",
            configuration_additional_info: "",
            accept_preset_ButtonText: 'Alle akzeptieren',
            declineButtonText: 'Ablehnen ',
            accept_all_ButtonText: 'Alle Cookies akzeptieren',
            decline_all_ButtonText: 'Alle ablehnen',
            customizeButtonText: 'Einstellungen',
            cancel_customizeButtonText: 'Zurück',
            saveButtonText: 'Speichern',
            closeButtonText: '×'
        },
        "en": {
            initialHeadline: 'Cookies, third party services & privacy',
            customizeHeadline: 'Select cookies to accept',
            explanationText: "",
            configuration_explanation_headline: "",
            configuration_explanation_text: "",
            configuration_additional_headline: "",
            configuration_additional_info: "",
            accept_preset_ButtonText: 'Accept all',
            declineButtonText: 'Decline',
            accept_all_ButtonText: 'Accept all',
            decline_all_ButtonText: 'Decline all',
            customizeButtonText: 'Customize',
            cancel_customizeButtonText: 'Go back',
            saveButtonText: 'Save',
            closeButtonText: '×'
        },
        "it": {
            initalHeadline: 'Cookie, servizi esterni e protezione dei dati',
            customizeHeadline: 'Le vostre impostazioni sulla protezione dei dati',
            explanationText: "",
            configuration_explanation_headline: "",
            configuration_explanation_text: "",
            configuration_additional_headline: "",
            configuration_additional_info: "",
            accept_preset_ButtonText: 'Accetta tutti ',
            declineButtonText: 'Rifiuta',
            accept_all_ButtonText: 'Accetta tutti',
            customizeButtonText: 'Impostazioni',
            cancel_customizeButtonText: 'Indietro',
            saveButtonText: 'Salva',
        }
    }, 
    sets: {
        "de": [
            {
                id: 'mandatory',
                name: 'Notwendige Cookies',
                description: 'Diese Cookies sind für die einwandfreie Funktion und das Design unserer Seiten nötig. Sie speichern keine personenbezogenen Daten.',
                mandatory: true,
                mandatory_text: "Diese Cookies sind notwendig, um Ihre Einstellungen zu speichern."
            }, {
                id: 'style',
                name: 'Styling Cookies',
                description: 'Diese Cookies sind für die einwandfreie Funktion und das Design unserer Seiten nötig. Sie speichern keine personenbezogenen Daten.'
            }, {
                id: 'google_analytics',
                name: 'Google Analytics',
                description: 'Diese Skripte und Cookies werden eingebunden, um mehr über die Besucher unserer Website zu erfahren - wie zum Beispiel Herkunft, Bildschirmauflösung oder verwendeter Browser.'
            }, {
                id: 'matomo_analytics',
                name: 'Matomo Analytics',
                description: 'Diese Skripte und Cookies werden eingebunden, um mehr über die Besucher unserer Website zu erfahren - wie zum Beispiel Herkunft, Bildschirmauflösung oder verwendeter Browser.'
            }, {
                id: 'google_maps',
                name: 'Google Maps',
                description: 'Diese Skripte und Cookies sind nötig, um die Karten des Dienstes darzustellen. Durch das Aktivieren können personenbezogene Daten an Google übertragen werden.'
            }, {
                id: 'mapbox_maps',
                name: 'Mapbox',
                description: 'Diese Skripte und Cookies sind nötig, um die Karten des Dienstes darzustellen. Durch das Aktivieren können personenbezogene Daten an Mapbox übertragen werden.'
            }, {
                id: 'youtube_video',
                name: 'YouTube Video',
                description: 'Diese Skripte und Cookies sind nötig, um YouTube Videos auf dieser Seite abzuspielen. Durch das Aktivieren können personenbezogene Daten an YouTube übertragen werden.'
            }, {
                id: 'vimeo_video',
                name: 'Vimeo Videos',
                description: 'Diese Skripte und Cookies sind nötig, um Vimeo Videos auf dieser Seite abzuspielen. Durch das Aktivieren können personenbezogene Daten an Vimeo übertragen werden.'
            }, {
                id: 'facebook',
                name: 'Facebook',
                description: 'Diese Skripte und Cookies sind nötig, um unseren Facebook-Stream auf der Seite einzubinden. Durch das Aktivieren werden Skripte von Facebook eingebunden. Dabei können personenbezogene Daten an Facebook übertragen werden.'
            }, {
                id: 'twitter',
                name: 'Twitter',
                description: 'Diese Skripte und Cookies sind nötig, um unseren Twitter-Stream auf der Seite einzubinden. Durch das Aktivieren werden Skripte von Twitter eingebunden. Dabei können personenbezogene Daten an Twitter übertragen werden.'
            }, {
                id: 'social_streams',
                name: 'Social Media Streams',
                description: 'Diese Skripte und Cookies sind nötig, um unsere Social Media Streams auf der Seite einzubinden. Durch das Aktivieren können personenbezogene Daten an Facebook, Twitter, Instagram und YouTube übertragen werden.'
            }, {
                id: 'podigee_podcast',
                name: 'Podigee Podcast-Hosting',
                description: 'Wir nutzen den Podcast-Hosting-Dienst Podigee des Anbieters Podigee. Dabei werden IP-Adressen und Geräteinformationen verarbeitet um Podcast-Downloads/Wiedergaben zu ermöglichen und Abrufzahlen zu ermitteln.'
            }, {
                id: 'sendinblue',
                name: 'sendinblue Newsletter registration',
                description: 'lorem ipsum .'
            }
        ],
        "en": [
            {
                id: 'mandatory',
                name: 'Essential cookies',
                description: 'Cookies that ensure the functionality and the design of our webpages. No personal data are collected. These cookies are required to save your session settings.',
                mandatory: true,
                mandatory_text: "These cookies are mandatory."
            }, {
                id: 'style',
                name: 'Styling Cookies',
                description: 'Cookies that ensure the design of our webpages. No personal data are collected.'
            }, {
                id: 'google_analytics',
                name: 'Google Analytics',
                description: 'Scripts and cookies that gather information about visitors of the site, for example country of origin, device settings and browsers.'
            }, {
                id: 'matomo_analytics',
                name: 'Matomo Analytics',
                description: 'Scripts and cookies that gather information about visitors of the site, for example country of origin, device settings and browsers.'
            }, {
                id: 'google_maps',
                name: 'Google Maps',
                description: 'Scripts and cookies that are required to display the maps of this service. On activation personal data might be forwarded to Google.'
            }, {
                id: 'mapbox_maps',
                name: 'Mapbox',
                description: 'Scripts and cookies that are required to display the maps of this service. On activation personal data might be forwarded to Mapbox.'
            }, {
                id: 'youtube_video',
                name: 'YouTube Video',
                description: 'Scripts and cookies that are required to play videos of this service on this website. On activation personal data might be forwarded to YouTube (Google).'
            }, {
                id: 'vimeo_video',
                name: 'Vimeo Videos',
                description: 'Scripts and cookies that are required to play videos of this service on this website. On activation personal data might be forwarded to Vimeo.'
            }, {
                id: 'facebook',
                name: 'Facebook Cookies',
                description: 'Scripts and cookies that are required to integrate our Facebook stream on this website. On activation personal data might be forwarded to Facebook.'
            }, {
                id: 'twitter',
                name: 'Twitter Cookies',
                description: 'Scripts and cookies that are required to integrate our Twitter stream on this website. On activation personal data might be forwarded to Twitter.'
            }, {
                id: 'social_streams',
                name: 'Social Media Streams',
                description: 'Scripts and cookies that are required to integrate our Social Media  streams on this website. On activation personal data might be forwarded to Facebook, Twitter, Instagram and YouTube (Google).'
            }, {
                id: 'podigee_podcast',
                name: 'Podigee Podcast-Hosting',
                description: 'We use Podigee service to integrate podcasts on our website. On activation IP addresses and information about the device in use are processed to enable download/playback podcasts and to get the number of downloads/calls/hits.'
            }, {
                id: 'sendinblue',
                name: 'sendinblue Newsletter registration',
                description: 'lorem ipsum .'
            }]
    }
}

Integrate button to show cookie settings

have a button or link or anything really with the class .js-vbcn-customize

<button class="js-vbcn-customize">Cookie Einstellungen</button>

Usage in other scripts

check the state

import {checkState} from "./vbcn";

if(checkState('your-type') ) {
    doSomething()
} else {
    soSomethingElse();
}

enable a set

import {enableType} from "./vbcn";

enableType('your-type');

write data to the cookie

import {updateCookieData} from "./vbcn";
updateCookieData('some-key', 'a value')

API

The consent manager exposes an api to the window object.

As soon as you initialized the VBCN the api can be accessed.

document.addEventListener("DOMContentLoaded", function() {
    window.myVBCN = new VBCN({
        notice: {
            ignoredPages: [
                '/no-data'
            ],
            ignoredHashes: [
                '#hide-my-ass',
            ],
            backdropColor: 'blue',
        }
    })
});

enable a specific type/set

window.myVBCN.enableType('your-type');

write some data to the cookie to be stored

window.myVBCN.updateCookieData('key', 'data');

get the current cookie data

window.myVBCN.getCookieData();

check the state of a type

window.myVBCN.checkState('your-type');

get the current state

window.myVBCN.state;

Analytics

There is an option to add analytics tracking information to the buttons of the consent manager. To set the infos set notice.analytics.addInfo = true and adapt the settings in notice.analytics to your needs.

You can find an exemplary implementation of how to track an event to google analytics or matomo in demo/analytics.js.

In the demo you can see the output in the console.

FAQ

does it work on localhost

Setting cookies on localhost works completely different and is not implemented for the consent manager yet.

What happens with JavaScript disabled?

Nothing. All scripts and styles are supposed to be first enabled by Javascript. No Javascript, no enabling of scripts. That is why you need to adapt templates in the first place.

Development contribution

Please be aware that although we provide this software to developers on a "do whatever you want with it" basis you still need to fulfil your financial contribution towards the development. As soon as a website using the scripts provided goes live please let us know so we can invoice you.