Iubenda logo
Start generating

Documentation

Table of Contents

How to save proof of consent to cookies (Privacy Controls and Cookie Solution and Consent Database integration)

In addition to recording GDPR consent for your forms, our Consent Database also allows you to save consent preferences collected with the Privacy Controls and Cookie Solution. Below we’ll explain how to save proof of consent to cookies with the combination of both solutions.

If you need to track consent preferences across different devices, jump to the advanced integration method.

Basic integration

Consent Database

Once you’ve activated the Consent Database, copy the snippet you find on Dashboard > [Your website] > Consent Database > Embed and paste it in the HEAD of your pages:

<!-- Consent Database -->
<script type="text/javascript">
    var _iub = _iub || {};
    _iub.cons_instructions = _iub.cons_instructions || [];
    _iub.cons_instructions.push(["init", {
        api_key: "YOUR_PUBLIC_API_KEY" //use your API key
    }]);
</script>
<script type="text/javascript" src="https://cdn.iubenda.com/cons/iubenda_cons.js" async></script>

The API key (displayed as “YOUR_PUBLIC_API_KEY” in the example above) is a unique code generated by us during the Consent Database activation and is specific to the particular site.

Privacy Controls and Cookie Solution

The Consent Database code will be followed by the Privacy Controls and Cookie Solution script. Once configured and saved your cookie banner, the Privacy Controls and Cookie Solution snippet will be similar to this:

<!-- Privacy Controls and Cookie Solution -->
<script type="text/javascript">
    var _iub = _iub || [];
    _iub.csConfiguration = {
        "lang": "en",
        "siteId": XXXXXX, //use your siteId
        "cookiePolicyId": YYYYYY, //use your cookiePolicyId
        "banner": {
            "position": "float-top-center",
            "acceptButtonDisplay": true,
            "customizeButtonDisplay": true
        }
    };
</script>
<script type="text/javascript" src="//cdn.iubenda.com/cs/iubenda_cs.js" charset="UTF-8" async></script>

In order to pass consent preferences to the Consent Database we’ll have to define a bannerHTML variable (via which we’ll save the banner HTML to use it as a proof) and a couple of callbacks:

<!-- Privacy Controls and Cookie Solution -->
<script type="text/javascript">
    var _iub = _iub || [];
    var bannerHTML; //bannerHTML variable
    _iub.csConfiguration = {
        "lang": "en",
        "siteId": 896537, //use your siteId
        "cookiePolicyId": 8207462, //use your cookiePolicyId
        "banner": {
            "position": "float-top-center",
            "acceptButtonDisplay": true,
            "customizeButtonDisplay": true
        },
        "callback": {
            "onReady": function() {
                var banner = document.getElementById('iubenda-cs-banner');
                if (banner) {
                    bannerHTML = banner.innerHTML;
                }
            },
            "onPreferenceFirstExpressed": function(event) {
                _iub.cons_instructions.push(["submit",
                    {
                        consent: {
                            subject: {},
                            preferences: event,
                            legal_notices: [{
                                identifier: "cookie_policy"
                            }],
                            proofs: [{
                                content: JSON.stringify(event),
                                form: bannerHTML
                            }]
                        }
                    }
                ]);
            }
        }
    };
</script>
<script type="text/javascript" src="//cdn.iubenda.com/cs/iubenda_cs.js" charset="UTF-8" async></script>

Once implemented, your Consent Database dashboard will store all the cookie consent preferences collected through the cookie banner:

Consent Solution dashboard with cookie preferences

You can also store any additional parameters you’d like to add to your cookie consent proofs, such as consent method (e.g. consentOnScroll , consentOnLinkAndButton), purposes etc.

Advanced integration (consent preferences synchronized across multiple devices)

If you need to track preferences of a user across different devices (e.g. website and mobile app), you’ll have to call the Consent Database at every pageview to keep the preferences constantly in sync among multiple Privacy Controls and Cookie Solution installations.

Let’s see how to do it.

