<!-- This script tag would usually go inside the <head> tag, above all other JavaScrip <script> tags, but the limitations of Codepen prevent me from doing this. -->
<script>
  window.gdpr = {
    "addTag": function(tag,attr,content) {
      var newTag = document.createElement(tag);
      for (var prop in attr) {
        if (!attr.hasOwnProperty(prop)) continue;
        newTag.setAttribute(prop,attr[prop]);
      }
      if (content) newTag.innerHTML = content;
      var scripts = document.getElementsByTagName("script");
      var here = scripts[scripts.length - 1];
      here.parentElement.insertBefore(newTag, here.nextSibling);
    }
  };
  var gdprChoice = document.cookie.match(new RegExp('(^| )gdpr=([^;]+)'));
  window.gdpr.choice = gdprChoice ? (gdprChoice[0].split('=')[1] == 'true') : null;
</script>

<p>
  <button type="button" data-js="cookie-config">Change my cookie preferences</button>
  <button type="button" onclick="document.cookie='gdpr=;expires=Fri, 01 Jan 2000 00:00:00 UTC;path=/'">Clear GDPR cookie</button>
  <button type="button" data-js="show-cookie">Show current GDPR cookie</button>
  <output></output>
</p>

<!-- Google Tag Manager -->
<script>
  if (window.gdpr.choice) {
    (function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
      new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
      j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
      'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
    })(window,document,'script','dataLayer','GTM-XXXXXXX');
  }
</script>
<!-- End Google Tag Manager -->

<!-- jQuery -->
<!-- jQuery doesn't set cookies, but this is more an example of how to pass attributes to a script
tag using the arguments object. -->
<script>
  if (window.gdpr.choice) {
    window.gdpr.addTag('script',{
      'src': 'https://code.jquery.com/jquery-3.5.1.min.js',
      'integrity': 'sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0=',
      'crossorigin': 'anonymous'
    });
  }
</script>

<!-- YouTube -->
<!-- Note that it's possible to add YouTube videos in "privacy-enhanced mode", which should not require this logic -->
<script>
  if (window.gdpr.choice) {
    window.gdpr.addTag('iframe',{
      'width': '560',
      'height': '315',
      'src': 'https://www.youtube.com/embed/gsQQgfRay88',
      'frameborder': 0,
      'allow': 'accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture',
      'allowfullscreen': true
    });
  } else {
    window.gdpr.addTag('p','','Please enable cookies to see this YouTube video');
  }
</script>

<!-- Soundcloud -->
<script>
  if (window.gdpr.choice) {
    window.gdpr.addTag('div',{
      'style': 'font-size: 10px; color: #cccccc;line-break: anywhere;word-break: normal;overflow: hidden;white-space: nowrap;text-overflow: ellipsis; font-family: Interstate,Lucida Grande,Lucida Sans Unicode,Lucida Sans,Garuda,Verdana,Tahoma,sans-serif;font-weight: 100;'
    },'<a href="https://soundcloud.com/garyvee" title="garyvee" target="_blank" style="color: #cccccc; text-decoration: none;">garyvee</a> · <a href="https://soundcloud.com/garyvee/gdpr-social-media-technology" title="GDPR, Social Media &amp; Technology - Impact on Society | A Fireside Chat: Drinking and Thinking With GaryVee at VM London" target="_blank" style="color: #cccccc; text-decoration: none;">GDPR, Social Media &amp; Technology - Impact on Society | A Fireside Chat: Drinking and Thinking With GaryVee at VM London</a>');
    window.gdpr.addTag('iframe',{
      'width': '100%',
      'height': '300',
      'scrolling': 'no',
      'allow': 'autoplay',
      'src': 'https://w.soundcloud.com/player/?url=https%3A//api.soundcloud.com/tracks/465022536&color=%23ff5500&auto_play=false&hide_related=false&show_comments=true&show_user=true&show_reposts=false&show_teaser=true&visual=true'
    });
  } else {
    window.gdpr.addTag('p','','Please enable cookies to hear this podcast');
  }
</script>

