Skip to content

Instantly share code, notes, and snippets.

@hans2103
Created April 10, 2024 10:03
Show Gist options
  • Save hans2103/13243293eb5e72b6e2c87751a42da458 to your computer and use it in GitHub Desktop.
Save hans2103/13243293eb5e72b6e2c87751a42da458 to your computer and use it in GitHub Desktop.
Cookie Consent for Google Tag Manager

Google Consent Mode implemented using GTM

This gist contains the code to implement a Consent Mode popup.

  1. Add a small piece of HTML code, as described in Website-Head-code.md, to the <head> of your website to set the consent as early as possible
  2. Then connect your website to Google Tag Manager using the provided code snippets by GTM. (or use a plugin from your CMS)
  3. Create a GTM Tag containing the HTML code from GTM-Tag-Custom-HTML.md
  4. Create a GTM Trigger as described in GTM-Trigger-gtm_consent_update.md
  5. Now you have a Consent Mode popup on your site storing the chosen consent in LocalStorage
  6. Create Tags depending on the created Trigger

GTM Tag

  • Name: Consent Mode
  • Type: Customm HTML
  • Content: code block below
  • Trigger: Consent Initialization - All Pages
<button type="button" class="cc-modal__button--settings" onclick="openCCModal('cc-accept')" aria-label="cookie settings">
    cookie
</button>

<div id="cc-accept" class="cc-modal">
    <div role="dialog" class="cc-modal__dialog">
        <div class="cc-modal__content">
            <div class="cc-modal__header">
                <h2>Deze website maakt gebruik van cookies</h2>
            </div>
            <div class="cc-modal__body">
                <p>
                    Deze website maakt gebruik van cookies om de functionaliteit en effectiviteit te verbeteren. Sommige cookies worden geplaatst door diensten van derden. Door op ‘accepteren en doorgaan’ te klikken ga je akkoord met het gebruik van cookies zoals omschreven in onze privacyverklaring. Je kunt je eigen voorkeuren aanpassen door op ‘zelf instellen’ te klikken.</p>
                <details>
                    <summary>Wat zijn cookies?</summary>
                    <div>
                        <p>Cookies zijn kleine tekstbestanden die door websites kunnen worden gebruikt om gebruikerservaringen efficiënter te maken.</p>
                        <p>Volgens de wet mogen wij cookies op jouw apparaat opslaan als ze strikt noodzakelijk zijn voor het gebruik van de site. Voor alle andere soorten cookies hebben we je toestemming nodig.</p>
                        <p>Deze website maakt gebruik van verschillende soorten cookies. Sommige cookies worden geplaatst door diensten van derden die op onze pagina's worden weergegeven.</p>
                        <p>Je kunt je toestemming op elk moment wijzigen of intrekken.</p>
                    </div>
                </details>
            </div>
            <div class="cc-modal__footer">
                <button id="cc-reject-all" class="cc-modal__button">Weiger</button>
                <button onclick="openCCModal('cc-settings')" class="cc-modal__button">Zelf instellen</button>
                <button id="cc-accept-all" class="cc-modal__button cc-modal__button--active">Accepteren</button>
            </div>
        </div>
    </div>

    <div id="cc-settings" class="cc-modal">
        <div role="dialog" class="cc-modal__dialog">
            <div class="cc-modal__content">
                <div class="cc-modal__header">
                    <button class="cc-modal__button-close" onclick="closeCCModal('cc-settings')" aria-label="Close">X</button>
                    <h2>Cookie Settings</h2>
                    <p>Welke cookies mogen we plaatsen?</p>
                </div>
                <div class="cc-modal__body">
                    <h3>Noodzakelijke cookies</h3>
                    <p>Noodzakelijke cookies helpen een website bruikbaarder te maken, door basisfuncties als paginanavigatie en toegang tot beveiligde gedeelten van de website mogelijk te maken. Zonder deze cookies kan de website niet naar behoren werken.</p>
                    <label><input id="consent-necessary" type="checkbox" value="cookiesNecessary" checked disabled/>Noodzakelijke cookies (altijd aan)</label>

                    <hr/>

                    <h3>Persoonlijke instellingen</h3>
                    <p>Voorkeurscookies zorgen ervoor dat een website informatie kan onthouden die van invloed is op het gedrag en de vormgeving van de website, zoals de taal van je voorkeur of de regio waar je woont.</p>
                    <label><input id="consent-preferences" type="checkbox" value="cookiesPreferences" checked />Voorkeurscookies</label>

                    <hr/>

                    <h3>Statistische cookies</h3>
                    <p>Statistische cookies helpen eigenaren van websites begrijpen hoe bezoekers hun website gebruiken, door anoniem gegevens te verzamelen en te rapporteren.</p>
                    <label><input id="consent-analytics" type="checkbox" value="cookiesAnalytics" checked />Statistiche cookies</label>

                    <hr/>

                    <h3>Marketing cookies</h3>
                    <p>Marketingcookies worden gebruikt om bezoekers te volgen wanneer ze verschillende websites bezoeken. Hun doel is advertenties weergeven die zijn toegesneden op en relevant zijn voor de individuele gebruiker. Deze advertenties worden zo waardevoller voor uitgevers en externe adverteerders.</p>
                    <label><input id="consent-marketing" type="checkbox" value="cookiesMarketing" />Marketing cookies</label>

                </div>

                <div class="cc-modal__footer">
                    <button id="cc-accept-selection" class="cc-modal__button cc-modal__button--active">Settings opslaan</button>
                </div>
            </div>
        </div>
    </div>
