klaro-org / klaro-js

Klaro Privacy Manager. An open-source, privacy-friendly & compliant consent manager for your website.
https://klaro.org
Other
1.2k stars 255 forks source link

Help implementing Google Consent Mode #398

Open modelesque opened 3 years ago

modelesque commented 3 years ago

Hi,

We have implemented Google Consent Mode according to your documentation. We fire our GTM tags based on an event trigger like klaro-googleTagManager-accepted. It does fire the tag, however, the tag itself does not function properly. In the case of Google Analytics, we have no page views.

The klaro-google-analytics-accepted event fires fairly late. It fires after the page view has been generated, and also the dataLayer within the klaro-google-analytics-accepted event doesn't contain a pageView. So it does fire the tag, but it doesn't generate a pageView. I don't see my website activity in the real-time view of Google Analytics.

My full config file:

export default {
    testing: window.klaroTesting,
    default: false,
    disablePoweredBy: true,
    additionalClass: 'gdpr',
    acceptAll: true,
    hideDeclineAll: true,
    noticeAsModal: true,
    groupByPurpose: false,
    styling: {
        theme: ['light'],
    },
    translations: window.klaroTranslations,
    services: [
        {
            name: 'sessionCookies',
            purposes: ['functional'],
            default: true,
            required: true,
        },
        {
            name: 'googleTagManager',
            purposes: ['marketing'],
            default: false,
            onAccept: function(opts) {
                window.gtmIsLoaded = true;

                // we notify the tag manager about all services that were accepted. You can define
                // a custom event in GTM to load the service if consent was given.
                for (let k of Object.keys(opts.consents)) {
                    if (opts.consents[k]) {
                        dataLayer.push({'event': 'klaro-' + k + '-accepted'})
                    }
                }

                // if consent for Google Analytics was granted we enable analytics storage
                if (opts.consents[opts.vars.googleAnalyticsName || 'google-analytics']) {
                    gtag('consent', 'update', {'analytics_storage': 'granted'});
                }
                // if consent for Google Ads was granted we enable ad storage
                if (opts.consents[opts.vars.adStorageName || 'google-ads']) {
                    gtag('consent', 'update', {'ad_storage': 'granted'});
                }
            },
            onInit: function(opts) {
                window.dataLayer = window.dataLayer || [];
                window.gtmIsLoaded = null;

                window.gtag = function(){dataLayer.push(arguments)}
                gtag('consent', 'default', {'ad_storage': 'denied', 'analytics_storage': 'denied'});
                gtag('set', 'ads_data_redaction', true);
            },
            onDecline: function(opts) {
                window.gtmIsLoaded = false;

                window.gtag = function(){dataLayer.push(arguments)}
                gtag('consent', 'default', {'ad_storage': 'denied', 'analytics_storage': 'denied'})
                gtag('set', 'ads_data_redaction', true)
            },
            vars: {
                googleAnalytics: 'google-analytics'
            }
        },
        {
            // In GTM, you should define a custom event trigger named `klaro-google-analytics-accepted`
            // which should trigger the Google Analytics integration.
            name: 'google-analytics',
            purposes: ['marketing'],
            cookies: [
                /^_ga(_.*)?/ // we delete the Google Analytics cookies if the user declines its use
            ],
        }
    ],
};

Any help would greatly be appreciated!

fjahn commented 2 years ago

I stumbled upon the same problem when trying to implement this. I could not get the code to work, but I did not bother to find a fix because I did not like this approach anyways. It seemed way to complicated for such a simple problem: If users consent to a service, send an event to Google Tag Manager.

Using Google Tag Manager

Here is the implementation I settled with:

function announceConsent (consentGiven, service) {
    const name = service.name
    const consentGivenPart = consentGiven ? 'accepted' : 'rejected'
    sendEvent(`consent.${consentGivenPart}.${name}`)
}

function sendEvent (name, data = {}) {
    window.dataLayer.push({
        'event': name,
        ...data,
    })
}

window.klaroConfig = {
    version: 1,
    ...
    services: [
        {
            name: 'googleAnalytics',
            title: 'Google Analytics',
            purposes: ['analytics'],
            cookies: [
                /^_ga(_.*)?/
            ],
            callback: announceConsent,
        },
    ],
}

After that, you just need to add a trigger in Google Tag Manager that listens for the consent.googleAnalytics.accepted event and hook it up to the configuration for Google Analytics.

Using just Google Analytics without Google Tag Manager

I also want to mention that most of the time, you really do not need Google Tag Manager. You can just as easily hook up Google Analytics via Klaro directly:

window.klaroConfig = {
    version: 1,
    ...
    services: [
        {
            name: 'googleAnalytics',
            title: 'Google Analytics',
            purposes: ['analytics'],
            cookies: [
                /^_ga(_.*)?/
            ],
        },
    ],
}

In your HTML, just do:

<script
    type="text/plain"
    data-type=""
    data-name="googleAnalytics"
    data-src="https://www.googletagmanager.com/gtag/js?id=<MEASUREMENT_ID>></script>
<script>
    window.dataLayer = window.dataLayer || [];
    function gtag(){dataLayer.push(arguments);}
    gtag('js', new Date());

    gtag('config', '<MEASUREMENT_ID>');
</script>

This approach of importing Google Analytics directly is documented here.

eddiesel commented 1 year ago

Still works in 2023 – thanks @fjahn

Attention: One thing has to be adjusted, if someone uses the Google Tag Manager implementation from @fjahn.

Either use consent.accepted.googleAnalytics (instead of consent.googleAnalytics.accepted) in Google Tag Manager or change the implementation of the announceConsent function so it produces the correct name:

-    sendEvent(`consent.${consentGivenPart}.${name}`)
+    sendEvent(`consent.${name}.${consentGivenPart}`)

@fjahn Maybe you could edit your original Post?