Home Custom Code Tag Templates An Easy Consent Tag Template That Actually Works

An Easy Consent Tag Template That Actually Works

Google published step-by-step documentation on creating a custom tag template in Google Tag Manager (GTM) for their consent mode. Web developers and analysts can manage how the user’s selected privacy permissions affect their tags and third-party pixels.

Sounds great! Except when I tried to implement it for a client’s website, it didn’t work. Thankfully, I figured out the issues and successfully fixed them. I published a revised version of Google’s tag template in a public GitHub repository so other analysts could skip the hassle. You’re welcome 😉

The Creepy Crawly Template Bugs

If you’re as nosy as I am and want to know what all the fuss is about, excellent! Strap in.

via GIPHY

Data Type Mismatch

Google’s template code assumes that the cookie with all the user’s privacy preferences will be an object data type and uses the expected keys to retrieve information.

/**
 * Called when consent changes. Assumes that consent object contains keys which
 * directly correspond to Google consent types.
*/
const onUserConsent = (consent) => {
  const consentModeStates = {
    ad_storage: consent['adConsentGranted'] ? 'granted' : 'denied',
    analytics_storage: consent['analyticsConsentGranted'] ? 'granted' :
                                                            'denied',
    functionality_storage: consent['functionalityConsentGranted'] ? 'granted' :
                                                                    'denied',
    personalization_storage:
        consent['personalizationConsentGranted'] ? 'granted' : 'denied',
    security_storage: consent['securityConsentGranted'] ? 'granted' : 'denied',
  };
  updateConsentState(consentModeStates);
};

Cookies, however, can only return strings. Even if your web developer does what they can to give you an object, it’ll come as a string, and Google won’t have any of it.

On the surface, it would seem evident that Google can figure it out. It’s technically a string, but it’s just an in-line object. The keys should still work just fine. For whatever reason, GTM refuses to cooperate consistently, though.

The solution to my problems was to parse the string and manually assign each permission state to its appropriate key.

// Parse consent settings to transform from string to object.
function parseSettings (x) {
  const permissions = x.toString().split(',').map(function (x) {return x.split(':')[1];});
  return {
    ad_storage: permissions[0] ? "granted" : "denied",
    analytics_storage: permissions[1] ? "granted" : "denied",
    functionality_storage: permissions[2] ? "granted" : "denied",
    personalization_storage: permissions[3] ? "granted" : "denied",
    security_storage: permissions[4] ? "granted" : "gdenied",
  };
}

Sandboxed JavaScript Limitations

Getting Google to see this not-a-string as an object was way more complicated than it should’ve been. Typically, a single line of code utilizing the Object.entries() and Array.map() methods would chop the string up more cleanly than the script I wrote. No such luck here, I’m afraid.

GTM’s sandboxed JavaScript does not support arrow functions or array destructuring. That makes the standard Object.entries(grantConsent).map(([key, value]) => ({key, value})) solution a no-go from the get-go. Thankfully, I circumvented these features with the parseSettings function depicted above.

User Preferences Overwritten on Page Load

While parseSettings successfully updated GTM with newly selected permissions, it wasn’t enough to ensure they persisted across page loads. My client had the issue of the default settings overwriting the user’s settings on each new page load.

While I’m not fully sure, I believe this bit of Google’s script is the culprit.

// Check if cookie is set and has values that correspond to Google consent
// types. If it does, run onUserConsent().
const settings = getCookieValues(COOKIE_NAME);
if (typeof settings !== 'undefined') {
  onUserConsent(settings);
}

I can’t explain why, but the if statement always returned “false.” Simply removing “typeof” made it work again. To try and spare the site of an unnecessary API call, I reworked the if statement so setDefaultState only fired when the user hadn’t customized their preferences.

// Check if cookie is set and has values that correspond to Google consent
// types. If it does, run onUserConsent().
const userSettings = getCookieValues(COOKIE_NAME);
if (userSettings !== 'undefined') {
  const settings = parseSettings (userSettings);
  updateConsentState(settings);
} else {
  // Otherwise, set default consent state(s)
  data.defaultSettings.forEach(settings => {
  const defaultData = parseCommandData(settings);
  defaultData.wait_for_update = 500;
  setDefaultConsentState(defaultData);
  });
}

It didn’t work.

Incorrect Setup Instructions

The last thing Google messed up (that I noticed and remembered, at least) Google’s instructions on how to set up the custom tag template need to be corrected. For example, they say to grant write permissions for the ad_storage and analytics_storage consent states even though the code also writes to the functionality_storage, personalizatio_storage, and security_storage consent states. For a detailed explanation of how to correctly set up the tag template’s non-code parts, look at my repository’s ReadMe.

Areas for Further Solution Improvement

While my version of the tag template code at least gets the job done, there are still a couple of things with which I could use help. Frankly, I don’t have the time to go past “functioning” and into the realm of “optimized” for this little project.

Regional Default Settings

Google’s original template claimed to support different default settings for individual regions. My changes should not impact that, but I didn’t confirm regionality worked before editing. Also, my client doesn’t care about regions, so I can’t test my version now. If you can test this, I’d super appreciate it! If you catch anything, open an issue in the GitHub repository, or contact me here.

Double Consent API Calls on Page Load

As mentioned, the default consent state is sent on every page load whether or not the user updated their preferences. My edits don’t change this – they only update the settings with the user’s selection to overwrite the default. I prefer to stop the redundancy, so if you come up with a solution, please let me know!

Until then, happy coding, and stay awesome!

PS: AIOSEO says I need more pictures, so please enjoy this picture of Buddy and Q-Tip.

The fluffiest kittos around

One Response

Leave a Reply

Your email address will not be published. Required fields are marked *

Have a GA/GTM project? I’ll help!

Recent Ramblings