Consent Database

As before, once you’ve activated the Consent Database, copy the snippet you find on Dashboard > [Your website] > Consent Database > Embed and paste it in the HEAD of your pages:

<!-- Consent Database -->
<script type="text/javascript">
    var _iub = _iub || {};
    _iub.cons_instructions = _iub.cons_instructions || [];
    _iub.cons_instructions.push(["init", {
        api_key: "YOUR_PUBLIC_API_KEY" //use your API key
    }]);
</script>
<script type="text/javascript" src="https://cdn.iubenda.com/cons/iubenda_cons.js" async></script>

The API key (displayed as “YOUR_PUBLIC_API_KEY” in the example above) is a unique code generated by us during the Consent Database activation and is specific to the particular site.

Privacy Controls and Cookie Solution

Again, the Consent Database code will be followed by the Privacy Controls and Cookie Solution script. Once configured and saved your cookie banner, the Privacy Controls and Cookie Solution snippet will be similar to this:

<!-- Privacy Controls and Cookie Solution -->
<script type="text/javascript">
    var _iub = _iub || [];
    _iub.csConfiguration = {
        "lang": "en",
        "siteId": XXXXXX, //use your siteId
        "cookiePolicyId": YYYYYY, //use your cookiePolicyId
        "banner": {
            "position": "float-top-center",
            "acceptButtonDisplay": true,
            "customizeButtonDisplay": true
        }
    };
</script>
<script type="text/javascript" src="//cdn.iubenda.com/cs/iubenda_cs.js" charset="UTF-8" async></script>

In order to pass consent preferences to the Consent Database, we’ll have to define two callbacks that are fired by the Privacy Controls and Cookie Solution to address all cases where a synchronization is needed:

<script type="text/javascript">
    var _iub = _iub || [];
    _iub.csConfiguration = {
        "lang": "en",
        "siteId": XXXXXX, //use your siteId
        "cookiePolicyId": YYYYYY, //use your cookiePolicyId
        "banner": {
            "position": "float-top-center",
            "acceptButtonDisplay": true,
            "customizeButtonDisplay": true
        },
        "callback": {
            "onReady": function() {
                consSyncronizer();
            },
            "onPreferenceFirstExpressed": function(preferences) {
                consSyncronizer();
            }
        }
    };
</script>

Now we’ll need two functions to address three steps:

  1. one function that fires when a page is loaded and before the Privacy Controls and Cookie Solution activates (needed in order to avoid the banner to show up if a remote consent is present for a given user). We’ll call it consPreflight.
  2. one function that fires when the Privacy Controls and Cookie Solution activates (onReady callback) and checks whether the device consent and the Consent Database consent are in sync. We’ll call it consSyncronizer.
  3. consSyncronizer will fire also when the preferences for the Privacy Controls and Cookie Solution are reopened and changed.

We’ll have to repeat these three steps at each pageview. Let’s see them in a little more detail.

1st step, consPreflight function

In order to avoid the banner to show up if a remote consent is present for a given user, this function queries the Consent Database for a subject_id (which is used to uniquely identify a user) and tries to retrieve his cookie preferences: 

  • If the subject_id is not found and the local cookie that stores the consent is not found either, the Privacy Controls and Cookie Solution is activated and the banner is shown. This is most likely the first visit of the user. 
  • If the subject_id is not found but the local cookie is present, it is pushed to the Consent Database and the returned subject_id is stored. The Privacy Controls and Cookie Solution is then activated, but the banner is not shown. This is the case for a user that gave consent before this logic has been implemented. 
  • If the subject_id is found and the local cookie is not present, the remote preferences are used to create a local consent cookie. The Privacy Controls and Cookie Solution is activated and the banner is not shown. This is the case for users that expressed a preference on one instance of the Privacy Controls and Cookie Solution (e.g. web), and then visited a second instance (e.g. mobile). 
  • Finally, if both the subject_id and the local cookie are found, nothing is done at this stage and the Privacy Controls and Cookie Solution is activated. This is the most common case for users that keep navigating the site.
