Pen Settings

HTML

CSS

CSS Base

Vendor Prefixing

Add External Stylesheets/Pens

Any URL's added here will be added as <link>s in order, and before the CSS in the editor. You can use the CSS from another Pen by using it's URL and the proper URL extention.

+ add another resource

JavaScript

Babel includes JSX processing.

Add External Scripts/Pens

Any URL's added here will be added as <script>s in order, and run before the JavaScript in the editor. You can use the URL of any other Pen and it will include the JavaScript from that Pen.

+ add another resource

Packages

Add Packages

Search for and use JavaScript packages from npm here. By selecting a package, an import statement will be added to the top of the JavaScript editor for this package.

Behavior

Save Automatically?

If active, Pens will autosave every 30 seconds after being saved once.

Auto-Updating Preview

If enabled, the preview panel updates automatically as you code. If disabled, use the "Run" button to update.

Format on Save

If enabled, your code will be formatted when you actively save your Pen. Note: your code becomes un-folded during formatting.

Editor Settings

Code Indentation

Want to change your Syntax Highlighting theme, Fonts and more?

Visit your global Editor Settings.

HTML

              
                <!-- initialize ConS -->
<script type="text/javascript">var _iub = _iub || {}; _iub.cons_instructions = _iub.cons_instructions || []; _iub.cons_instructions.push(["init", {api_key: "vB3SU82UQLQUQvu1dSuDhrEa4JdxBl0I"}]);</script>
<script type="text/javascript" src="https://cdn.iubenda.com/cons/iubenda_cons.js" async></script>

<!-- initialize CS -->
<script type="text/javascript">
  var _iub = _iub || [];
  _iub.csConfiguration = {
    "lang": "en",
    "siteId": 1792741, //use your siteId
    "consentOnContinuedBrowsing": false,
    "cookiePolicyId": 79838567, //use your cookiePolicyId
    "perPurposeConsent": true, //enable per-category consent
    "enableCMP": true, //enable IAB TCF
    "googleAdsPreferenceManagement": true,
    "banner": {
      "acceptButtonDisplay": true,
      "customizeButtonDisplay": true,
      "position": "float-top-center",
      "rejectButtonDisplay": true //show reject button
    },
    "callback": {
      "onReady": function() {
        console.log('[onReady] CS is initialized');
        console.log('[onReady] local consent: ' + JSON.stringify(_iub.cs.consent));
        consSyncronizer();
      },
      "onPreferenceFirstExpressed": function(preferences) {
        console.log('[onPreferenceFirstExpressed] ' + JSON.stringify(preferences));
        consSyncronizer();
      }
    }
  };
</script>
<script type="text/javascript" src="//cdn.iubenda.com/cs/tcf/stub.js"></script>

<header>
    <div class="wrapper">
        <h1>iubenda Cookie Solution</h1>
        <p>Integration between Cookie Solution and Consent Solution (sync at every pageview)</p>
    </div>
</header>

