You are here

GDPR

description

GDPR by santiano.io is a two step consent form system allowing you to manage user's consents on their privacy inside GTM.

The idea is simply to have 3 levels of userConsentSettings to simplify the form for the user and in the same time provide you the ability to customize this form to your liking.

This is technical solution and I suggest you should contact your lawyer to manage the texts inside.

setup

Please refer to the container setup instructions

Step 1 - On Demand

Show me the GDPR popIn Step 1

Step 2 - On Demand

Show me the GDPR popIn Step 2

The slides from MeasureCamp London 18

tagging plans

Calling the GDPR Consent form on demand

Calling the GDPR Consent form on demand
Ways to call the GDPR consent form from the website itself

  <!-- To be called when you want to show the GDPR popIn on demand -->

<script type="text/javascript" >
  // To show Consent form Step 1
    dataLayer.push({
        'event': 'gdprShowConsentForm',
        'eventCommand': 'gdprShowPopInStep1'});

</script>

<script type="text/javascript" >
  // To show Consent form Step 2
    dataLayer.push({
        'event': 'gdprShowConsentForm',
        'eventCommand': 'gdprShowPopInStep2'});

</script>

<!-- In your HTML to add to your buttons, that's the same principe :) -->

<a href="#" onclick="dataLayer.push({'event': 'gdprShowConsentForm', 'eventCommand': 'gdprShowPopInStep1'});">Show me the GDPR popIn Step 1</a>

<a href="#" onclick="dataLayer.push({'event': 'gdprShowConsentForm', 'eventCommand': 'gdprShowPopInStep2'});">Show me the GDPR popIn Step 2</a>
close

gtm tags

GDPR PopIn

GDPR PopIn
Tag Type : Custom HTML
The GDPR Consent form popin itself with its Style / Html and Js logic

  <!-- santiano.io GDPR

The following code is separated in 3 parts :
-> Styling
-> HTML
-> Javascript
-->



<style>
/* 
  	For the CSS Lovers out there
   	Feel free to externalize and adapt this inline CSS
   	If you have advices for improving the style of this popIn
  	feel free to leave a comment on santiano.io
*/
  
  
.modal{
  display:none;
  position: fixed;
  z-index:9000; /* #over9000 thats' a Vegeta Safety */
  left: 0;
  top:0;
  height: 100%;
  max-height: 100%;
  width:100%;
  overflow: auto;
  background-color: rgba(0,0,0,0.6);
}

.modal-content{
  background:#fff;
  margin: 20% auto;
  width:70%;
  max-width: 550px;
  box-shadow: 0 5px 8px 0 rgba(0,0,0,0.2),0 7px 20px 0 rgba(0,0,0,0.17);
  animation-name:modalopen;
  animation-duration:1.5s;
  border-radius: 10px;
}

#gdprModal {
  
}

#gdprCredit a {
  color: #ffffff;
  text-decoration: underline;
}

#gdprControlBtn,
#gdprOkBtnStep1,
#gdprOkBtnStep2 {
  cursor: pointer;
  border-width: 0px;
  margin-left: 5px;
  padding: 6px 16px;
  font-size: 13px;
  line-height: 1.846;
  border-radius: 3px;
}

#gdprOkBtnStep1,
#gdprOkBtnStep2 {
  background-color: #4caf50;
  color: #ffffff;
}

#gdprControlBtn {
  background-color: #eeeeee;
  color: #000;
}

#gdprOkBtnStep1:hover,
#gdprOkBtnStep2:hover {
  background-color: #009933;
}

#gdprControlBtn:hover{
  background-color: #d7d7d7;
}
#gdprFooter {
  text-align: right;
}

#gdprCredit {
  color: #ffffff;
  text-align: left;
  position: fixed;
  bottom: 15px;
  left: 15px;
}
#gdprHeader h2{
  margin: 0px;
  padding: 20px 10px;
}

#gdprBody {
  padding-bottom: 20px;
  padding-left: 10px;
  padding-right: 10px;
}  

#gdprScreen {
  
} 

@media (max-width : 767.98px){

  #gdprScreenFirst,
  #gdprScreenSecond {
    margin: 0 auto;
    padding: 10px;
    width:100%;
  }
}

@media (min-width: 768px) {
  #gdprScreenFirst,
  #gdprScreenSecond {
    margin: 20% auto;
    padding: 10px;
    width:70%;
    max-width: 550px;
    border-radius: 10px;
  }
}
  
