Sandboxed JavaScript for CMP (Consent Mode v2) cannot write to dataLayer

I have set up a custom template using code from my CMP provider, which works fine for consent setting. We have had to make several additions and edits to the CMP as provided. I want to send a custom event when consent is updated to use as a trigger for certain tags, but I keep getting “‘dataLayer’ is not defined” errors. It seems that I can’t get the sandboxed javascript to talk to my dataLayer at all, as any reference to it or the window creates issues.

I assume this is an issue with the custom template limitations. I want to understand why it’s not working and how to be able to send custom events to the dataLayer in sandboxed javascript.

I have tried different methods of trying to make this work, but everything I tried results in either a ‘window is not defined’ or ‘dataLayer’ is not defined error. My provider is unwilling to help as they believe it’s a Google issue. Note: the script works fine if I remove the references to window and dataLayer and does update consent as it should. However, I need to send custom events as part of ‘updateConsentState’ too to trigger other tags.

Please see my code below:

// Initialize dataLayer
window.dataLayer = window.dataLayer || [];

// Enter your template code here.
const log = require('logToConsole');
const setDefaultConsentState = require('setDefaultConsentState');
const updateConsentState = require('updateConsentState');
const injectScript = require('injectScript');
const queryPermission = require('queryPermission');
const copyFromWindow = require('copyFromWindow');
log('data =', data);

// set default consent
setDefaultConsentState({
    'ad_storage': 'denied',
    'analytics_storage': 'denied',
    'ad_user_data': 'denied',
    'ad_personalization':'denied',
    'functionality_storage': data.functional,
    'personalization_storage': data.functional,
    'security_storage': 'granted'
});

// start of config
var config = {
    apiKey: data.apiKey,
    logConsent: true,
    product: data.product,
    optionalCookies: [
        {
            name : 'Analytics',
            label: "<strong>Analytics cookies</strong>",
            description: "<p>Analytics cookies help us to improve our website by collecting data about how you use it.</p>",
            cookies: ['_gid', '_ga*', 'nmstat', '__utma', '__utmc', '__utmz', '__utmt', '__utmb', '_hj*', 'CLID', 'SRM_B', 'uid', '_vwo*', '_gat',],
            onAccept : function(){
                updateConsentState({
                    'analytics_storage': 'granted',
                });
                // Push event to dataLayer
                window.dataLayer.push({
                    'event': 'analytics_granted',
                    'category': 'Analytics',
                    'action': 'Granted'
                });
            },
            onRevoke: function(){
                updateConsentState({
                    'analytics_storage': 'denied',
                });
            }
        },
        {
            name : 'marketing',
            label: "<strong>Marketing cookies</strong>",
            description: "<p>Marketing cookies help us show you adverts that are more relevant to you.</p>",
            cookies: ['X-AB', '_gcl*', 'uid', 'test_cookie', 'YSC', 'VISITOR_INFO1*', '_ttp', '_scid', '_scid_r', '_scid*', '_uet*', 'muc_ads', 'li_sugr', 'bcookie', 'lidc', 'personaliza*', 'MUID', 'UserMatch*', 'AnalyticsSync*', '_fbp*', '_tt_enable*', 'bscookie', 'li_gc', 'MR', 'SM', 'ANONCHK', 'MSPTC', 'IDE', 'suid', 'uid*', 'TapAd*', 'XANDR*', 'receive-cookie*', 'uuid2', '_rxuuid', 'ab', 'anHistory', 'anj', 'anProfile', 'u', 'bku', 'bkpa', '__141_cid', '__io_cid', 'A3', 'utm_*', 'NID', 'cf_clearance', '_cfuvid', '_fbc'],
            onAccept : function(){
                updateConsentState({
                    'ad_storage': 'granted',
                    'ad_user_data': 'granted',
                    'ad_personalization':'granted',
                });
                // Push event to dataLayer
                window.dataLayer.push({
                    'event': 'marketing_granted',
                    'category': 'Marketing',
                    'action': 'Granted'
                });
            },
            onRevoke: function(){
                updateConsentState({
                    'ad_storage': 'denied',
                    'ad_user_data': 'denied',
                    'ad_personalization': 'denied',
                });
            }
        }
    ],
    text: {
        title: "<div class='u-text-h4 u-font-bold u-font-serif u-mb-1'>Control your cookies</div>",
        notifyTitle: "<div class='u-text-h4 u-font-bold u-font-serif u-mb-1'>Control your cookies</div>",
        notifyText: "<p>We need some essential cookies to make this website work. We want to set other cookies to understand how you use the site and give you the best experience. If you change your mind, you can change your settings.</p>",
        acceptSettings: "Accept all",
        rejectSettings: "Reject non-essential",
        accept: "Accept all",
        reject: "Reject non-essential",
        settings: "More options",
        necessaryTitle:"<strong>Essential cookies</strong>",
        necessaryDescription:"<p>We need some essential cookies to make this website work. They help you move between pages, interact with the website and access secure areas. You can only reject essential cookies in your browser settings. Some parts of the site may not work if you do.</p>",
        closeLabel: "<span>Save and close cookie control</span>",
        notifyDescription : "<p>We need some essential cookies to make this website work. We want to set other cookies to understand how you use the site and give you the best experience.</p>",
    },
    consentCookieExpiry: 365,
    theme: 'light',
    subDomains: true,
    statement: {
        description: 'For more detailed information, please check our',
        name: 'Cookie Policy',
        url: 'https://www.mmu.ac.uk/cookie-policy',
        updated: '04/03/2024',
    },
    excludedCountries: 'all',
    position: 'left',
    layout: 'popup',
    toggleType: 'slider',
    branding: {
        'backgroundColor': '#ffffff',
        'fontColor': '#000000',
        'acceptBackground':'#ffcd00',
        'rejectBackground':'#ffffff',
        'acceptText':'#000000',
        'rejectText':'#000000',
        'removeAbout': true,
        'removeIcon': true,
        'toggleBackground':'#A9A3AD',
        'toggleText':'#ffffff',
    }
};

// end of config

const onSuccess = () => {
    const CookieControl = copyFromWindow('CookieControl');
    log(config);
    CookieControl.load(config);
    data.gtmOnSuccess();
};

const onFailure = () => {
    log("fail");
    data.gtmOnFailure();
};

injectScript('https://cc.cdn.civiccomputing.com/9/cookieControl-9.x.min.js', onSuccess, onFailure);

// Call data.gtmOnSuccess when the tag is finished.
data.gtmOnSuccess();