<!-- Multiple pieces of content -->
<!-- Note that the order of the content is reversed, as each is added directly
 after the current <script> tag, but one after the other. -->
<script>
  if (window.gdpr.choice) {
    window.gdpr.addTag('img',{
      'src': 'https://placeimg.com/560/315/any',
      'width': 560,
      'height': 315,
      'alt': 'Placeholder image',
      'title': 'Title text'
    });
    window.gdpr.addTag('h1','','Content hidden from cookie rejectors');
  } else {
    window.gdpr.addTag('p','','Please enable cookies to see this content');
  }
</script>
body {
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;
  max-width: 60em;
  margin: 0 auto;
  padding: 1em;
}

// The banner which lets the user choose how they want to deal with cookies
[data-js="cookie-choice"] {
  background: #eee;
  bottom: 0;
  left: 0;
  opacity: 1;
  right: 0;
  transition: opacity .2s;
  position: fixed;
}

// Toggle class
.hide {
  opacity: 0;
}

// For demo purposes
output {
  border: dashed 2px #ccc;
  display: block;
  margin: 1em 0;
  padding: .5em;
}
View Compiled
// Has the setup already run?
if (typeof window.gdpr.choice === 'undefined') {
  // Adds (or updates) a global variable with the current state of the GDPR acceptance
  // (this code should also appear in the <head>, so it runs before the script tags appear
  // on the page)
  const gdprChoice = document.cookie.match(new RegExp('(^| )gdpr=([^;]+)'));
  window.gdpr.choice = gdprChoice ? (gdprChoice[0].split('=')[1] == 'true') : null;
}

// Adds the cookie control markup to the page
let cookieChoice = document.createElement('fieldset');
cookieChoice.setAttribute('data-js', 'cookie-choice');
// The cookie control always needs to be in the DOM, so the user can change their mind later
if (window.gdpr.choice !== null) {
  cookieChoice.classList.add('hide');
}
cookieChoice.innerHTML = '<legend>Please accept our cookies</legend><p><button type="button" data-js="gdpr-no">No, I don\'t think so</button> <button type="button" data-js="gdpr-yes">Oh, OK then</button></p>';
document.body.appendChild(cookieChoice);

cookieChoice.addEventListener('click', this.cookieDecision, false);

// Button so the user can change their mind (sometimes more than one appears on the page)
const btnConfig = document.querySelectorAll('[data-js="cookie-config"]');
for (var i = 0; i < btnConfig.length; i++) {
  btnConfig[i].addEventListener('click', function () {cookieChoice.classList.remove('hide')}, false);
}

// The user has interacted with the cookie control panel in some way
function cookieDecision(e) {
  const cookieChoice = document.querySelector('[data-js="cookie-choice"]');
  const btnType = e.target.getAttribute('data-js');
  // "No, I don't think so"
  if (btnType === 'gdpr-no') {
    cookieChoice.classList.add('hide');
    updateCookie(false);
    window.gdpr = false;
  }
  // "Oh, OK then"
  else if (btnType === 'gdpr-yes') {
    cookieChoice.classList.add('hide');
    updateCookie(true);
    window.gdpr = true;
  }
}

function updateCookie(yesOrNo) {
  let myDate = new Date;
  // This selects a date one year in the future, short by a couple of days
  // dev.to/rossangus/a-horrible-coincidence-3fbj
  myDate.setTime(myDate.getTime()+Math.pow(9,11));
  document.cookie = "gdpr=" + yesOrNo + ";expires=" + myDate.toGMTString() + ";SameSite=None;Secure;path=/";
}

// This is not core functionality, but is used to display the current GDPR cookie, for testing purposes
const btnShowCookie = document.querySelector('[data-js="show-cookie"]');
let cookieOutput = document.querySelector('output');

if (btnShowCookie && cookieOutput) {
  btnShowCookie.addEventListener('click', function () {
    let currentCookie = document.cookie.match(new RegExp('(^| )gdpr=([^;]+)'));
    if (currentCookie) {
       cookieOutput.innerHTML = currentCookie[0];
    } else {
      cookieOutput.innerHTML = 'null';
    }
  }, false);
}

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.