#gdprScreenFirst,
#gdprScreenSecond {
  display:none;
  background:#fff;
  padding: 10px;
  box-shadow: 0 5px 8px 0 rgba(0,0,0,0.2),0 7px 20px 0 rgba(0,0,0,0.17);
  animation-name:modalopen;
  animation-duration:1.5s;
  
}

@keyframes modalopen{
  from{ opacity: 0}
  to {opacity: 1}
}
  
</style>




<div id="gdprModal" class="modal">
  <div id="gdprScreen">
    <div id="gdprScreenFirst">
      <div id="gdprHeader">
        <h2 id="gdpr1Title"></h2>
      </div>
      <div id="gdprBody">
        <p id="gdpr1Paragraph"></p>
      </div>
      <div id="gdprFooter">
        <button id="gdprControlBtn" type="button"></button>
        <button id="gdprOkBtnStep1" type="button"></button>
      </div>
    </div>

    <div id="gdprScreenSecond">
      <div id="gdprHeader">
        <h2 id="gdpr2Title"></h2>
      </div>
      <div id="gdprBody">
        <p id="gdpr2Paragraph"></p>
        <div class="form-check">
          <input type="checkbox" value="" id="gdprStage0">
          <label id="gdprStage0Label" for="gdprStage0"></label>
        </div>
        <div class="form-check">
          <input type="checkbox" value="" id="gdprStage1">
          <label id="gdprStage1Label" for="gdprStage1"></label>
        </div>
        <div class="form-check">
          <input type="checkbox" value="" id="gdprStage2">
          <label id="gdprStage2Label" for="gdprStage2"></label>
        </div>
      </div>
      <div id="gdprFooter">
        <button id="gdprOkBtnStep2" type="button" class="btn btn-success">OK</button>
      </div>
    </div>
  </div>
  <div id="gdprCredit">
    <p>Privacy protected with <a target="_blank" href="http://santiano.io">santiano.io</a></p>
  </div>
</div>
<!-- Start of the JS logic -->
<script>

/* 
  	For the Javascript Lovers out there
   	Feel free to improve my code as I am far from a JS Jedi
   	If you have advices for improving the effciciency of this popIn
  	feel free to leave a comment on santiano.io
*/  
  

var gdprModal = document.getElementById('gdprModal');

var gdprStage0 = document.getElementById('gdprStage0');
var gdprStage1 = document.getElementById('gdprStage1');
var gdprStage2 = document.getElementById('gdprStage2');

// Grabbing the buttons
var gdprControlBtn = document.getElementById('gdprControlBtn');
var gdprOkBtnStep1 = document.getElementById('gdprOkBtnStep1');
var gdprOkBtnStep2 = document.getElementById('gdprOkBtnStep2');


// the First screen ;P
var gdprScreenFirst = document.getElementById('gdprScreenFirst');
// the Control center (itself)
var gdprScreenSecond = document.getElementById('gdprScreenSecond');

// button listeners
gdprControlBtn.addEventListener('click', gdprHideStep1ShowStep2);
gdprOkBtnStep1.addEventListener('click', gdprStep1validation);
gdprOkBtnStep2.addEventListener('click', gdprStep2validation);

// Checkboxes activations
gdprStage0.addEventListener('click', gdprStage0Select);
gdprStage1.addEventListener('click', gdprStage1Select);
gdprStage2.addEventListener('click', gdprStage2Select);

// Checkbox behavior : 
function gdprStage0Select(){
  if(document.getElementById('gdprStage0').checked == false) {
    checkboxUnSelect(gdprStage1);
    checkboxUnSelect(gdprStage2);
  };
};