</div>

<style>
    .cc-modal {
        position: fixed;
        inset: 0;
        z-index: 1050;
        display: flex;
        justify-content: center;
        align-items: center;
        overflow: hidden;
        outline: 0;
        transition: opacity .15s linear;
        font-size: 16px;
        line-height: 1.5555555556;
        font-weight: 400;
        letter-spacing: normal;
        background-color:rgba(20,20,20,.75);
        font-family: system-ui, sans-serif;
    }

    .cc-modal:not(.open) {
        display: none;
        opacity: 0;
    }

    .cc-modal.open {
        overflow-x: hidden;
        overflow-y: auto;
    }

    .cc-modal h2 {
        font-size: 2em;
    }

    .cc-modal .cc-modal__dialog {
        transition: transform .3s ease-out;
        transform: translate(0,-50px);

        position: relative;
        margin: 1.75em auto;
        inline-size: calc(100% - 1em);
        pointer-events: none;
        max-inline-size: 42em;
        max-block-size:80vh;
    }

    .cc-modal.open .cc-modal__dialog {
        transform: none;
    }

    .cc-modal__content {
        position: relative;
        display: flex;
        flex-direction: column;
        inline-size: 100%;
        pointer-events: auto;
        background-color: #f8f9fa;
        background-clip: padding-box;
        border: 1px solid rgba(0,0,0,.2);
        border-radius: 0.3em;
        outline: 0;
    }

    .cc-modal__content > * {
        padding: 1em;
    }

    .cc-modal__content > * > * {
        margin-block: unset;
    }

    .cc-modal__header {
        border-bottom: 1px solid;
    }

    .cc-modal__body > * + * {
        margin-top: .5em;
    }
    .cc-modal__footer {
        display: flex;
        align-items: stretch;
        gap: .5em;
        border-top: 1px solid;
    }

    .cc-modal__button {
        flex:  1;
        color: #1a73e8;
        background-color: #ffffff;
        border: 1px solid #dadce0;
        border-radius: .25em;
        padding:  1em;
        cursor: pointer;
        transition: background-color .2s,box-shadow .2s,color .2s;
    }

    .cc-modal__button:hover,
    .cc-modal__button:focus {
        background-color: #f6f9fe;
        border-color: #1a73e8;
        color: #174ea6;
    }

    .cc-modal__button--active {
        color: #ffffff;
        background-color: #1a73e8;
        border-color: #1a73e8;
    }

    .cc-modal__button--active:hover,
    .cc-modal__button--active:focus {
        box-shadow: 0 1px 2px 0 rgba(60,64,67,.3), 0 1px 3px 1px rgba(60,64,67,.15);
        background-color: #185abc;
        color: #ffffff;
    }

    .cc-modal__button--settings {
        position: fixed;
        display: flex;
        justify-content: center;
        align-items: center;
        inset-block-end: .5em;
        inset-inline-start: .5em;
        border: none;
        background: transparent;
    }

    .cc-modal__button--settings svg {
        inline-size: 1em;
        block-size: 1em;
    }

    .cc-modal__button-close {
        border: none;
        background: transparent;
        float: right;
    }


    .cc-modal details {
        padding: .5em;
        border: 1px solid #dadce0;
        border-radius: .25em;
    }

    .cc-modal details summary {
        cursor: pointer;
    }

    .cc-modal details summary > * {
        display: inline;
    }

    details[open] summary {
        border-bottom: 1px solid #dadce0;
        margin-bottom: 0.5em;
    }

    .cc-modal details > div > * {
        margin-bottom: unset;
    }

    .cc-modal details > div > * + * {
        margin-top: .5em;
    }
</style>


