The consent dialog

The General Data Protection Regulation, or GDPR in short is among us since 25 may 2018. This EU regulation handles on how we as developers, website owners, ... need to deal with the privacy of individuals.

Because of this the "old" cookiebar was not sufficient anymore. With the 5.9.0 release we introduced "the consent dialog". This gives you the ability to build your site fully compliant with GDPR.

The consent dialog will be shown to your visitors, in the dialog they can select their privacy preferences, it will look like below in the default Fork theme:

The consent dialog in the Fork Theme

The preferences are stored in functional cookies so they are remembered.

IMPORTANT: it is still your responsibility to respect the visitors choices. Fork gives you the ability to do so.

Configuration of the consent dialog

In the backend under "Settings" there is a new block which allows you to define different privacy levels. You can add as many as needed. A visitor can agree to each level separately.

Enable the consent dialog and configure the levels

For each level you need to add 2 translations, these translations will be used in the consent dialog.

  • Title, this is used as the label for the checkbox
  • Text, this is used as a description for the level. As GDPR states a user needs to make an informed discision, so in the description you can describe what the level means an how you will use the visitors agreement.

The reference code/name of the translation uses the level like explained below:

{{ ('msg.PrivacyConsentLevel' ~ level|ucfirst ~ 'Title')|trans|raw }}
{{ ('msg.PrivacyConsentLevel' ~ level|ucfirst ~ 'Text')|trans|raw }}

So for instance if you define the level "statistics" you will need to add 2 translations with the names:

  • PrivacyConsentLevelStatisticsTitle
  • PrivacyConsentLevelStatisticsText

Remark: If you change the levels the consent dialog will be shown again to all visitors. Previous choices will not be ticked.

There is one level that is always available: functional, this is always allowed. The user can not change this. It is added as it is a good practice to explain your visitor what you store in these cookies.


Retrieving choices in JavaScript

The choices of the visitor are available in jsData in the privacyConsent-object.

  • possibleLevels, contains all the levels that are defined thru the CMS.
  • levelsHash, this is the hash that is used to determine if the levels are changed.
  • visitorChoices, this contains the choice a user has made per level. The default is false.

Retrieving choices in PHP

A new service is available as ForkCMS\Privacy\ConsentDialog. This service exposes some methods that you can use:

  • getLevels(bool $includeFunctional = false), this will return all the defined levels.
  • getVisitorChoices(): returns an array with the users chosen preferences
  • hasAgreedTo(string $level): returns a boolean if the user has agreed to a given level. Returns false per default, also for non existing levels.

So for example if you want to do personalations if the user has agreed to the personalisation-level, you can use the snippet below:

if ($this->getContainer()->get(ForkCMS\Privacy\ConsentDialog::class)->hasAgreedTo('personalisation')) {
    ... your code ...

Anonymize IP

Google Analytics has a feature called anonymizeIp. If you use our Google Analytics or Google Tag Manager integration we use the anonymizeIp feature by default.

In this case you need to add a privacy level with the name statistics. If you do so, and the visitor agrees to it we will disable the IP anonymization.

Warning: In Belgium this is not correct. The DPA decided that anonymizeIp is not enough, therefor you should ask permission before tracking! See below how you can achieve this.

Google Tag Manager

If you use Google Tag Manager it is completely up to you to adhere the visitors preferences. Below is explained on how it can be configured.

Create a variables

  • Open Variables
  • Click "New" next to "User-Defined Variables"
  • Name it "Privacy Consent - DataLayer - Level XXX", eg: Privacy Consent - DataLayer - Level statistics
  • Choose "Data Layer Variable" for the type
  • Use "privacyConsentLevelXXXAgreed" as the value for "Data Layer Variable Name", replace XXX with the ucfirst version of you level name
  • Enable "Set Default Value", and set the Default Value to "false"

Example configuration for data layer variables

Do this for all the levels you defined.

Create triggers

  • Open Triggers
  • Click "New"
  • Name it "Privacy Consent - Check - Level XXX not allowed", eg: Privacy Consent - Check - Level statistics not allowed
  • Choose "Custom event" for the Trigger Type
  • Use ".*" as Event name, and tick "Use regex matching"
  • Select "Some custom Events"
  • Select the relevant variable, something like DataLayer - Privacy Consent - Level XXX"
  • Choose "Equals" as the condition and "false" as the value

Trigger example configuration

  • Click "New"
  • Name it "Privacy Consent - Event - Level XXX - Agreed", eg: Privacy Consent - Event - Level statistics - Agreed
  • Choose "Custom event" for the Trigger Type
  • Use "privacyConsentLevelXXXAgreed" as Event name, replace XXX with the ucfirst name of your level name
  • Select "All Custom Events"

Event trigger configuration

Repeat these steps for each level you have defined.

Load a tag only when it is allowed

  • Open the tag you want to configure. For instance Hotjar
  • Edit the triggers
  • Add "Privacy Consent - Event - Level XXX - Agreed" on the Firing Triggers. This will add the tag if the user agrees.
  • Add "Privacy Consent - Check - Level XXX not allowed" on the Exceptions. This will prevent the tag from loading when the user did not agree.

Hotjar example tag configuration

By adding the exception the Tag won't be fired. This is the case when a visitor has not agreed to anything. In that case the consent dialog is shown. When the visitor clicks "Save my preferences", we will fire an event per agreed level: privacyConsentLevelXXXAgreed. This will fire the tag, as it is configured as a Firing trigger.

If the visitor visits another page the exception won't be triggered as the variable is true. So the tag will be fired by the "All Pages" trigger.