function gdprUpdateTextContent(){
  // this feature is going to be usefull for Two reasons :
    // i might have to publish the content according to the 'websiteLanguage"
    // these strings can be plugged to the static DataLayer served by the website servers...
  var gdprPopInHtmlStrings = {{gdprPopInHtmlStrings}};

  //filling step 1 :
  document.getElementById('gdpr1Title').innerHTML = gdprPopInHtmlStrings.screenFirst.headerTitle;
  document.getElementById('gdpr1Paragraph').innerHTML = gdprPopInHtmlStrings.screenFirst.textContent;
  document.getElementById('gdprOkBtnStep1').innerHTML = gdprPopInHtmlStrings.screenFirst.buttonOK;
  document.getElementById('gdprControlBtn').innerHTML = gdprPopInHtmlStrings.screenFirst.buttonControl;
  // filling step 2 :
  document.getElementById('gdpr2Title').innerHTML = gdprPopInHtmlStrings.screenSecond.headerTitle;
  document.getElementById('gdpr2Paragraph').innerHTML = gdprPopInHtmlStrings.screenSecond.textContent;
  document.getElementById('gdprStage0Label').innerHTML = gdprPopInHtmlStrings.screenSecond.stage0;
  document.getElementById('gdprStage1Label').innerHTML = gdprPopInHtmlStrings.screenSecond.stage1;
  document.getElementById('gdprStage2Label').innerHTML = gdprPopInHtmlStrings.screenSecond.stage2;
  document.getElementById('gdprOkBtnStep2').innerHTML = gdprPopInHtmlStrings.screenSecond.buttonOK;
}

function gdprStage1Select(){
  if(document.getElementById('gdprStage1').checked == false) {
      checkboxUnSelect(gdprStage2);
    } else {
      checkboxSelect(gdprStage0);
    };
};

function gdprStage2Select(){
  if(document.getElementById('gdprStage2').checked == true) {
    checkboxSelect(gdprStage0);
    checkboxSelect(gdprStage1);
  }
};

// when the GDPR Sreen 1 is Validated
function gdprStep1validation(){
  gdprHideModal();
  setUserConsent();
  gdprAllValidations(); // Yeah
  // promo click 1 OK
};

function gdprStep2validation(){
  gdprHideModal();
  setUserConsent();
  setUserGtmTagsPreference(gdprGrabUserPreferenceFromForm());
  // promo click 
};

function gdprGrabUserPreferenceFromForm(){
	if(document.getElementById('gdprStage2').checked == true) {
    	return 3;
    } else if (document.getElementById('gdprStage1').checked == true) {
    	return 2;
    } else if (document.getElementById('gdprStage0').checked == true) {
    	return 1;
    } else {
    	return 0;
    };
}  

function gdprAllValidations(){
  // console.log('ALL 3 validated my friend');
  setUserGtmTagsPreference(3);

  window.localStorage.setItem('gdprUserConsentTimeStamp', new Date().getTime() );
  // where the dataLayerPush gets updated :) :) :) 
  // promo Click
};

function setUserConsent() {
	window.localStorage.setItem('gdprUserConsent', '1');
  	// could also be stored in a cookie
}
  
function setUserGtmTagsPreference(numBer) {
	// 
  	window.localStorage.setItem('gdprUserConsentSetting', numBer);
    var consentTimeStamp = new Date();
    window.localStorage.setItem('gdprUserConsentTimeStamp', consentTimeStamp.getTime() );
    
}
  
function readUserGtmTagsPreference() {
  	// reading the gdprUserConsentSetting 
	return window.localStorage.getItem('gdprUserConsentSetting');
}

  
function gdprPromoView(
  // next version guys i need sleep
){

}
function gdprPromoClick(
// next version guys as I really need sleep
){
  
}

function checkboxSelect(gdprStage){
  gdprStage.checked = true;
};

function checkboxUnSelect(gdprStage){
  gdprStage.checked = false;
};

function checkboxDisable(gdprStage){
  gdprStage.disabled = 'true';
};


function gdprGrabSettingsFromGtmUpdateForm(){
  var gdprCurrentSettings = readUserGtmTagsPreference();
  var gdprDefaultSettings = 1;
  // the dlv goes here
  if (gdprCurrentSettings == undefined){
    gdprCurrentSettings = gdprDefaultSettings;
  };
  switch(gdprCurrentSettings) {
    case '1':
        checkboxSelect(gdprStage0);
        break;
    case '2':
        checkboxSelect(gdprStage0);
        checkboxSelect(gdprStage1);
        break;
    case '3':
        checkboxSelect(gdprStage0);
        checkboxSelect(gdprStage1);
        checkboxSelect(gdprStage2);
        break;
    default:
        break;
    };
  var gdprStage0IsMandatory = 1;
  if (gdprStage0IsMandatory) {
  	checkboxSelect(gdprStage0);
    checkboxDisable(gdprStage0);
  }
};