<script>
    function openCCModal(id) {
        document.getElementById(id).classList.add('open');
        document.body.classList.add('cc-modal-open');

        if (localStorage.getItem('consentMode') !== null) {
            restoreFromLocalStorage();
        }
    }

    // close currently open modal
    function closeCCModal(id) {
        document.getElementById(id).classList.remove('open');
        document.body.classList.remove('cc-modal-open');
    }

    // close all open modals
    function closeCCModals() {
        document.querySelector('.cc-modal.open').classList.remove('open');
        document.body.classList.remove('cc-modal-open');
    }

    window.dataLayer = window.dataLayer || [];
  
    function gtag() {
      dataLayer.push(arguments);
    }

    // accept all cookies
    function acceptAllCookies() {
        setConsent(
            {
                adStorage: true,
                analyticsStorage: true,
                personalizationStorage: true,
                functionalityStorage: true,
                securityStorage: true,
                adUserData: true,
                adPersonalization: true
            }
        );
        closeCCModals();
    };

    // accept selection
    function acceptSelectedCookies() {
        setConsent(
            {
                adStorage: document.getElementById('consent-marketing').checked,
                analyticsStorage: document.getElementById('consent-analytics').checked,
                personalizationStorage: document.getElementById('consent-preferences').checked,
                functionalityStorage: document.getElementById('consent-preferences').checked,
                securityStorage: true,
                adUserData: document.getElementById('consent-marketing').checked,
                adPersonalization: document.getElementById('consent-marketing').checked,
            }
        );
        closeCCModals();
    }

    // accept only necessary
    function acceptNoCookies() {
        setConsent(
            {
                adStorage: false,
                analyticsStorage: false,
                personalizationStorage: false,
                functionalityStorage: false,
                securityStorage: true,
                adUserData: false,
                adPersonalization: false
            }
        );
        closeCCModals();
    }

    // set consent
    function setConsent(consent) {
        var consentMode = {
            'ad_storage': consent.adStorage ? 'granted' : 'denied',
            'analytics_storage': consent.analyticsStorage ? 'granted' : 'denied',
            'personalization_storage': consent.personalizationStorage ? 'granted' : 'denied',
            'functionality_storage': consent.functionalityStorage ? 'granted' : 'denied',
            'security_storage': consent.securityStorage ? 'granted' : 'denied',
            'ad_user_data': consent.adUserData ? 'granted' : 'denied',
            'ad_personalization': consent.adPersonalization ? 'granted' : 'denied',
        };
        gtag('consent', 'update', consentMode);
        localStorage.setItem('consentMode', JSON.stringify(consentMode));
        dataLayer.push({event: 'gtm_consent_update'});
    }

    // load settings
    function   restoreFromLocalStorage() {
        var consent = JSON.parse(localStorage.getItem('consentMode'));

        if (consent.adStorage === 'granted'
            || consent.adUserData === 'granted'
            || consent.adPersonalization === 'granted') {
            document.getElementById('consent-marketing').setAttribute('checked', 'checked')
        }

        if (consent.analyticsStorage === 'granted') {
            document.getElementById('consent-analytics').setAttribute('checked', 'checked')
        }

        if (consent.personalizationStorage === 'granted'
            || consent.functionalityStorage === 'granted') {
            document.getElementById('consent-preferences').setAttribute('checked', 'checked')
        }

        if (consent.securityStorage === 'granted') {
            document.getElementById('consent-necessary').setAttribute('checked', 'checked')
        }
    }

    // Store the cookie preferences into local storage
    if (localStorage.getItem('consentMode') === null) {
        document.getElementById('cc-accept').classList.add('open');
    }

    document.getElementById('cc-accept-all').addEventListener('click', function (ev) {
        acceptAllCookies()
    });

    document.getElementById('cc-accept-selection').addEventListener('click', function (ev) {
        acceptSelectedCookies();
    });

    document.getElementById('cc-reject-all').addEventListener('click', function (ev) {
        acceptNoCookies();
    });
</script>

Head script for the website

Place the script below in the head of your website to set the default consent mode or fetch it from localhost

<script>
window.dataLayer = window.dataLayer || [];

function gtag() {
    dataLayer.push(arguments);
}

if (localStorage.getItem('consentMode') === null) {
    gtag('consent', 'default', {
        'ad_storage': 'denied',
        'ad_user_data': 'denied',
        'ad_personalization': 'denied',
        'analytics_storage': 'granted',
        'personalization_storage': 'granted',
        'functionality_storage': 'granted',
        'security_storage': 'granted',
    });
} else {
    gtag('consent', 'default', JSON.parse(localStorage.getItem('consentMode')));
}
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment