klaro-js icon indicating copy to clipboard operation
klaro-js copied to clipboard

Reload script add by Google Tags Manager

Open Mickaeldicurzio opened this issue 6 years ago • 7 comments

hello everybody,

I work with Klaro on project and the customer want to add scripts with google tags manager. We decided to add script with data-name allowing script by category.

GTM is allowed by Klaro too. So, all GTM script a execute after Klaro execution. I manage somehow a solution. I listen DOM changes with an mutationObserver on script and iframe and updateConsent of this category twice.

var mutationObserver = new MutationObserver(function (mutations) {
    mutations.forEach(function (mutation) {
        if (mutation.addedNodes[0] && (mutation.addedNodes[0].localName === "script" || mutation.addedNodes[0].localName === "iframe")) {
            if (mutation.addedNodes[0].dataset.name === 'cat') {
                window.klaro.getManager().updateConsent('cat', !window.klaro.getManager().getConsent('cat'))
                window.klaro.getManager().saveAndApplyConsents();
                window.klaro.getManager().updateConsent('cat',  !window.klaro.getManager().getConsent('cat'))
                window.klaro.getManager().saveAndApplyConsents();
            }
        }
    });
});
mutationObserver.observe(document.documentElement, {
    attributes: true,
    childList: true,
    subtree: true,
});

I've wonder if there's a better and more cleaner way to do.

Here is my klaro app config:

// This is a list of third-party apps that Klaro will manage for you.
    apps: [

        // The apps will appear in the modal in the same order as defined here.
        {
            name: 'google-map',
            title: 'googleMap',
            default_value: null,
            purposes: ['externaltracker'],
            description: 'ma description'
        },
        {
            name: 'iframe',
            title: 'Iframe',
            default_value: null,
            purposes: ['externaltracker'],
            description: 'my description',
        },
        {
            name: 'gtm',
            title: 'Google Tag Manager',
            default_value: null,
            purposes: ['externaltracker'],
            description: 'my description',
        },
        {
            name: 'recaptcha',
            title: 'recaptcha',
            default_value: null,
            purposes: ['externaltracker'],
            description: 'my description'
        },
        {
            name: 'cat',
            title: 'my first category',
            default_value: null,
            purposes: ['externaltracker'],
            description: 'my description',
        },
    ],

thanks for your answers !! :smile:

Mickaeldicurzio avatar Oct 21 '19 09:10 Mickaeldicurzio

Hi, is this a general question or is something not working? If something is not working could you describe how to reproduce the issue?

I'm not familiar with Google Tags Manager, but maybe someone else reading this has a good solution for you. :)

What is the observer listing to and when is that action toggling the consent management in Klaro? What does the abbreviation(?) cat stand for? Category? 🐱

jaller94 avatar Oct 25 '19 16:10 jaller94

Are you trying to toggle the scripts which are added by Google Tag Manager? So you changed the tags in GTM too? Which of the tags come from GTM? Interesting solution, do not really have a better idea.

amenk avatar Apr 02 '20 13:04 amenk

ping @Mickaeldicurzio

amenk avatar May 05 '20 12:05 amenk

update :

var mutationObserver = new MutationObserver(function (mutations) {
    mutations.forEach(function (mutation) {
        if (mutation.addedNodes[0] && (mutation.addedNodes[0].localName === "script" || mutation.addedNodes[0].localName === "iframe")) {
            // console.log(mutation.addedNodes[0].dataset.name);
            let categoryName = mutation.addedNodes[0].dataset.name;
            let webpack = window.klaro.getManager();
            if (typeof(categoryName) !== 'undefined' && categoryName.includes('lazy-')) {
                webpack.updateConsent(categoryName, !window.klaro.getManager().getConsent(categoryName))
                webpack.saveAndApplyConsents();
                webpack.updateConsent(categoryName, !window.klaro.getManager().getConsent(categoryName))
                webpack.saveAndApplyConsents();
            }
        }
    });
});


// Starts listening for changes in the root HTML element of the page.
mutationObserver.observe(document.documentElement, {
    childList: true,
    subtree: true,
});

Mickaeldicurzio avatar May 07 '20 13:05 Mickaeldicurzio

ping @amenk

We have put this script in order to listen dom element injected by GTM. If a script contain an data-name attribute started by "lazy-", we will inject it to Klaro

exemple:

<script data-type="text/javascript" data-name="lazy-pub" type="opt-in" data-src="somescript.js" async="true"></script>

but, unfortunately, we have to update consent 2 time for make it works.

webpack.updateConsent(categoryName, !window.klaro.getManager().getConsent(categoryName))
webpack.saveAndApplyConsents();
webpack.updateConsent(categoryName, !window.klaro.getManager().getConsent(categoryName))
webpack.saveAndApplyConsents();

Mickaeldicurzio avatar May 07 '20 13:05 Mickaeldicurzio

well, I will make an Update ( for everyone who have the same issues ) Observers work but it can appear to be a bas solution. In fact, it can create infinte loop on prod envs.

I recommend now to use dataLayer from GTM : https://developers.google.com/tag-manager/devguide and push event in klaro calback for activate gtm tags

callback: function(consent, app) {
            if (consent) {
                dataLayer.push({'event': 'gtm-event-1'});
            }
        }

Mickaeldicurzio avatar Jan 27 '21 11:01 Mickaeldicurzio

@Mickaeldicurzio My problem is that I have a lot of fields to consent.. (google_analytics, facebok, etc) and every time config.js loads (which is every page) the call back runs and push all the consents one by one in data layer... Did you know a way to send all the consents in one push? Like an array or something else?

this is my func so far, I would like to send only once with all data, it this possible, can you help me? Thanks a lot!

  callback: function (consent, service) {
    dataLayer.push({
      event: "consent",
      tool: service.name,
      consent: consent,
    });
  },
};

caioricciuti avatar Jan 29 '21 16:01 caioricciuti