function gdprShowStep1(){
  gdprShowModal()
  gdprScreenFirst.style.display ='block';
  gdprGrabSettingsFromGtmUpdateForm();
  gdprUpdateTextContent();
  // promo view 1 or event triggered
};

function gdprShowStep2(){
  gdprShowModal()
  gdprGrabSettingsFromGtmUpdateForm();

  gdprUpdateTextContent()
  gdprScreenSecond.style.display = 'block';
  // promo view 2 from Itself
};

function gdprHideStep1ShowStep2(){
  gdprScreenFirst.style.display ='none';
  gdprScreenSecond.style.display = 'block';
  // promo click 1 "control button"
  // promo view 2 from step 1
};


function gdprShowModal(){
  gdprModal.style.display = 'block';
};

function gdprHideModal(){
  gdprModal.style.display = 'none';
};

// now we are ready to show it guys
var eventCommand = {{eventCommand}};

if (eventCommand == 'gdprShowPopInStep1') {
  gdprShowStep1();

} else if (eventCommand == 'gdprShowPopInStep2') {
  gdprShowStep2();

} else {
  setTimeout(gdprShowStep1, 1000);
}



</script>

close
gdprDummyTag - Level 1

gdprDummyTag - Level 1
Tag Type : Custom HTML
Play with the popin and look at your console :) remember to remove this tag when you install the container

  <script> console.log("I am a level 1 tag And i have loaded");</script>
close
gdprDummyTag - Level 2

gdprDummyTag - Level 2
Tag Type : Custom HTML
Play with the GDPR popin and look at your browser console. Remember to remove that tag from your GTM

  <script> console.log("I am a level 2 tag And i have loaded");</script>
close
gdprDummyTag - Level 3

gdprDummyTag - Level 3
Tag Type : Custom HTML
Play with the GDPR popin and look at your console. remember to remove that from your GTM

  <script> console.log("I am a level 3 tag and i have loaded");</script>
close

gtm triggers

gdprExceptionTrigger - Group1 Tag

gdprExceptionTrigger - Group1 Tag
Trigger Type : Custom Event
This is an exception trigger for the group 1 tags -> audience tools
Event Name Match Regex : ^(.*)$ gdprUserConsentSetting is less than 1

close
gdprExceptionTrigger - Group2 Tag

gdprExceptionTrigger - Group2 Tag
Trigger Type : Custom Event
exception trigger for the group 2 tags
Event Name matches Regex ^(.*)$ gdprUserConsentSetting is less than 2

close
gdprExceptionTrigger - Group3 Tag

gdprExceptionTrigger - Group3 Tag
Trigger Type : Custom Event
This is an exception trigger for the group 1 tags -> audience tools
Event Name Match Regex : ^(.*)$ gdprUserConsentSetting is less than 1

close
gdprShowPopInStep1

gdprShowPopInStep1
Trigger Type : Custom Event
Show us the step ONE of of that popin
Event Name is : gdprShowConsentForm eventCommand equals gdprShowPopInStep1

close
gdprShowPopInStep2

gdprShowPopInStep2
Trigger Type : Custom Event
Show me the step 2
eventName : gdprShowConsentForm eventCommand = gdprShowPopInStep2

close
gdprUserConsentIsOutdated - All pages

gdprUserConsentIsOutdated - All pages
Trigger Type : Page View
When the consent is outdated
gdprConsentIsOutdated equals 1

close
gdprUserConsentIsRequired - All pages

gdprUserConsentIsRequired - All pages
Trigger Type : Page View
we should gather the consent of our user don't you think ?
gdprUserConsent equals 0

close

gtm variables

eventCommand

eventCommand
Variable Type : Data Layer Variable
santiano.io comes with its specific eventCommand : its naming scheme facilitates management and maintenance of events tags and ecommerce tags.

  Data Layer Variable Name  : eventCommand 
Data Layer Version : Version 2
close
gdprDefaultConsentFrequencyForUsers