<section class="wrapper">
  
    <h2><mark>This demo is outdated: TCF v1.1 is no longer supported</mark></h2> 
      <p>👉 Click <a href="https://codepen.io/iubenda/pen/995b3bcac79d03024c1f5b70d2620d16?editors=1000" target="_blank">here</a> for a demo of the <strong>latest version (2.0)</strong>.</p>
  
    <hr />

    <p>In addition to GDPR consent for your forms, our <a href="https://www.iubenda.com/en/consent-solution" target="_blank">Consent Solution</a> allows you to save consent preferences collected with the <a href="https://www.iubenda.com/en/cookie-solution" target="_blank">Cookie Solution</a>. Read our <a href="https://www.iubenda.com/en/help/21982" target="_blank">guide on how to save proof of consent cookies</a> to learn more.</p>
  
    <p>Please note that this is the <strong>advanced demo</strong> (also with the <a href="https://codepen.io/iubenda/pen/rRNOYP/left?editors=1000" target="_blank">TCF option enabled</a>, here the <a href="https://codepen.io/iubenda/pen/995b3bcac79d03024c1f5b70d2620d16/left?editors=1000" target="_blank">same demo with TCF v2</a>), if you don't need to <a href="https://www.iubenda.com/en/help/21982#advanced" target="_blank">track preferences of a user across different devices</a>, take a look at the <a href="https://codepen.io/iubenda/pen/5a7e7ec4d57914b3d84671d66a6f922c/left?editors=1000" target="_blank">basic</a> one.</p>
  
    <p>To reopen the consent modal and edit your preferences:</p>
  
    <a href="#" class="iubenda-cs-preferences-link btn">Update your consent preferences</a> or <a href="#" class="iubenda-advertising-preferences-link btn">Update your advertising tracking preferences</a>

    <div class="note">
        <ul>
            <li><p>Remember to use your own credentials from <a href="https://www.iubenda.com/en/dashboard" target="_blank">your iubenda account</a></p></li>
            <li><p>As this is a sample for pure demonstrative purposes, we store the <code>subject_id</code> in the localStorage. A production application should bind a user and a <code>subject_id</code> at database level or anyway in a more reliable way than the browser localStorage.</p> <p>Also, the GET requests to the Consent Solution are possible only using the private key (since the public key is write only). This key should not be disclosed publicly in the frontend of the application. The GET requests should therefore be performed in the backend and the results passed along to the Cookie Solution.</p></li>
        </ul>
    </div>

    <h4>Helpful guides</h4>
    <ul class="guides">
        <li><a href="https://www.iubenda.com/en/help/1177" target="_blank">Cookie Solution - Getting Started</a></li>
        <li><a href="https://www.iubenda.com/en/help/3831" target="_blank">How to Customize the Look and Behavior of the Cookie Banner (Beginner's Guide)</a></li>
        <li><a href="https://www.iubenda.com/en/help/1205" target="_blank">How to Configure Your Cookie Solution (Advanced Guide)</a></li>
        <li><a href="https://www.iubenda.com/en/help/3081" target="_blank">Introduction to the Prior Blocking of Cookies</a></li>
    </ul>

</section>
              
            
!

CSS

              
                
              
            
!

JS

              
                // Utilities for reading, setting and deleting cookies
function setCookie(name, value, days) {
  var expires = "";
  if (days) {
    var date = new Date();
    date.setTime(date.getTime() + (days*24*60*60*1000));
    expires = "; expires=" + date.toUTCString();
  }
  document.cookie = name + "=" + (value || "")  + expires + "; path=/";
}

function getCookie(name) {
  var nameEQ = name + "=";
  var ca = document.cookie.split(';');
  for(var i=0;i < ca.length;i++) {
    var c = ca[i];
    while (c.charAt(0)==' ') c = c.substring(1,c.length);
    if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
  }
  return null;
}

function eraseCookie(name) {
  document.cookie = name+'=; Max-Age=-99999999;';
}

///////////////////////////////////////////////////////////////

// Send a POST request to the Consent Solution API and write a new consent for a given subject
// Writes the subject_id to localStorage if successful
function consPreferencesPost(subject, preferences) {
  _iub.cons_instructions.push(["submit",
    {
      consent: {
        subject: subject,
        preferences: preferences,
        proofs: [{
          content: 'test2',
          form: 'test2'
        }],
        legal_notices: [{
          identifier: "cookie_policy"
        }]
      }
    },
    {
      success: function(response) {
        console.log('[consPreferencesPost] Sent consent to ConS: ' + JSON.stringify(response));

        var response_body = JSON.parse(response.responseText);
        var subject_id = response_body.subject_id;
        console.log('[consPreferencesPost] Subject ID: ' + subject_id);

        localStorage.setItem('subject_id', subject_id);
        console.log('[consPreferencesPost] subject_id saved in local storage');
      },
      error: function(response) {
        console.log('[consPreferencesPost] Failed: ' + JSON.stringify(response));
      }
    }
  ]);
}

///////////////////////////////////////////////////////////////

// Synchronizing service that runs at every pageview before the Cookie Solution is loaded
// Used only to fetch a remote consent when a local consent doesn't exist before the Cookie Solution starts
function consPreflight() {
  console.log('[consPreflight] started');

  // Check if the subject id is available
  var subject_id = localStorage.getItem('subject_id');

  if (subject_id) {
    // Subject id available, check if we need to pull from the Consent Solution before activating the Cookie Solution
    console.log('[consPreflight] subject_id found: ' + subject_id);

    // Try to the fetch the Cookie Solution local cookie
    var cookiePolicyId = _iub.csConfiguration.cookiePolicyId;
    var cookieName = '_iub_cs-' + cookiePolicyId;
    var cookieLocal = getCookie(cookieName);

    if (cookieLocal === null) {
      // No local consent (cookie) found, but a remote consent (Consent Solution) likely exists
      // Fetch the remote consent and create a local consent from it
      console.log('[consPreflight] no local consent found: querying ConS');

      // Perform a request for the given subject_id to the Consent Solution
      // WARNING: This uses the private key and should be done in the backend
      $.ajax({
        url: "https://consent.iubenda.com/subjects/" + subject_id,
        type: "GET",
        headers: { "ApiKey": "vs3hcMXwsqrrauIfmW14pFHcUIm9CVvp" }
      })
      .done(function(data, textStatus, jqXHR) {
        console.log("[consPreflight] ConS call successful: creating cookie");
        var consPreferences = data.preferences;

        // Create the local consent with the remote consent info
        var cookieContent = {timestamp: consPreferences.cookieTimestamp.value, version: consPreferences.cookieVersion.value, purposes: consPreferences.cookiePurposes.value, id: cookiePolicyId};
        setCookie(cookieName, escape(JSON.stringify(cookieContent)), 365);

        if (_iub.csConfiguration.enableCMP) {
        // If the Cookie Solution uses the TCF...
          if (consPreferences.cookieTCFv1) {
            // ...create a cookie for the TCF...
            console.log("[consPreflight] TCF preferences found: creating cookie");
            var cookieTcfName = 'iubeuconsent';
            var cookieTcfContent = consPreferences.cookieTCFv1.value;
            setCookie(cookieTcfName, cookieTcfContent, 365);
          }

          if (consPreferences.cookieIsGoogleNonPersonalizedAds) {
            // ...and for Google Ads
            console.log("[consPreflight] Google Ads preferences found: creating cookie");
            var cookieGoogleAdsName = cookieName + '-granular';
            var cookieGoogleAdsContent = {googleAdsPersonalized: !consPreferences.cookieIsGoogleNonPersonalizedAds.value};
            setCookie(cookieGoogleAdsName, escape(JSON.stringify(cookieGoogleAdsContent)), 365);
          }
        }
      })
      .fail(function(jqXHR, textStatus, errorThrown) {
        // If the request fails, a few retries should be performed before activating the Cookie Solution
        console.log("[consPreflight] Consent Solution call failed");
        activateCookieSolution();
      })
      .always(function() {
        // Once the request and the syncronization is finished, activate the Cookie Solution
        console.log("[consPreflight] activating Cookie Solution");
        activateCookieSolution();
      });
    } else {
      // Local consent (cookie) found, we don't need to do any pre-configuration
      console.log('[consPreflight] local consent found: activating Cookie Solution');
      activateCookieSolution();
    }
  } else {
    // No subject_id available, so we have nothing to syncronize from
    console.log('[consPreflight] subject_id not found: activating Cookie Solution');
    activateCookieSolution();
  }
}

// Asynchronously activate the Cookie Solution
function activateCookieSolution() {
  var s = document.createElement('script');
  s.src = '//cdn.iubenda.com/cs/iubenda_cs.js';
  document.head.appendChild(s);
}

///////////////////////////////////////////////////////////////

// Synchronizing service that runs at every pageview once the Cookie Solution is loaded
// Used to keep in constant sync the local and the remote consent
function consSyncronizer() {
  // Check if the subject id is available
  var subject_id = localStorage.getItem('subject_id');

  // Gather all the local consent info
  var cookiePurposes = _iub.cs.consent.purposes;
  var cookieTimestamp = _iub.cs.consent.timestamp;
  var cookieVersion = _iub.cs.consent.version;
  var cookiePolicyId = _iub.cs.consent.id;

  if (subject_id === null) {
    // No subject_id found...
    if (cookieTimestamp == undefined) {
      // ...and also no local consent. This is most likely a first time visit
      console.log('[consSyncronizer] subject_id & local consent not found: aborting');

      return;
    } else {
      // ...but local consent found. It has probably never been sent to the ConS, so do it now
      console.log('[consSyncronizer] local consent found, subject_id not found: pushing to ConS');

      var cookiePreferences = {cookiePurposes: cookiePurposes, cookieTimestamp: cookieTimestamp, cookieVersion: cookieVersion, cookiePolicyId: cookiePolicyId};
      tcfAddPreferences(cookiePreferences, function() {
        consPreferencesPost({}, cookiePreferences);
      });

      return;
    }
  }

  // Both a subject_id and a local consent found, check if they need to be synced
  console.log('[consSyncronizer] subject_id & local consent found: ' + subject_id);

  // Query the ConS and retrieve the remote consent for the given subject
  $.ajax({
    url: "https://consent.iubenda.com/subjects/" + subject_id,
    type: "GET",
    headers: { "ApiKey": "vs3hcMXwsqrrauIfmW14pFHcUIm9CVvp" }
  })
  .done(function(data, textStatus, jqXHR) {
    console.log("[consSyncronizer] Consent Solution call successful");
    var consPreferences = data.preferences;

    // Convert local and remote timestamps into Unix time for easier comparison
    var consTimestamp = consPreferences.cookieTimestamp.value;
    var cookieUnixTime = new Date(cookieTimestamp).getTime();
    var consUnixTime = new Date(consTimestamp).getTime();

    console.log('[consSyncronizer] Consent Solution Timestamp: ' + consTimestamp);
    console.log('[consSyncronizer] Cookie Timestamp: ' + cookieTimestamp);

    if (cookieUnixTime == consUnixTime) {
      // Timestamps are equal: the local and remote consents are in sync, do nothing
      console.log('[consSyncronizer] cookieTimestamp == consTimestamp, do nothing');
      return;
    } else if (cookieUnixTime > consUnixTime) {
      // Local timestamp is newer than remote consent: something was changed locally, push the updated consent to ConS
      console.log('[consSyncronizer] cookieTimestamp > consTimestamp, push to ConS');
      var cookiePreferences = {cookiePurposes: cookiePurposes, cookieTimestamp: cookieTimestamp, cookieVersion: cookieVersion, cookiePolicyId: cookiePolicyId};
      tcfAddPreferences(cookiePreferences, function() {
        consPreferencesPost({id: subject_id}, cookiePreferences);
      });
    } else {
      // Remote timestamp is newer than local consent: something was changed in another Cookie Solution instance and the local consent is now old, get the updated consent from Consent Solution
      console.log('[consSyncronizer] cookieTimestamp < consTimestamp, updated from Consent Solution');
      _iub.cs.api.storeConsent({purposes: consPreferences.cookiePurposes.value});

      if (_iub.cs.options.enableCMP) {
        // If the Cookie Solution uses the TCF...
        if (consPreferences.cookieTCFv1) {
          // ...update the cookie for the TCF...
          console.log("[consSyncronizer] TCF preferences found: updated from Consent Solution");
          var cookieTcfName = 'iubeuconsent';
          var cookieTcfContent = consPreferences.cookieTCFv1.value;
          setCookie(cookieTcfName, cookieTcfContent, 365);
        }

        if (consPreferences.cookieIsGoogleNonPersonalizedAds) {
          // ...and for Google Ads
          console.log("[consSyncronizer] Google Ads preferences found: updated from ConS");
          var cookieGoogleAdsName = '_iub_cs-' + cookiePolicyId + '-granular';
          var cookieGoogleAdsContent = {googleAdsPersonalized: !consPreferences.cookieIsGoogleNonPersonalizedAds.value};
          setCookie(cookieGoogleAdsName, escape(JSON.stringify(cookieGoogleAdsContent)), 365);
        }
      }
    }
  })
  .fail(function(jqXHR, textStatus, errorThrown) {
    console.log("[consSyncronizer] Consent Solution call failed");
  });
}

///////////////////////////////////////////////////////////////

// Add the TCF (if active) values to a preferences object before pushing to the ConS (invoked via callback)
function tcfAddPreferences(preferences, callback) {
  if (!window.__cmp) {
    // Do nothing if the TCF is not active
    console.log('[tcfAddPreferences] tcf not found, preferences: ' + JSON.stringify(preferences));
    return callback();
  }

  __cmp('getConsentData', null, function(res) {
    // Append TCF and Google Ads values to the preferences object
    preferences.cookieTCFv1 = res.consentData;
    if (_iub.cs.options.googleAdsPreferenceManagement) {
      preferences.cookieIsGoogleNonPersonalizedAds = _iub.cs.api.isGoogleNonPersonalizedAds();
    }

    console.log('[tcfAddPreferences] tcf found, preferences: ' + JSON.stringify(preferences));
    callback();
  });
}

///////////////////////////////////////////////////////////////

// Entry point preloader for CS+ConS syncronization
consPreflight();
              
            
!
999px

Console