function consPreflight() {
  
  // 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 Database before activating the Privacy Controls and Cookie Solution

    // Try to the fetch the Privacy Controls and 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 Database) likely exists
      // Fetch the remote consent and create a local consent from it
      // Perform a request for the given subject_id to the Consent Database
      // 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) {
        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.enableTCF) {
        // If the Privacy Controls and Cookie Solution uses the TCF...
          if (consPreferences.cookieTCFv2) {
            // ...create a cookie for the TCF...
            var cookieTcfName = 'iubeuconsent-v2';
            var cookieTcfContent = consPreferences.cookieTCFv2.value;
            setCookie(cookieTcfName, cookieTcfContent, 365);
          }
        }
      })
      .fail(function(jqXHR, textStatus, errorThrown) {
        // If the request fails, a few retries should be performed before activating the Privacy Controls and Cookie Solution
        activateCookieSolution();
      })
      .always(function() {
        // Once the request and the syncronization is finished, activate the Privacy Controls and Cookie Solution
        activateCookieSolution();
      });
    } else {
      // Local consent (cookie) found, we don't need to do any pre-configuration
      activateCookieSolution();
    }
  } else {
    // No subject_id available, so we have nothing to syncronize from
    activateCookieSolution();
  }
}
Important

For demonstration purpose only, we store the subject_id in the localStorage. A production application should bind a user and a subject_id at database level or anyway in a more reliable way than the browser localStorage.

Also, the GET requests to the Consent Database 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 to the Privacy Controls and Cookie Solution.

2nd step, consSyncronizer function

This function fires when the Privacy Controls and Cookie Solution activates (onReady callback) and checks whether the device consent and the Consent Database consent (if present, or if created in one of the previous cases) are in sync.

This is done by comparing the timestamp of the cookie with the Consent Database preferences: 

  • If the timestamps are equal, no action is performed as the two consents are synchronized. 
  • If the remote timestamp is newer than the local timestamp, the remote preferences are used to update the local preferences. 
  • If the local timestamp is newer than the remote timestamp, the local preferences are pushed to the Consent Database in order to update the subject.
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
      return;
    } else {
      // ...but local consent found. It has probably never been sent to the ConS, so do it now
      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
  // 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) {
    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();

    if (cookieUnixTime == consUnixTime) {
      // Timestamps are equal: the local and remote consents are in sync, do nothing
      return;
    } else if (cookieUnixTime > consUnixTime) {
      // Local timestamp is newer than remote consent: something was changed locally, push the updated consent 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 Privacy Controls and Cookie Solution instance and the local consent is now old, get the updated consent from Consent Database
      _iub.cs.api.storeConsent({purposes: consPreferences.cookiePurposes.value});

      if (_iub.cs.options.enableTCF) {
        // If the Privacy Controls and Cookie Solution uses the TCF...
        if (consPreferences.cookieTCFv2) {
          // ...update the cookie for the TCF...
          var cookieTcfName = 'iubeuconsent-v2';
          var cookieTcfContent = consPreferences.cookieTCFv2.value;
          setCookie(cookieTcfName, cookieTcfContent, 365);
        }
      }
    }
  })
  .fail(function(jqXHR, textStatus, errorThrown) {
    console.log("[consSyncronizer] Consent Database call failed");
  });
}

3rd step, consSyncronizer function (again)

The consSyncronizer function will fire also when the preferences for the Privacy Controls and Cookie Solution are reopened and changed. This happens when using (for example) a button with the iubenda-cs-preferences-link class that opens the preferences window.

In this case, since both step 1 and step 2 have already been performed, we can safely assume that the local consent and the remote consent are in sync and that the preference change needs to be pushed to the Consent Database.

Once you’ve implemented these steps along with other additional functions (see our CodePen demo), your Consent Database dashboard will store all the cookie consent preferences collected through the cookie banner across different devices.

See also