gdprDefaultConsentFrequencyForUsers
Variable Type : Constant
Default Number of milliseconds between gdprConsent is asked again. (As we are dealing with European Law, we need to be super precise so it's expressed in milliseconds)

  Value : 2591999999
By the way that's equal to 29.9999999884 Days 
Feel free to change the frequency

close
gdprPopInHtmlStrings

gdprPopInHtmlStrings
Variable Type : Custom Javascript
The content of the pop up is stored in a variable so you can easily plug it to your dataLayer if you want

    function() {
    // ### Editing ###
    // Feel free to edit these text variables below
    // or connect them directly to your website dataLayer 
    // by changing this variable type while keeping the following objet structure
    //
    // ### Disclaimer ###
    // You should definitly have a 'wee chat' with your favorite lawyer :)
    // #iAmNotALawyer and should not be taking any responsability for the legality of your implementation
    // that's also the reason why santiano.io is released under Apache V2.0 licence
    //
    // ### Word of advice ###
    // Keep that popin cool and usable for two main reasons:
    // 1) Internet is a cool place
    // 2) https://www.youtube.com/watch?v=ewHQduV71hM
    // Ok now get back to work :)
    
    var gdprPopInHtmlStrings = {
		screenFirst: {
          'headerTitle': 'Your Privacy Settings',
          'textContent': 'As any other websites in the "Internets", we do use cookies and have third party tags running on this site that allow us to analyse our traffic and as a result improve your online experience. <br>We could also practice something called "Online Advertising" that really helps with the bills you know... <br>Please say yes and many people will keep their job :)',
          'buttonOK': 'I accept',
          'buttonControl': 'Control'
        },
        screenSecond: {
          'headerTitle': 'User data preference',
          'textContent': '#iAmNotALawyer so I suppose you should edit this text',
          'stage0': 'System cookies and anonymous audience tools',
          'stage1': 'Some intermediate level you will find a name for',
          'stage2': 'Personnalized advertising',
          'buttonOK': 'OK'
        }
    };
  return gdprPopInHtmlStrings;
}
close
gdprUserConsent

gdprUserConsent
Variable Type : Custom Javascript
The gdprUserConsent is a localStorage boolean taking the values of 1 or 0, default value is of course 0

    function() {
    var gdprUserConsent = window.localStorage.getItem('gdprUserConsent');
    if (gdprUserConsent == null) {
    	return 0
    } else {
  		return gdprUserConsent;
    }
  }
close
gdprUserConsentElapsedTime

gdprUserConsentElapsedTime
Variable Type : Custom Javascript
This calculates the elapsed time since the user provided his consent, (in milliseconds)

  function() {
    var gdprUserConsent = {{gdprUserConsent}};
	var gdprUserConsentTimeStamp = {{gdprUserConsentTimeStamp}};
	if (gdprUserConsent == '1') {
    	var now = new Date();
    	var gdprUserConsentElapsedTime = now.getTime() - gdprUserConsentTimeStamp;
      	return gdprUserConsentElapsedTime;
    } else {
    	return undefined
    }
}
close
gdprUserConsentIsOutdated

gdprUserConsentIsOutdated
Variable Type : Custom Javascript
We just check if our gdprUserConsent is outdated

    function() {
    // That would be very evil to change the frequency depending on the value of the 'gdprUserConsentSetting'
    // Doing so is more like Saruman than like Gandalf
    // Respect your users and you will finish in the greyHavens
    
    var gdprDefaultConsentFrequencyForUsers = {{gdprDefaultConsentFrequencyForUsers}};
	var gdprUserConsentElapsedTime = {{gdprUserConsentElapsedTime}};
	if (gdprUserConsentElapsedTime > gdprDefaultConsentFrequencyForUsers) {
    	return 1
    } else {
    	return 0
    }
}
close
gdprUserConsentSetting

gdprUserConsentSetting
Variable Type : Custom Javascript
This is a local storage variable taking care of the group of tags you have in GTM. the default value is 1 default, the values are expected to be between 0 and 3.

    function() {
    var gdprUserConsentSetting = window.localStorage.getItem('gdprUserConsentSetting');
  	if (gdprUserConsentSetting == null) {
        // that's my default setting here
    	return 1
    } else {
      	
  		return gdprUserConsentSetting;
    }   
  }
close
gdprUserConsentTimeStamp

gdprUserConsentTimeStamp
Variable Type : Custom Javascript
Stored timestamp in the localStorage of the userConsent

    function() {
    var gdprUserConsentTimeStamp = window.localStorage.getItem('gdprUserConsentTimeStamp');
  	if (gdprUserConsentTimeStamp == null) {
    	return undefined
    } else {
  		return gdprUserConsentTimeStamp;
    }    
  }
close

Add comment

Download