{
    "exportFormatVersion": 2,
    "exportTime": "2026-06-15 19:12:00",
    "containerVersion": {
        "path": "accounts/6268264869/containers/255515747/versions/0",
        "accountId": "6268264869",
        "containerId": "255515747",
        "containerVersionId": "0",
        "container": {
            "path": "accounts/6268264869/containers/255515747",
            "accountId": "6268264869",
            "containerId": "255515747",
            "name": "Stape - GoHighLevel - Web",
            "publicId": "GTM-T6GTJF67",
            "usageContext": [
                "WEB"
            ],
            "fingerprint": "1781524868636",
            "tagManagerUrl": "https://tagmanager.google.com/#/container/accounts/6268264869/containers/255515747/workspaces?apiLink=container",
            "features": {
                "supportUserPermissions": true,
                "supportEnvironments": true,
                "supportWorkspaces": true,
                "supportGtagConfigs": false,
                "supportBuiltInVariables": true,
                "supportClients": false,
                "supportFolders": true,
                "supportTags": true,
                "supportTemplates": true,
                "supportTriggers": true,
                "supportVariables": true,
                "supportVersions": true,
                "supportZones": true,
                "supportTransformations": false
            },
            "tagIds": [
                "GTM-T6GTJF67"
            ]
        },
        "tag": [
            {
                "accountId": "6268264869",
                "containerId": "255515747",
                "tagId": "3",
                "name": "Listener GoHighLevel",
                "type": "html",
                "parameter": [
                    {
                        "type": "TEMPLATE",
                        "key": "html",
                        "value": "<script>\n(function() {\n  var inputData = {};\n  window.addEventListener('message', function (event) {\n    if(Object.prototype.toString.call(event.data) === '[object Array]') {\n        var inputJSON = event.data[2];\n\n        if(inputJSON && inputJSON.includes('full_address') && inputJSON.includes('customer_id') && inputJSON.includes('full_name') && inputJSON.includes('email')) {\n            var inputObject = JSON.parse(inputJSON);\n            inputData = inputObject\n            dataLayer.push({\n                event: 'generate_lead',\n                inputs: inputObject\n            });\n        }\n\n        if(event.data[0] === 'msgsndr-booking-complete') {\n            dataLayer.push({\n                event: 'schedule',\n                inputs: inputData\n            });\n        }\n    }\n  });\n})();\n</script>"
                    },
                    {
                        "type": "BOOLEAN",
                        "key": "supportDocumentWrite",
                        "value": "false"
                    }
                ],
                "fingerprint": "1781524941218",
                "firingTriggerId": [
                    "2147479553"
                ],
                "tagFiringOption": "ONCE_PER_EVENT",
                "monitoringMetadata": {
                    "type": "MAP"
                },
                "consentSettings": {
                    "consentStatus": "NOT_SET"
                }
            },
            {
                "accountId": "6268264869",
                "containerId": "255515747",
                "tagId": "11",
                "name": "GA4 - Etiqueta de configuración",
                "type": "googtag",
                "parameter": [
                    {
                        "type": "TEMPLATE",
                        "key": "tagId",
                        "value": "{{Const - GA4 ID fuente de datos}}"
                    },
                    {
                        "type": "TEMPLATE",
                        "key": "eventSettingsVariable",
                        "value": "{{GA4 eventos compartidos}}"
                    }
                ],
                "fingerprint": "1781529320455",
                "firingTriggerId": [
                    "2147479573"
                ],
                "tagFiringOption": "ONCE_PER_EVENT",
                "monitoringMetadata": {
                    "type": "MAP"
                },
                "consentSettings": {
                    "consentStatus": "NOT_SET"
                }
            },
            {
                "accountId": "6268264869",
                "containerId": "255515747",
                "tagId": "13",
                "name": "FB - Pixel",
                "type": "cvt_KFNBV",
                "parameter": [
                    {
                        "type": "BOOLEAN",
                        "key": "disablePushState",
                        "value": "false"
                    },
                    {
                        "type": "TEMPLATE",
                        "key": "eventId",
                        "value": "{{ID de evento}}"
                    },
                    {
                        "type": "TEMPLATE",
                        "key": "eventNameStandard",
                        "value": "PageView"
                    },
                    {
                        "type": "BOOLEAN",
                        "key": "dataLayerEventPush",
                        "value": "false"
                    },
                    {
                        "type": "TEMPLATE",
                        "key": "pixelIds",
                        "value": "{{Const - FB Pixel ID}}"
                    },
                    {
                        "type": "BOOLEAN",
                        "key": "objectPropertiesFromVariable",
                        "value": "false"
                    },
                    {
                        "type": "BOOLEAN",
                        "key": "consent",
                        "value": "true"
                    },
                    {
                        "type": "BOOLEAN",
                        "key": "enableDataLayerMapping",
                        "value": "false"
                    },
                    {
                        "type": "TEMPLATE",
                        "key": "inheritEventName",
                        "value": "override"
                    },
                    {
                        "type": "BOOLEAN",
                        "key": "disableAutoConfig",
                        "value": "false"
                    },
                    {
                        "type": "BOOLEAN",
                        "key": "enableConsentMode",
                        "value": "false"
                    },
                    {
                        "type": "BOOLEAN",
                        "key": "enableParamBuilderSdk",
                        "value": "true"
                    },
                    {
                        "type": "BOOLEAN",
                        "key": "enableEdvancedMatching",
                        "value": "false"
                    },
                    {
                        "type": "BOOLEAN",
                        "key": "dpoLDU",
                        "value": "false"
                    },
                    {
                        "type": "TEMPLATE",
                        "key": "eventName",
                        "value": "standard"
                    }
                ],
                "fingerprint": "1781525500427",
                "firingTriggerId": [
                    "2147479573"
                ],
                "tagFiringOption": "ONCE_PER_EVENT",
                "monitoringMetadata": {
                    "type": "MAP"
                },
                "consentSettings": {
                    "consentStatus": "NOT_SET"
                }
            },
            {
                "accountId": "6268264869",
                "containerId": "255515747",
                "tagId": "14",
                "name": "TikTok - Pixel",
                "type": "cvt_KF8K9",
                "parameter": [
                    {
                        "type": "BOOLEAN",
                        "key": "eventParametersFromVariable",
                        "value": "false"
                    },
                    {
                        "type": "TEMPLATE",
                        "key": "eventId",
                        "value": "{{ID de evento}}"
                    },
                    {
                        "type": "TEMPLATE",
                        "key": "eventNameSetupMethod",
                        "value": "override"
                    },
                    {
                        "type": "TEMPLATE",
                        "key": "eventNameStandard",
                        "value": "Pageview"
                    },
                    {
                        "type": "BOOLEAN",
                        "key": "enableLDU",
                        "value": "false"
                    },
                    {
                        "type": "BOOLEAN",
                        "key": "additionalEventParametersFromVariable",
                        "value": "false"
                    },
                    {
                        "type": "BOOLEAN",
                        "key": "disableHistoryObserver",
                        "value": "false"
                    },
                    {
                        "type": "TEMPLATE",
                        "key": "pixelIds",
                        "value": "{{Const - TikTok Pixel ID}}"
                    },
                    {
                        "type": "BOOLEAN",
                        "key": "enableGoogleConsentMode",
                        "value": "false"
                    },
                    {
                        "type": "BOOLEAN",
                        "key": "enableDataLayerMapping",
                        "value": "false"
                    },
                    {
                        "type": "BOOLEAN",
                        "key": "pushEventIdToDataLayer",
                        "value": "false"
                    },
                    {
                        "type": "TEMPLATE",
                        "key": "eventName",
                        "value": "standard"
                    },
                    {
                        "type": "BOOLEAN",
                        "key": "enableAdvancedMatching",
                        "value": "false"
                    },
                    {
                        "type": "TEMPLATE",
                        "key": "consentOptMode",
                        "value": "optout"
                    }
                ],
                "fingerprint": "1781525829228",
                "firingTriggerId": [
                    "2147479573"
                ],
                "tagFiringOption": "ONCE_PER_EVENT",
                "monitoringMetadata": {
                    "type": "MAP"
                },
                "consentSettings": {
                    "consentStatus": "NOT_SET"
                }
            },
            {
                "accountId": "6268264869",
                "containerId": "255515747",
                "tagId": "17",
                "name": "Data Tag - PageView",
                "type": "cvt_MBTSV",
                "parameter": [
                    {
                        "type": "BOOLEAN",
                        "key": "add_data_layer",
                        "value": "true"
                    },
                    {
                        "type": "TEMPLATE",
                        "key": "request_type",
                        "value": "auto"
                    },
                    {
                        "type": "BOOLEAN",
                        "key": "add_consent_state",
                        "value": "false"
                    },
                    {
                        "type": "BOOLEAN",
                        "key": "dataLayerEventPush",
                        "value": "false"
                    },
                    {
                        "type": "BOOLEAN",
                        "key": "richsstsse",
                        "value": "false"
                    },
                    {
                        "type": "TEMPLATE",
                        "key": "data_tag_load_script_url",
                        "value": "https://stapecdn.com/dtag/v9.js"
                    },
                    {
                        "type": "BOOLEAN",
                        "key": "add_common_cookie",
                        "value": "true"
                    },
                    {
                        "type": "BOOLEAN",
                        "key": "addGaParameters",
                        "value": "false"
                    },
                    {
                        "type": "TEMPLATE",
                        "key": "protocol_version",
                        "value": "2"
                    },
                    {
                        "type": "TEMPLATE",
                        "key": "event_type",
                        "value": "standard"
                    },
                    {
                        "type": "TEMPLATE",
                        "key": "event_name_standard",
                        "value": "page_view"
                    },
                    {
                        "type": "BOOLEAN",
                        "key": "add_data_layer_use_own_data_model",
                        "value": "true"
                    },
                    {
                        "type": "TEMPLATE",
                        "key": "gtm_server_domain",
                        "value": "{{Const - URL servidor}}"
                    },
                    {
                        "type": "TEMPLATE",
                        "key": "request_path",
                        "value": "/data"
                    },
                    {
                        "type": "BOOLEAN",
                        "key": "add_common",
                        "value": "true"
                    },
                    {
                        "type": "BOOLEAN",
                        "key": "useFetchInsteadOfXHR",
                        "value": "true"
                    },
                    {
                        "type": "LIST",
                        "key": "custom_data",
                        "list": [
                            {
                                "type": "MAP",
                                "map": [
                                    {
                                        "type": "TEMPLATE",
                                        "key": "name",
                                        "value": "event_id"
                                    },
                                    {
                                        "type": "TEMPLATE",
                                        "key": "value",
                                        "value": "{{ID de evento}}"
                                    },
                                    {
                                        "type": "TEMPLATE",
                                        "key": "transformation",
                                        "value": "none"
                                    },
                                    {
                                        "type": "TEMPLATE",
                                        "key": "store",
                                        "value": "none"
                                    }
                                ]
                            }
                        ]
                    }
                ],
                "fingerprint": "1781529909104",
                "firingTriggerId": [
                    "2147479573"
                ],
                "tagFiringOption": "ONCE_PER_EVENT",
                "monitoringMetadata": {
                    "type": "MAP"
                },
                "consentSettings": {
                    "consentStatus": "NOT_SET"
                }
            },
            {
                "accountId": "6268264869",
                "containerId": "255515747",
                "tagId": "21",
                "name": "FB - Lead y Agenda",
                "type": "cvt_KFNBV",
                "parameter": [
                    {
                        "type": "BOOLEAN",
                        "key": "disablePushState",
                        "value": "false"
                    },
                    {
                        "type": "TEMPLATE",
                        "key": "eventId",
                        "value": "{{ID de evento}}"
                    },
                    {
                        "type": "BOOLEAN",
                        "key": "dataLayerEventPush",
                        "value": "false"
                    },
                    {
                        "type": "TEMPLATE",
                        "key": "pixelIds",
                        "value": "{{Const - FB Pixel ID}}"
                    },
                    {
                        "type": "BOOLEAN",
                        "key": "objectPropertiesFromVariable",
                        "value": "false"
                    },
                    {
                        "type": "BOOLEAN",
                        "key": "consent",
                        "value": "true"
                    },
                    {
                        "type": "BOOLEAN",
                        "key": "enableDataLayerMapping",
                        "value": "true"
                    },
                    {
                        "type": "TEMPLATE",
                        "key": "inheritEventName",
                        "value": "inherit"
                    },
                    {
                        "type": "BOOLEAN",
                        "key": "disableAutoConfig",
                        "value": "false"
                    },
                    {
                        "type": "BOOLEAN",
                        "key": "runInitOnce",
                        "value": "false"
                    },
                    {
                        "type": "BOOLEAN",
                        "key": "enableConsentMode",
                        "value": "false"
                    },
                    {
                        "type": "BOOLEAN",
                        "key": "enableParamBuilderSdk",
                        "value": "true"
                    },
                    {
                        "type": "BOOLEAN",
                        "key": "enableCurrentDataLayerOnly",
                        "value": "false"
                    },
                    {
                        "type": "BOOLEAN",
                        "key": "enableEdvancedMatching",
                        "value": "true"
                    },
                    {
                        "type": "BOOLEAN",
                        "key": "dpoLDU",
                        "value": "false"
                    },
                    {
                        "type": "BOOLEAN",
                        "key": "userDataFromVariable",
                        "value": "false"
                    },
                    {
                        "type": "BOOLEAN",
                        "key": "enableEventEnhancement",
                        "value": "false"
                    }
                ],
                "fingerprint": "1781530860868",
                "firingTriggerId": [
                    "19",
                    "20"
                ],
                "tagFiringOption": "ONCE_PER_EVENT",
                "monitoringMetadata": {
                    "type": "MAP"
                },
                "consentSettings": {
                    "consentStatus": "NOT_SET"
                }
            },
            {
                "accountId": "6268264869",
                "containerId": "255515747",
                "tagId": "22",
                "name": "TikTok - Lead",
                "type": "cvt_KF8K9",
                "parameter": [
                    {
                        "type": "BOOLEAN",
                        "key": "eventParametersFromVariable",
                        "value": "false"
                    },
                    {
                        "type": "TEMPLATE",
                        "key": "eventId",
                        "value": "{{ID de evento}}"
                    },
                    {
                        "type": "TEMPLATE",
                        "key": "eventNameSetupMethod",
                        "value": "inherit"
                    },
                    {
                        "type": "BOOLEAN",
                        "key": "enableLDU",
                        "value": "false"
                    },
                    {
                        "type": "BOOLEAN",
                        "key": "additionalEventParametersFromVariable",
                        "value": "false"
                    },
                    {
                        "type": "BOOLEAN",
                        "key": "disableHistoryObserver",
                        "value": "false"
                    },
                    {
                        "type": "TEMPLATE",
                        "key": "pixelIds",
                        "value": "{{Const - TikTok Pixel ID}}"
                    },
                    {
                        "type": "BOOLEAN",
                        "key": "enableGoogleConsentMode",
                        "value": "false"
                    },
                    {
                        "type": "BOOLEAN",
                        "key": "enableEventUserDataEnhancement",
                        "value": "false"
                    },
                    {
                        "type": "BOOLEAN",
                        "key": "enableDataLayerMapping",
                        "value": "true"
                    },
                    {
                        "type": "BOOLEAN",
                        "key": "pushEventIdToDataLayer",
                        "value": "false"
                    },
                    {
                        "type": "BOOLEAN",
                        "key": "enableMostRecentDataLayerEventOnly",
                        "value": "false"
                    },
                    {
                        "type": "BOOLEAN",
                        "key": "userDataFromVariable",
                        "value": "false"
                    },
                    {
                        "type": "BOOLEAN",
                        "key": "enableAdvancedMatching",
                        "value": "true"
                    },
                    {
                        "type": "TEMPLATE",
                        "key": "consentOptMode",
                        "value": "optout"
                    }
                ],
                "fingerprint": "1781529561810",
                "firingTriggerId": [
                    "20",
                    "19"
                ],
                "tagFiringOption": "ONCE_PER_EVENT",
                "monitoringMetadata": {
                    "type": "MAP"
                },
                "consentSettings": {
                    "consentStatus": "NOT_SET"
                }
            },
            {
                "accountId": "6268264869",
                "containerId": "255515747",
                "tagId": "27",
                "name": "Data Tag - Lead y Agenda",
                "type": "cvt_MBTSV",
                "parameter": [
                    {
                        "type": "BOOLEAN",
                        "key": "add_data_layer",
                        "value": "true"
                    },
                    {
                        "type": "TEMPLATE",
                        "key": "event_name_custom",
                        "value": "{{Event}}"
                    },
                    {
                        "type": "TEMPLATE",
                        "key": "request_type",
                        "value": "auto"
                    },
                    {
                        "type": "BOOLEAN",
                        "key": "add_consent_state",
                        "value": "false"
                    },
                    {
                        "type": "BOOLEAN",
                        "key": "dataLayerEventPush",
                        "value": "false"
                    },
                    {
                        "type": "BOOLEAN",
                        "key": "richsstsse",
                        "value": "false"
                    },
                    {
                        "type": "TEMPLATE",
                        "key": "data_tag_load_script_url",
                        "value": "https://stapecdn.com/dtag/v9.js"
                    },
                    {
                        "type": "BOOLEAN",
                        "key": "add_common_cookie",
                        "value": "true"
                    },
                    {
                        "type": "LIST",
                        "key": "user_data",
                        "list": [
                            {
                                "type": "MAP",
                                "map": [
                                    {
                                        "type": "TEMPLATE",
                                        "key": "name",
                                        "value": "email_address"
                                    },
                                    {
                                        "type": "TEMPLATE",
                                        "key": "value",
                                        "value": "{{Usuario - Email}}"
                                    },
                                    {
                                        "type": "TEMPLATE",
                                        "key": "transformation",
                                        "value": "none"
                                    },
                                    {
                                        "type": "TEMPLATE",
                                        "key": "store",
                                        "value": "none"
                                    }
                                ]
                            },
                            {
                                "type": "MAP",
                                "map": [
                                    {
                                        "type": "TEMPLATE",
                                        "key": "name",
                                        "value": "first_name"
                                    },
                                    {
                                        "type": "TEMPLATE",
                                        "key": "value",
                                        "value": "{{Usuario - Nombre}}"
                                    },
                                    {
                                        "type": "TEMPLATE",
                                        "key": "transformation",
                                        "value": "none"
                                    },
                                    {
                                        "type": "TEMPLATE",
                                        "key": "store",
                                        "value": "none"
                                    }
                                ]
                            },
                            {
                                "type": "MAP",
                                "map": [
                                    {
                                        "type": "TEMPLATE",
                                        "key": "name",
                                        "value": "last_name"
                                    },
                                    {
                                        "type": "TEMPLATE",
                                        "key": "value",
                                        "value": "{{Usuario - Apellido}}"
                                    },
                                    {
                                        "type": "TEMPLATE",
                                        "key": "transformation",
                                        "value": "none"
                                    },
                                    {
                                        "type": "TEMPLATE",
                                        "key": "store",
                                        "value": "none"
                                    }
                                ]
                            },
                            {
                                "type": "MAP",
                                "map": [
                                    {
                                        "type": "TEMPLATE",
                                        "key": "name",
                                        "value": "phone_number"
                                    },
                                    {
                                        "type": "TEMPLATE",
                                        "key": "value",
                                        "value": "{{Usuario - Teléfono}}"
                                    },
                                    {
                                        "type": "TEMPLATE",
                                        "key": "transformation",
                                        "value": "none"
                                    },
                                    {
                                        "type": "TEMPLATE",
                                        "key": "store",
                                        "value": "none"
                                    }
                                ]
                            }
                        ]
                    },
                    {
                        "type": "BOOLEAN",
                        "key": "addGaParameters",
                        "value": "false"
                    },
                    {
                        "type": "TEMPLATE",
                        "key": "protocol_version",
                        "value": "2"
                    },
                    {
                        "type": "TEMPLATE",
                        "key": "event_type",
                        "value": "custom"
                    },
                    {
                        "type": "BOOLEAN",
                        "key": "add_data_layer_use_own_data_model",
                        "value": "true"
                    },
                    {
                        "type": "TEMPLATE",
                        "key": "gtm_server_domain",
                        "value": "{{Const - URL servidor}}"
                    },
                    {
                        "type": "TEMPLATE",
                        "key": "request_path",
                        "value": "/data"
                    },
                    {
                        "type": "BOOLEAN",
                        "key": "add_common",
                        "value": "true"
                    },
                    {
                        "type": "BOOLEAN",
                        "key": "useFetchInsteadOfXHR",
                        "value": "true"
                    },
                    {
                        "type": "LIST",
                        "key": "custom_data",
                        "list": [
                            {
                                "type": "MAP",
                                "map": [
                                    {
                                        "type": "TEMPLATE",
                                        "key": "name",
                                        "value": "event_id"
                                    },
                                    {
                                        "type": "TEMPLATE",
                                        "key": "value",
                                        "value": "{{ID de evento}}"
                                    },
                                    {
                                        "type": "TEMPLATE",
                                        "key": "transformation",
                                        "value": "none"
                                    },
                                    {
                                        "type": "TEMPLATE",
                                        "key": "store",
                                        "value": "none"
                                    }
                                ]
                            }
                        ]
                    }
                ],
                "fingerprint": "1781530848661",
                "firingTriggerId": [
                    "19",
                    "20"
                ],
                "tagFiringOption": "ONCE_PER_EVENT",
                "monitoringMetadata": {
                    "type": "MAP"
                },
                "consentSettings": {
                    "consentStatus": "NOT_SET"
                }
            },
            {
                "accountId": "6268264869",
                "containerId": "255515747",
                "tagId": "28",
                "name": "GA4 - Lead y Agenda",
                "type": "gaawe",
                "parameter": [
                    {
                        "type": "BOOLEAN",
                        "key": "sendEcommerceData",
                        "value": "false"
                    },
                    {
                        "type": "TEMPLATE",
                        "key": "eventName",
                        "value": "{{Event}}"
                    },
                    {
                        "type": "TEMPLATE",
                        "key": "measurementIdOverride",
                        "value": "{{Const - GA4 ID fuente de datos}}"
                    },
                    {
                        "type": "TEMPLATE",
                        "key": "eventSettingsVariable",
                        "value": "{{GA4 eventos compartidos}}"
                    }
                ],
                "fingerprint": "1781530833551",
                "firingTriggerId": [
                    "20",
                    "19"
                ],
                "tagFiringOption": "ONCE_PER_EVENT",
                "monitoringMetadata": {
                    "type": "MAP"
                },
                "consentSettings": {
                    "consentStatus": "NOT_SET"
                }
            }
        ],
        "trigger": [
            {
                "accountId": "6268264869",
                "containerId": "255515747",
                "triggerId": "19",
                "name": "generate_lead",
                "type": "CUSTOM_EVENT",
                "customEventFilter": [
                    {
                        "type": "EQUALS",
                        "parameter": [
                            {
                                "type": "TEMPLATE",
                                "key": "arg0",
                                "value": "{{_event}}"
                            },
                            {
                                "type": "TEMPLATE",
                                "key": "arg1",
                                "value": "generate_lead"
                            }
                        ]
                    }
                ],
                "fingerprint": "1781529471728"
            },
            {
                "accountId": "6268264869",
                "containerId": "255515747",
                "triggerId": "20",
                "name": "schedule",
                "type": "CUSTOM_EVENT",
                "customEventFilter": [
                    {
                        "type": "EQUALS",
                        "parameter": [
                            {
                                "type": "TEMPLATE",
                                "key": "arg0",
                                "value": "{{_event}}"
                            },
                            {
                                "type": "TEMPLATE",
                                "key": "arg1",
                                "value": "schedule"
                            }
                        ]
                    }
                ],
                "fingerprint": "1781529487349"
            }
        ],
        "variable": [
            {
                "accountId": "6268264869",
                "containerId": "255515747",
                "variableId": "8",
                "name": "Const - FB Pixel ID",
                "type": "c",
                "parameter": [
                    {
                        "type": "TEMPLATE",
                        "key": "value",
                        "value": "TU_PIXEL_ID"
                    }
                ],
                "fingerprint": "1781550353769",
                "formatValue": {}
            },
            {
                "accountId": "6268264869",
                "containerId": "255515747",
                "variableId": "9",
                "name": "Const - TikTok Pixel ID",
                "type": "c",
                "parameter": [
                    {
                        "type": "TEMPLATE",
                        "key": "value",
                        "value": "TU_PIXEL_ID"
                    }
                ],
                "fingerprint": "1781550397161",
                "formatValue": {}
            },
            {
                "accountId": "6268264869",
                "containerId": "255515747",
                "variableId": "10",
                "name": "Const - GA4 ID fuente de datos",
                "type": "c",
                "parameter": [
                    {
                        "type": "TEMPLATE",
                        "key": "value",
                        "value": "TU_ID_DE_GA4"
                    }
                ],
                "fingerprint": "1781550366347",
                "formatValue": {}
            },
            {
                "accountId": "6268264869",
                "containerId": "255515747",
                "variableId": "12",
                "name": "ID de evento",
                "type": "cvt_M63B8",
                "fingerprint": "1781525482290",
                "formatValue": {}
            },
            {
                "accountId": "6268264869",
                "containerId": "255515747",
                "variableId": "16",
                "name": "Const - URL servidor",
                "type": "c",
                "parameter": [
                    {
                        "type": "TEMPLATE",
                        "key": "value",
                        "value": "URL_DEL_SERVIDOR"
                    }
                ],
                "fingerprint": "1781550417095",
                "formatValue": {}
            },
            {
                "accountId": "6268264869",
                "containerId": "255515747",
                "variableId": "18",
                "name": "GA4 eventos compartidos",
                "type": "gtes",
                "parameter": [
                    {
                        "type": "LIST",
                        "key": "eventSettingsTable",
                        "list": [
                            {
                                "type": "MAP",
                                "map": [
                                    {
                                        "type": "TEMPLATE",
                                        "key": "parameter",
                                        "value": "server_container_url"
                                    },
                                    {
                                        "type": "TEMPLATE",
                                        "key": "parameterValue",
                                        "value": "{{Const - URL servidor}}"
                                    }
                                ]
                            }
                        ]
                    }
                ],
                "fingerprint": "1781529315838"
            },
            {
                "accountId": "6268264869",
                "containerId": "255515747",
                "variableId": "23",
                "name": "Usuario - Nombre",
                "type": "v",
                "parameter": [
                    {
                        "type": "INTEGER",
                        "key": "dataLayerVersion",
                        "value": "2"
                    },
                    {
                        "type": "BOOLEAN",
                        "key": "setDefaultValue",
                        "value": "false"
                    },
                    {
                        "type": "TEMPLATE",
                        "key": "name",
                        "value": "inputs.first_name"
                    }
                ],
                "fingerprint": "1781529774986",
                "formatValue": {}
            },
            {
                "accountId": "6268264869",
                "containerId": "255515747",
                "variableId": "24",
                "name": "Usuario - Email",
                "type": "v",
                "parameter": [
                    {
                        "type": "INTEGER",
                        "key": "dataLayerVersion",
                        "value": "2"
                    },
                    {
                        "type": "BOOLEAN",
                        "key": "setDefaultValue",
                        "value": "false"
                    },
                    {
                        "type": "TEMPLATE",
                        "key": "name",
                        "value": "inputs.email"
                    }
                ],
                "fingerprint": "1781529817121",
                "formatValue": {}
            },
            {
                "accountId": "6268264869",
                "containerId": "255515747",
                "variableId": "25",
                "name": "Usuario - Apellido",
                "type": "v",
                "parameter": [
                    {
                        "type": "INTEGER",
                        "key": "dataLayerVersion",
                        "value": "2"
                    },
                    {
                        "type": "BOOLEAN",
                        "key": "setDefaultValue",
                        "value": "false"
                    },
                    {
                        "type": "TEMPLATE",
                        "key": "name",
                        "value": "inputs.last_name"
                    }
                ],
                "fingerprint": "1781529843077",
                "formatValue": {}
            },
            {
                "accountId": "6268264869",
                "containerId": "255515747",
                "variableId": "26",
                "name": "Usuario - Teléfono",
                "type": "v",
                "parameter": [
                    {
                        "type": "INTEGER",
                        "key": "dataLayerVersion",
                        "value": "2"
                    },
                    {
                        "type": "BOOLEAN",
                        "key": "setDefaultValue",
                        "value": "false"
                    },
                    {
                        "type": "TEMPLATE",
                        "key": "name",
                        "value": "inputs.phone"
                    }
                ],
                "fingerprint": "1781529870537",
                "formatValue": {}
            }
        ],
        "builtInVariable": [
            {
                "accountId": "6268264869",
                "containerId": "255515747",
                "type": "PAGE_URL",
                "name": "Page URL"
            },
            {
                "accountId": "6268264869",
                "containerId": "255515747",
                "type": "PAGE_HOSTNAME",
                "name": "Page Hostname"
            },
            {
                "accountId": "6268264869",
                "containerId": "255515747",
                "type": "PAGE_PATH",
                "name": "Page Path"
            },
            {
                "accountId": "6268264869",
                "containerId": "255515747",
                "type": "REFERRER",
                "name": "Referrer"
            },
            {
                "accountId": "6268264869",
                "containerId": "255515747",
                "type": "EVENT",
                "name": "Event"
            }
        ],
        "fingerprint": "1781550719278",
        "tagManagerUrl": "https://tagmanager.google.com/#/versions/accounts/6268264869/containers/255515747/versions/0?apiLink=version",
        "customTemplate": [
            {
                "accountId": "6268264869",
                "containerId": "255515747",
                "templateId": "5",
                "name": "Unique Event ID",
                "fingerprint": "1781525110990",
                "templateData": "___TERMS_OF_SERVICE___\n\nBy creating or modifying this file you agree to Google Tag Manager's Community\nTemplate Gallery Developer Terms of Service available at\nhttps://developers.google.com/tag-manager/gallery-tos (or such other URL as\nGoogle may provide), as modified from time to time.\n\n\n___INFO___\n\n{\n  \"type\": \"MACRO\",\n  \"id\": \"cvt_M63B8\",\n  \"version\": 1,\n  \"displayName\": \"Unique Event ID\",\n  \"description\": \"Generates unique event id\",\n  \"categories\": [\n    \"UTILITY\"\n  ],\n  \"containerContexts\": [\n    \"WEB\"\n  ],\n  \"brand\": {\n    \"displayName\": \"stape-io\",\n    \"id\": \"github.com_stape-io\"\n  }\n}\n\n\n___TEMPLATE_PARAMETERS___\n\n[]\n\n\n___SANDBOXED_JS_FOR_WEB_TEMPLATE___\n\nconst copyFromDataLayer = require('copyFromDataLayer');\nconst setInWindow = require('setInWindow');\nconst copyFromWindow = require('copyFromWindow');\nconst getTimestampMillis = require('getTimestampMillis');\nconst generateRandom = require('generateRandom');\n\n\nreturn getBrowserId() + '_' + getPageLoadId() + getGtmUniqueEventId();\n\nfunction getGtmUniqueEventId() {\n    let gtmId = copyFromDataLayer('gtm.uniqueEventId')  || 0;\n    return gtmId >= 0 ? gtmId : '00';\n}\n\nfunction getBrowserId() {\n    let gtmBrowserId =  copyFromWindow('gtmBrowserId');\n\n    if (!gtmBrowserId) {\n        gtmBrowserId = getTimestampMillis() + generateRandom(100000, 999999);\n        setInWindow('gtmBrowserId', gtmBrowserId, false);\n    }\n\n    return gtmBrowserId;\n}\n\nfunction getPageLoadId() {\n  let eventId = copyFromWindow('gtmPageLoadId');\n\n  if (!eventId) {\n    eventId = getTimestampMillis() + generateRandom(100000, 999999);\n    setInWindow('gtmPageLoadId', eventId, false);\n  }\n\n  return eventId;\n}\n\n\n___WEB_PERMISSIONS___\n\n[\n  {\n    \"instance\": {\n      \"key\": {\n        \"publicId\": \"read_data_layer\",\n        \"versionId\": \"1\"\n      },\n      \"param\": [\n        {\n          \"key\": \"allowedKeys\",\n          \"value\": {\n            \"type\": 1,\n            \"string\": \"specific\"\n          }\n        },\n        {\n          \"key\": \"keyPatterns\",\n          \"value\": {\n            \"type\": 2,\n            \"listItem\": [\n              {\n                \"type\": 1,\n                \"string\": \"gtm.uniqueEventId\"\n              }\n            ]\n          }\n        }\n      ]\n    },\n    \"clientAnnotations\": {\n      \"isEditedByUser\": true\n    },\n    \"isRequired\": true\n  },\n  {\n    \"instance\": {\n      \"key\": {\n        \"publicId\": \"access_globals\",\n        \"versionId\": \"1\"\n      },\n      \"param\": [\n        {\n          \"key\": \"keys\",\n          \"value\": {\n            \"type\": 2,\n            \"listItem\": [\n              {\n                \"type\": 3,\n                \"mapKey\": [\n                  {\n                    \"type\": 1,\n                    \"string\": \"key\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"read\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"write\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"execute\"\n                  }\n                ],\n                \"mapValue\": [\n                  {\n                    \"type\": 1,\n                    \"string\": \"gtmPageLoadId\"\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": true\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": true\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": false\n                  }\n                ]\n              },\n              {\n                \"type\": 3,\n                \"mapKey\": [\n                  {\n                    \"type\": 1,\n                    \"string\": \"key\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"read\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"write\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"execute\"\n                  }\n                ],\n                \"mapValue\": [\n                  {\n                    \"type\": 1,\n                    \"string\": \"gtmBrowserId\"\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": true\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": true\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": false\n                  }\n                ]\n              }\n            ]\n          }\n        }\n      ]\n    },\n    \"clientAnnotations\": {\n      \"isEditedByUser\": true\n    },\n    \"isRequired\": true\n  }\n]\n\n\n___TESTS___\n\nscenarios: []\n\n\n___NOTES___\n\nCreated on 11/03/2021, 11:05:32\n\n\n",
                "galleryReference": {
                    "host": "github.com",
                    "owner": "stape-io",
                    "repository": "unique-event-id-variable",
                    "version": "76498f16f1954b0286640d19eb6a1ddf2909e183",
                    "signature": "fe53a57c443dd898aa8ad7095fc9a32114fafa6af0eb66b1671338f69d9530be",
                    "galleryTemplateId": "M63B8"
                }
            },
            {
                "accountId": "6268264869",
                "containerId": "255515747",
                "templateId": "6",
                "name": "Facebook Pixel by Stape",
                "fingerprint": "1781525127915",
                "templateData": "___TERMS_OF_SERVICE___\n\nBy creating or modifying this file you agree to Google Tag Manager's Community\nTemplate Gallery Developer Terms of Service available at\nhttps://developers.google.com/tag-manager/gallery-tos (or such other URL as\nGoogle may provide), as modified from time to time.\n\n\n___INFO___\n\n{\n  \"type\": \"TAG\",\n  \"id\": \"cvt_KFNBV\",\n  \"version\": 1,\n  \"displayName\": \"Facebook Pixel by Stape\",\n  \"categories\": [\n    \"ADVERTISING\",\n    \"ANALYTICS\",\n    \"CONVERSIONS\",\n    \"MARKETING\",\n    \"REMARKETING\"\n  ],\n  \"brand\": {\n    \"id\": \"github.com_stape-io\",\n    \"displayName\": \"stape-io\",\n    \"thumbnail\": \"data:image/png;base64,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MYEFAJCYwAIASExgAQAkJrAAABITWAAAiQksAIDEBBYAQGICCwAgMYEFAJDYZAAwMucXi/jM/1iOO6/rxB1Hu3HrNd3YPxOxazpiotOJNlteKWJ+OWKu/D145lwRT54p4v8+3Y/zC0VA2wgsgBFaKAPjC7+//MLn+8q4OrqvG0f3Rhwpn4/srT7vxLXl46ZD5eNgd/XjXeW79XT5mJkq37i79QmxomyjXhlOCysRi+V/1mIv4szFIo7NFvHU2X48Vz6fvlDE8fMRJ+b65aOIk+fLH98LaDWBBTBGc4vVox/fO1V91l/3x1RRdXCmEwd3d+LArogDu7txeE/EofLzQ+XzwfLzQ7vLWCu/b890p4y2TuwtJ2Izq1HWid3l81T1mIio0qxbTsomJ9b+2b1+Ef3yX1s+xXL5vPR8JC2uBlOx+uu7uFSsTt4ulh+fK6dNZ+eLODcfcboMqTNlPFVBVU2hqm+bLX9cbyUgewILoOaqydDxMnaOz106SusHUG+W3AEAEhNYAACJCSwAgMQEFgBAYgILACAxgQUAkJjAAgBITGABACQmsAAAEhNYAACJCSwAgMQEFgBAYgILACAxgQUAkJjAAgBITGABACQmsAAAEhNYAACJCSwAgMQEFgBAYgILACAxgQUAkJjAAgBITGABACQmsAAAEhNYAACJCSwAgMQEFgBAYgILACAxgQUAkJjAAgBITGABACQmsAAAEhNYAACJCSwAgMQEFgBAYgILACAxgQUAkJjAAgBITGABACQmsAAAEhNYAACJCSwAgMQEFgBAYgILACAxgQUAkJjAAgBITGABACQmsAAAEhNYAACJCSwAgMQEFgBAYgILACAxgQUAkJjAAgBITGABACQmsAAAEhNYAACJCSwAgMQEFgBAYgILACAxgQUAkJjAAgBITGABACQmsAAAEhNYAACJCSwAgMQEFgBAYgILACAxgQUAkJjAAgBITGABACQmsAAAEhNYAACJCSwAgMQEFgBAYgILACAxgQUAkJjAAgBITGABACQmsAAAEhNYAACJCSwAgMQEFgBAYgILACAxgQUAkJjAAgBITGABACQmsAAAEhNYAACJCSwAgMQEFgBAYgILACAxgQUAkJjAAgBITGABACQmsAAAEhNYAACJCSwAgMQEFgBAYgILACAxgQUAkJjAAgBITGABACQmsAAAEhNYAACJCSwAgMQEFgBAYgILACAxgQUAkJjAAgBITGABACQmsAAAEhNYAACJCSwAgMQEFgBAYgILACAxgQUAkJjAAgBI7M8AEVZ9YYB+7i0AAAAASUVORK5CYII\\u003d\"\n  },\n  \"description\": \"Integrates the Facebook/Meta Pixel into the page and allows easy event tracking.\",\n  \"containerContexts\": [\n    \"WEB\"\n  ]\n}\n\n\n___TEMPLATE_PARAMETERS___\n\n[\n  {\n    \"type\": \"GROUP\",\n    \"name\": \"baseConfigurationGroup\",\n    \"subParams\": [\n      {\n        \"type\": \"TEXT\",\n        \"name\": \"pixelIds\",\n        \"displayName\": \"Facebook Pixel ID(s)\",\n        \"simpleValueType\": true,\n        \"valueValidators\": [\n          {\n            \"type\": \"NON_EMPTY\"\n          },\n          {\n            \"type\": \"REGEX\",\n            \"args\": [\n              \"^[0-9,]+$\"\n            ]\n          }\n        ],\n        \"help\": \"Array, single item string or comma separated string of Pixel IDs.\",\n        \"alwaysInSummary\": true,\n        \"valueHint\": \"1234...,9876...\"\n      },\n      {\n        \"type\": \"SELECT\",\n        \"name\": \"inheritEventName\",\n        \"displayName\": \"Event Name Setup Method\",\n        \"selectItems\": [\n          {\n            \"value\": \"inherit\",\n            \"displayValue\": \"Inherit from DataLayer\"\n          },\n          {\n            \"value\": \"override\",\n            \"displayValue\": \"Override\"\n          }\n        ],\n        \"simpleValueType\": true,\n        \"subParams\": [\n          {\n            \"type\": \"RADIO\",\n            \"name\": \"eventName\",\n            \"radioItems\": [\n              {\n                \"value\": \"standard\",\n                \"displayValue\": \"Standard\",\n                \"subParams\": [\n                  {\n                    \"type\": \"SELECT\",\n                    \"name\": \"eventNameStandard\",\n                    \"macrosInSelect\": false,\n                    \"selectItems\": [\n                      {\n                        \"value\": \"PageView\",\n                        \"displayValue\": \"PageView\"\n                      },\n                      {\n                        \"value\": \"AddPaymentInfo\",\n                        \"displayValue\": \"AddPaymentInfo\"\n                      },\n                      {\n                        \"value\": \"AddToCart\",\n                        \"displayValue\": \"AddToCart\"\n                      },\n                      {\n                        \"value\": \"AddToWishlist\",\n                        \"displayValue\": \"AddToWishlist\"\n                      },\n                      {\n                        \"value\": \"CompleteRegistration\",\n                        \"displayValue\": \"CompleteRegistration\"\n                      },\n                      {\n                        \"value\": \"Contact\",\n                        \"displayValue\": \"Contact\"\n                      },\n                      {\n                        \"value\": \"CustomizeProduct\",\n                        \"displayValue\": \"CustomizeProduct\"\n                      },\n                      {\n                        \"value\": \"Donate\",\n                        \"displayValue\": \"Donate\"\n                      },\n                      {\n                        \"value\": \"FindLocation\",\n                        \"displayValue\": \"FindLocation\"\n                      },\n                      {\n                        \"value\": \"InitiateCheckout\",\n                        \"displayValue\": \"InitiateCheckout\"\n                      },\n                      {\n                        \"value\": \"Lead\",\n                        \"displayValue\": \"Lead\"\n                      },\n                      {\n                        \"value\": \"Purchase\",\n                        \"displayValue\": \"Purchase\"\n                      },\n                      {\n                        \"value\": \"Schedule\",\n                        \"displayValue\": \"Schedule\"\n                      },\n                      {\n                        \"value\": \"Search\",\n                        \"displayValue\": \"Search\"\n                      },\n                      {\n                        \"value\": \"StartTrial\",\n                        \"displayValue\": \"StartTrial\"\n                      },\n                      {\n                        \"value\": \"SubmitApplication\",\n                        \"displayValue\": \"SubmitApplication\"\n                      },\n                      {\n                        \"value\": \"Subscribe\",\n                        \"displayValue\": \"Subscribe\"\n                      },\n                      {\n                        \"value\": \"ViewContent\",\n                        \"displayValue\": \"ViewContent\"\n                      }\n                    ],\n                    \"simpleValueType\": true,\n                    \"displayName\": \"Event Name\",\n                    \"defaultValue\": \"PageView\"\n                  }\n                ]\n              },\n              {\n                \"value\": \"custom\",\n                \"displayValue\": \"Custom\",\n                \"subParams\": [\n                  {\n                    \"type\": \"TEXT\",\n                    \"name\": \"eventNameCustom\",\n                    \"simpleValueType\": true,\n                    \"displayName\": \"Event Name\",\n                    \"valueValidators\": [\n                      {\n                        \"type\": \"NON_EMPTY\"\n                      }\n                    ]\n                  }\n                ]\n              }\n            ],\n            \"simpleValueType\": true,\n            \"enablingConditions\": [\n              {\n                \"paramName\": \"inheritEventName\",\n                \"paramValue\": \"override\",\n                \"type\": \"EQUALS\"\n              }\n            ],\n            \"displayName\": \"Event Type\"\n          }\n        ],\n        \"defaultValue\": \"override\",\n        \"alwaysInSummary\": true\n      },\n      {\n        \"type\": \"CHECKBOX\",\n        \"name\": \"enableDataLayerMapping\",\n        \"checkboxText\": \"Enable automatic User Data and Event Parameters mapping from the Data Layer\",\n        \"simpleValueType\": true,\n        \"help\": \"If you check this, then the Facebook tag will populate standard Object Properties and User Data automatically from the DataLayer. The tag parses Universal Analytics,  \\u003ca target\\u003d\\\"_blank\\\" href\\u003d\\\"https://developers.google.com/analytics/devguides/collection/ga4/ecommerce\\\"\\u003eGA4\\u003c/a\\u003e and \\u003ca target\\u003d\\\"_blank\\\" href\\u003d\\\"https://developers.google.com/tag-platform/tag-manager/server-side/common-event-data\\\"\\u003eCommon Event Data\\u003c/a\\u003e formats.\",\n        \"defaultValue\": true,\n        \"alwaysInSummary\": true,\n        \"subParams\": [\n          {\n            \"type\": \"CHECKBOX\",\n            \"name\": \"enableCurrentDataLayerOnly\",\n            \"checkboxText\": \"Use data only from the most recent Data Layer event where the data can be found (ignore recursive merges)\",\n            \"simpleValueType\": true,\n            \"help\": \"If enabled, the tag will take data only from the most recent Data Layer event where the data can be found. \\n\\u003cbr/\\u003e\\u003cbr/\\u003e\\nIn other words, the tag will ignore recursive merges for Data Layer variables and take only the most recent value of the data. \\u003ca href\\u003d\\\"https://www.simoahava.com/gtm-tips/data-layer-variable-versions-explained/\\\"\\u003eLearn more\\u003c/a\\u003e.\\n\\u003cbr/\\u003e\\nThat\\u0027s how it worked in the old Facebook pixel tag.\",\n            \"defaultValue\": false,\n            \"enablingConditions\": [\n              {\n                \"paramName\": \"enableDataLayerMapping\",\n                \"paramValue\": true,\n                \"type\": \"EQUALS\"\n              }\n            ],\n            \"alwaysInSummary\": true\n          }\n        ]\n      },\n      {\n        \"type\": \"CHECKBOX\",\n        \"name\": \"enableEdvancedMatching\",\n        \"checkboxText\": \"Enable Advanced Matching\",\n        \"simpleValueType\": true,\n        \"help\": \"Enable sending of user personal information such as email addresses, names, etc. to Meta.\\n\\u003cbr/\\u003e\\nMore information can be found \\u003ca target\\u003d\\\"_blank\\\" href\\u003d\\\"https://developers.facebook.com/docs/meta-pixel/advanced/advanced-matching/\\\"\\u003ehere\\u003c/a\\u003e.\",\n        \"subParams\": [\n          {\n            \"type\": \"GROUP\",\n            \"name\": \"advancedMatchingGroup\",\n            \"subParams\": [\n              {\n                \"type\": \"CHECKBOX\",\n                \"name\": \"enableEventEnhancement\",\n                \"checkboxText\": \"Enable Event Enhancement\",\n                \"simpleValueType\": true,\n                \"help\": \"Enable the use of \\u003ci\\u003elocalStorage\\u003c/i\\u003e to store data for enhanced event tracking.\\n\\u003cbr/\\u003e\\u003cbr/\\u003e\\nNote: If the \\u003ci\\u003eEnable automatic data population from the Data Layer\\u003c/i\\u003e option is selected, all User Data it finds in the Data Layer will be stored, not just the fields explicitly defined in the User Data section.\",\n                \"subParams\": [\n                  {\n                    \"type\": \"CHECKBOX\",\n                    \"name\": \"storeUserDataHashed\",\n                    \"checkboxText\": \"Store User Data hashed\",\n                    \"simpleValueType\": true,\n                    \"help\": \"The User Data will be stored hashed in \\u003ci\\u003elocalStorage\\u003c/i\\u003e.\",\n                    \"enablingConditions\": [\n                      {\n                        \"paramName\": \"enableEventEnhancement\",\n                        \"paramValue\": true,\n                        \"type\": \"EQUALS\"\n                      }\n                    ]\n                  }\n                ]\n              },\n              {\n                \"type\": \"CHECKBOX\",\n                \"name\": \"runInitOnce\",\n                \"checkboxText\": \"Run the \\u0027init\\u0027 command only once\",\n                \"simpleValueType\": true,\n                \"help\": \"When Advanced Matching is enabled, the tag runs the \\u003ci\\u003einit\\u003c/i\\u003e command with each event to send user information that becomes available after page load.\\n\\u003cbr/\\u003e\\u003cbr/\\u003e\\nThis causes the following message in the Console from the fbevents.js file:\\n\\u003ci\\u003e[Meta Pixel] - Duplicate Pixel ID: {Pixel ID}.\\u003c/i\\u003e\\n\\u003cbr/\\u003e\\u003cbr/\\u003e\\nEnable this option to skip repeated \\u003ci\\u003einit\\u003c/i\\u003e calls and suppress the Console message. Note that Advanced Matching data found after the first call won’t be sent.\"\n              }\n            ],\n            \"enablingConditions\": [\n              {\n                \"paramName\": \"enableEdvancedMatching\",\n                \"paramValue\": true,\n                \"type\": \"EQUALS\"\n              }\n            ]\n          }\n        ],\n        \"defaultValue\": true,\n        \"alwaysInSummary\": true\n      }\n    ]\n  },\n  {\n    \"type\": \"GROUP\",\n    \"name\": \"complianceGroup\",\n    \"displayName\": \"Compliance\",\n    \"groupStyle\": \"ZIPPY_OPEN\",\n    \"subParams\": [\n      {\n        \"type\": \"SELECT\",\n        \"name\": \"consent\",\n        \"displayName\": \"Consent Granted\",\n        \"macrosInSelect\": true,\n        \"selectItems\": [\n          {\n            \"value\": true,\n            \"displayValue\": \"True\"\n          },\n          {\n            \"value\": false,\n            \"displayValue\": \"False\"\n          }\n        ],\n        \"simpleValueType\": true,\n        \"help\": \"Setting Consent Granted to \\u003cstrong\\u003efalse\\u003c/strong\\u003e will prevent the pixel from sending hits until tag fired with Consent Granted \\u003cstrong\\u003etrue\\u003c/strong\\u003e.\\n\\u003cbr/\\u003e\\n\\u003ca href\\u003d\\\"https://developers.facebook.com/docs/meta-pixel/implementation/gdpr\\\"\\u003eLearn more\\u003c/a\\u003e.\",\n        \"enablingConditions\": [\n          {\n            \"paramName\": \"enableConsentMode\",\n            \"paramValue\": false,\n            \"type\": \"EQUALS\"\n          }\n        ]\n      },\n      {\n        \"type\": \"CHECKBOX\",\n        \"name\": \"enableConsentMode\",\n        \"checkboxText\": \"Enable GTM consent mode support\",\n        \"simpleValueType\": true,\n        \"help\": \"When enabled, this tag checks for the Google Consent Mode \\u003ci\\u003ead_storage\\u003c/i\\u003e consent.\\n\\u003cbr/\\u003e\\nIf consent is not granted, the Facebook Pixel consent is set as revoked. \\n\\u003cbr/\\u003e\\nIf consent is granted (initially or later), the pixel consent is automatically granted.\"\n      },\n      {\n        \"type\": \"CHECKBOX\",\n        \"name\": \"dpoLDU\",\n        \"checkboxText\": \"Limited Data Use (LDU)\",\n        \"simpleValueType\": true,\n        \"help\": \"Limited Data Use is a data processing option that gives you more control over how your data is used in the system receiving the data. \\u003ca target\\u003d\\\"_blank\\\" href\\u003d\\\"https://developers.facebook.com/docs/meta-pixel/implementation/data-processing-options\\\"\\u003eLearn more\\u003c/a\\u003e.\"\n      },\n      {\n        \"type\": \"TEXT\",\n        \"name\": \"dpoCountry\",\n        \"displayName\": \"Country\",\n        \"simpleValueType\": true,\n        \"defaultValue\": 0,\n        \"enablingConditions\": [\n          {\n            \"paramName\": \"dpoLDU\",\n            \"paramValue\": true,\n            \"type\": \"EQUALS\"\n          }\n        ],\n        \"valueValidators\": [\n          {\n            \"type\": \"NUMBER\"\n          }\n        ]\n      },\n      {\n        \"type\": \"TEXT\",\n        \"name\": \"dpoState\",\n        \"displayName\": \"State\",\n        \"simpleValueType\": true,\n        \"defaultValue\": 0,\n        \"enablingConditions\": [\n          {\n            \"paramName\": \"dpoLDU\",\n            \"paramValue\": true,\n            \"type\": \"EQUALS\"\n          }\n        ],\n        \"valueValidators\": [\n          {\n            \"type\": \"NUMBER\"\n          }\n        ]\n      }\n    ]\n  },\n  {\n    \"displayName\": \"User Data\",\n    \"name\": \"userDataListGroup\",\n    \"groupStyle\": \"ZIPPY_CLOSED\",\n    \"type\": \"GROUP\",\n    \"subParams\": [\n      {\n        \"type\": \"LABEL\",\n        \"name\": \"userDataLabel\",\n        \"displayName\": \"User Data Properties that you can send to Meta can be found \\u003ca target\\u003d\\\"_blank\\\" href\\u003d\\\"https://developers.facebook.com/docs/meta-pixel/advanced/advanced-matching\\\"\\u003ehere\\u003c/a\\u003e.\\u003cbr\\u003e\\u003cbr\\u003e\"\n      },\n      {\n        \"type\": \"SELECT\",\n        \"name\": \"userDataFromVariable\",\n        \"displayName\": \"Load Properties From Variable\",\n        \"macrosInSelect\": true,\n        \"selectItems\": [\n          {\n            \"value\": false,\n            \"displayValue\": \"False\"\n          }\n        ],\n        \"simpleValueType\": true,\n        \"help\": \"You can use a standard User-Provided Data variable or create a variable that returns a JavaScript object with the desired user data properties. This object will merge with additional properties from the table below, with any conflicts resolved in favor of the table entries.\"\n      },\n      {\n        \"name\": \"userDataList\",\n        \"simpleTableColumns\": [\n          {\n            \"valueValidators\": [\n              {\n                \"type\": \"NON_EMPTY\"\n              }\n            ],\n            \"defaultValue\": \"em\",\n            \"displayName\": \"Property Name\",\n            \"name\": \"name\",\n            \"isUnique\": true,\n            \"type\": \"SELECT\",\n            \"selectItems\": [\n              {\n                \"value\": \"em\",\n                \"displayValue\": \"Email\"\n              },\n              {\n                \"value\": \"ph\",\n                \"displayValue\": \"Phone\"\n              },\n              {\n                \"value\": \"ge\",\n                \"displayValue\": \"Gender\"\n              },\n              {\n                \"value\": \"db\",\n                \"displayValue\": \"Date of Birth\"\n              },\n              {\n                \"value\": \"ln\",\n                \"displayValue\": \"Last Name\"\n              },\n              {\n                \"value\": \"fn\",\n                \"displayValue\": \"First Name\"\n              },\n              {\n                \"value\": \"ct\",\n                \"displayValue\": \"City\"\n              },\n              {\n                \"value\": \"st\",\n                \"displayValue\": \"State\"\n              },\n              {\n                \"value\": \"zp\",\n                \"displayValue\": \"Zip\"\n              },\n              {\n                \"value\": \"country\",\n                \"displayValue\": \"Country\"\n              },\n              {\n                \"value\": \"external_id\",\n                \"displayValue\": \"External ID\"\n              }\n            ]\n          },\n          {\n            \"defaultValue\": \"\",\n            \"displayName\": \"Property Value\",\n            \"name\": \"value\",\n            \"type\": \"TEXT\"\n          }\n        ],\n        \"type\": \"SIMPLE_TABLE\",\n        \"newRowButtonText\": \"Add property\"\n      }\n    ],\n    \"enablingConditions\": [\n      {\n        \"paramName\": \"enableEdvancedMatching\",\n        \"paramValue\": true,\n        \"type\": \"EQUALS\"\n      }\n    ]\n  },\n  {\n    \"displayName\": \"Object Properties\",\n    \"name\": \"objectPropertiesGroup\",\n    \"groupStyle\": \"ZIPPY_CLOSED\",\n    \"type\": \"GROUP\",\n    \"subParams\": [\n      {\n        \"type\": \"LABEL\",\n        \"name\": \"objectPropertiesLabel\",\n        \"displayName\": \"Standard Object Properties that you can send to Meta can be found \\u003ca target\\u003d\\\"_blank\\\" href\\u003d\\\"https://developers.facebook.com/docs/meta-pixel/reference#object-properties\\\"\\u003ehere\\u003c/a\\u003e.\\u003cbr\\u003e\\u003cbr\\u003e\"\n      },\n      {\n        \"type\": \"SELECT\",\n        \"name\": \"objectPropertiesFromVariable\",\n        \"displayName\": \"Load Properties From Variable\",\n        \"macrosInSelect\": true,\n        \"selectItems\": [\n          {\n            \"value\": false,\n            \"displayValue\": \"False\"\n          }\n        ],\n        \"simpleValueType\": true,\n        \"help\": \"You can create a variable that returns a JavaScript object with the desired properties. This object will merge with additional properties from the table below, with any conflicts resolved in favor of the table entries.\"\n      },\n      {\n        \"name\": \"objectPropertiesList\",\n        \"simpleTableColumns\": [\n          {\n            \"valueValidators\": [],\n            \"defaultValue\": \"\",\n            \"displayName\": \"Property Name\",\n            \"name\": \"name\",\n            \"isUnique\": true,\n            \"type\": \"TEXT\"\n          },\n          {\n            \"defaultValue\": \"\",\n            \"displayName\": \"Property Value\",\n            \"name\": \"value\",\n            \"type\": \"TEXT\"\n          }\n        ],\n        \"type\": \"SIMPLE_TABLE\",\n        \"newRowButtonText\": \"Add property\"\n      }\n    ]\n  },\n  {\n    \"type\": \"GROUP\",\n    \"name\": \"serverGroup\",\n    \"displayName\": \"Server Side Tracking\",\n    \"groupStyle\": \"ZIPPY_CLOSED\",\n    \"subParams\": [\n      {\n        \"type\": \"TEXT\",\n        \"name\": \"eventId\",\n        \"displayName\": \"Event ID\",\n        \"simpleValueType\": true,\n        \"help\": \"Set the Event ID parameter in case you are tracking the same event via server-side using the Meta Conversions API.\\n\\u003cbr/\\u003e\\nThe Event ID can be used to deduplicate the same event if sent from multiple sources. \\n\\u003cbr/\\u003e\\n\\u003ca href\\u003d\\\"https://developers.facebook.com/docs/marketing-api/conversions-api/deduplicate-pixel-and-server-events/\\\"\\u003eLearn more\\u003c/a\\u003e.\"\n      },\n      {\n        \"type\": \"GROUP\",\n        \"name\": \"advancedSettingsGroup\",\n        \"displayName\": \"Advanced Settings\",\n        \"groupStyle\": \"ZIPPY_OPEN_ON_PARAM\",\n        \"subParams\": [\n          {\n            \"type\": \"CHECKBOX\",\n            \"name\": \"dataLayerEventPush\",\n            \"checkboxText\": \"Push event to DataLayer with this Event ID\",\n            \"simpleValueType\": true,\n            \"help\": \"Helpful for easier events deduplication.\",\n            \"defaultValue\": false\n          },\n          {\n            \"type\": \"TEXT\",\n            \"name\": \"dataLayerEventName\",\n            \"displayName\": \"DataLayer Event Name\",\n            \"simpleValueType\": true,\n            \"enablingConditions\": [\n              {\n                \"paramName\": \"dataLayerEventPush\",\n                \"paramValue\": true,\n                \"type\": \"EQUALS\"\n              }\n            ],\n            \"valueValidators\": [\n              {\n                \"type\": \"NON_EMPTY\"\n              }\n            ],\n            \"valueHint\": \"page_view_unique\"\n          },\n          {\n            \"type\": \"TEXT\",\n            \"name\": \"dataLayerVariableName\",\n            \"displayName\": \"DataLayer Object Name\",\n            \"simpleValueType\": true,\n            \"enablingConditions\": [\n              {\n                \"paramName\": \"dataLayerEventPush\",\n                \"paramValue\": true,\n                \"type\": \"EQUALS\"\n              }\n            ],\n            \"valueValidators\": [\n              {\n                \"type\": \"NON_EMPTY\"\n              }\n            ],\n            \"defaultValue\": \"dataLayer\",\n            \"help\": \"Use dataLayer by default. Modify only if you renamed dataLayer object name.\"\n          }\n        ]\n      }\n    ]\n  },\n  {\n    \"type\": \"GROUP\",\n    \"name\": \"otherSettingsGroup\",\n    \"displayName\": \"Other Settings\",\n    \"groupStyle\": \"ZIPPY_CLOSED\",\n    \"subParams\": [\n      {\n        \"help\": \"Facebook automatically collects metadata and user interactions (e.g., clicks). Check this box to disable this functionality.\",\n        \"simpleValueType\": true,\n        \"name\": \"disableAutoConfig\",\n        \"checkboxText\": \"Disable Automatic Configuration\",\n        \"type\": \"CHECKBOX\"\n      },\n      {\n        \"type\": \"CHECKBOX\",\n        \"name\": \"disablePushState\",\n        \"checkboxText\": \"Disable History Event Tracking\",\n        \"simpleValueType\": true,\n        \"help\": \"The Facebook Pixel automatically tracks history events (pushState and replaceState) as PageViews. Check this box to disable this automatic tracking.\"\n      },\n      {\n        \"type\": \"CHECKBOX\",\n        \"name\": \"enableParamBuilderSdk\",\n        \"checkboxText\": \"Increase Browser ID and Click ID Cookies Coverage\",\n        \"simpleValueType\": true,\n        \"defaultValue\": true,\n        \"help\": \"When enabled, the Parameter Builder SDK library will be loaded. This library helps retrieving and saving the Browser ID (\\u003ci\\u003e_fbp\\u003c/i\\u003e cookie) and Click ID (\\u003ci\\u003e_fbc\\u003c/i\\u003e cookie) values into cookies, and it also tries to retrieve a backup Click ID from in-app-browser when feasible.\\n\\u003cbr/\\u003e\\u003cbr/\\u003e\\n\\u003ca href\\u003d\\\"https://developers.facebook.com/docs/marketing-api/conversions-api/parameter-builder-library\\\"\\u003eLearn more\\u003c/a\\u003e.\",\n        \"alwaysInSummary\": true\n      }\n    ]\n  }\n]\n\n\n___SANDBOXED_JS_FOR_WEB_TEMPLATE___\n\nconst addConsentListener = require('addConsentListener');\nconst aliasInWindow = require('aliasInWindow');\nconst callInWindow = require('callInWindow');\nconst copyFromDataLayer = require('copyFromDataLayer');\nconst copyFromWindow = require('copyFromWindow');\nconst createQueue = require('createQueue');\nconst getType = require('getType');\nconst injectScript = require('injectScript');\nconst isConsentGranted = require('isConsentGranted');\nconst JSON = require('JSON');\nconst localStorage = require('localStorage');\nconst makeNumber = require('makeNumber');\nconst makeString = require('makeString');\nconst makeTableMap = require('makeTableMap');\nconst math = require('Math');\nconst Object = require('Object');\nconst setInWindow = require('setInWindow');\nconst sha256 = require('sha256');\nconst templateStorage = require('templateStorage');\n\n// Call-once methods.\nlet gtmOnSuccess = () => {\n  gtmOnSuccess = () => {};\n  return data.gtmOnSuccess();\n};\n\nlet gtmOnFailure = () => {\n  gtmOnFailure = () => {};\n  return data.gtmOnFailure();\n};\n\n/*==============================================================================\n==============================================================================*/\n\nconst queueName = 'fbq';\nconst queue = getQueue(queueName);\nconst isConsentRevoked = data.enableConsentMode\n  ? !isConsentGranted('ad_storage')\n  : data.consent === false;\nconst isParamBuilderSdkEnabled = data.hasOwnProperty('enableParamBuilderSdk')\n  ? data.enableParamBuilderSdk\n  : true;\nconst PARTNER_NAME = 'stape-gtm-1.2.0' + (isParamBuilderSdkEnabled ? '-pb' : '');\n\nsetConsent(isConsentRevoked);\nsendEvent(isConsentRevoked);\nsendDataLayerPush();\nrunOnConsentGranted('ad_storage', isConsentRevoked, () => {\n  loadScripts(isParamBuilderSdkEnabled);\n});\n\nif (isConsentRevoked) {\n  // If consent is revoked, call gtmOnSuccess to avoid 'Still running' status.\n  return gtmOnSuccess();\n}\n\n/*==============================================================================\n  Vendor related functions\n==============================================================================*/\n\nfunction getQueue(queueName) {\n  const q = copyFromWindow(queueName);\n  if (q) return q;\n\n  setInWindow(queueName, function () {\n    const callMethod = copyFromWindow(queueName + '.callMethod.apply');\n    if (callMethod) callInWindow(queueName + '.callMethod.apply', null, arguments);\n    else callInWindow(queueName + '.queue.push', arguments);\n  });\n\n  aliasInWindow('_' + queueName, queueName);\n  createQueue(queueName + '.queue');\n\n  return copyFromWindow(queueName);\n}\n\nfunction setFbqConsent(command) {\n  const queue = getQueue(queueName);\n  if (command === 'revoke') {\n    // Allows only one 'revoke' command at a time in the queue to avoid it being locked indefinitely.\n    const queueHasRevokeCommand = (queue.queue || []).some(\n      (item) => item[0] === 'consent' && item[1] === 'revoke'\n    );\n    if (queueHasRevokeCommand) return;\n  }\n  queue('consent', command);\n}\n\nfunction runOnConsentGranted(consentType, isConsentRevoked, callback) {\n  if (data.enableConsentMode) {\n    if (isConsentRevoked) {\n      const callbacksKey = 'fbq_consent_callbacks_' + consentType;\n      const callbacks = templateStorage.getItem(callbacksKey) || [];\n      callbacks.push(callback);\n      templateStorage.setItem(callbacksKey, callbacks);\n\n      const listenerAddedKey = 'fbq_consent_listener_added_' + consentType;\n      if (!templateStorage.getItem(listenerAddedKey)) {\n        templateStorage.setItem(listenerAddedKey, true);\n        addConsentListener(consentType, (type, granted) => {\n          if (type !== consentType || !granted) return;\n          const queuedCallbacks = templateStorage.getItem(callbacksKey) || [];\n          templateStorage.setItem(callbacksKey, []);\n          queuedCallbacks.forEach((cb) => cb());\n        });\n      }\n    } else {\n      callback();\n    }\n    return;\n  }\n\n  // Manual consent\n  if (!isConsentRevoked) callback();\n}\n\nfunction setConsent(isConsentRevoked) {\n  if (data.dpoLDU) {\n    queue('dataProcessingOptions', ['LDU'], makeNumber(data.dpoCountry), makeNumber(data.dpoState));\n  }\n\n  if (isConsentRevoked) setFbqConsent('revoke');\n\n  runOnConsentGranted('ad_storage', isConsentRevoked, () => {\n    setFbqConsent('grant');\n  });\n}\n\nfunction setSettings(pixelId) {\n  if (data.disableAutoConfig) {\n    queue('set', 'autoConfig', false, pixelId);\n  }\n\n  if (data.disablePushState) {\n    setInWindow(queueName + '.disablePushState', true);\n  }\n}\n\nfunction sendEvent(isConsentRevoked) {\n  const initIds = copyFromWindow('_meta_gtm_ids') || [];\n  const pixelIds = data.pixelIds;\n  const eventName = getEventName();\n  const command = getCommand(eventName);\n  const eventData = getEventData(eventName);\n  const userData = getUserData(isConsentRevoked);\n\n  pixelIds.split(',').forEach((pixelId) => {\n    const isNotInitialized = initIds.indexOf(pixelId) === -1;\n\n    if (isNotInitialized) {\n      initIds.push(pixelId);\n      setInWindow('_meta_gtm_ids', initIds, true);\n      setSettings(pixelId);\n    }\n\n    if (isNotInitialized || (data.enableEdvancedMatching && !data.runInitOnce)) {\n      queue('init', pixelId, userData);\n    }\n    queue('set', 'agent', PARTNER_NAME, pixelId);\n    queue(\n      command,\n      pixelId,\n      eventName,\n      eventData,\n      data.eventId ? { eventID: data.eventId } : undefined\n    );\n  });\n}\n\nfunction getEventName() {\n  if (data.inheritEventName === 'inherit') {\n    let eventName = copyFromDataLayer('event');\n\n    if (!eventName) {\n      const ecommerceDataLayer = copyFromDataLayer('ecommerce', 1);\n      if (ecommerceDataLayer.detail) eventName = 'ViewContent';\n      else if (ecommerceDataLayer.add) eventName = 'AddToCart';\n      else if (ecommerceDataLayer.checkout) eventName = 'InitiateCheckout';\n      else if (ecommerceDataLayer.purchase) eventName = 'Purchase';\n    }\n\n    const mapFacebookEventName = {\n      page_view: 'PageView',\n      'gtm.dom': 'PageView',\n      add_payment_info: 'AddPaymentInfo',\n      add_to_cart: 'AddToCart',\n      add_to_wishlist: 'AddToWishlist',\n      sign_up: 'CompleteRegistration',\n      begin_checkout: 'InitiateCheckout',\n      generate_lead: 'Lead',\n      purchase: 'Purchase',\n      search: 'Search',\n      view_item: 'ViewContent',\n\n      contact: 'Contact',\n      customize_product: 'CustomizeProduct',\n      donate: 'Donate',\n      find_location: 'FindLocation',\n      schedule: 'Schedule',\n      start_trial: 'StartTrial',\n      submit_application: 'SubmitApplication',\n      subscribe: 'Subscribe',\n\n      page_view_stape: 'PageView',\n      add_payment_info_stape: 'AddPaymentInfo',\n      add_to_cart_stape: 'AddToCart',\n      sign_up_stape: 'CompleteRegistration',\n      begin_checkout_stape: 'InitiateCheckout',\n      purchase_stape: 'Purchase',\n      view_item_stape: 'ViewContent',\n\n      'gtm4wp.addProductToCartEEC': 'AddToCart',\n      'gtm4wp.productClickEEC': 'ViewContent',\n      'gtm4wp.checkoutOptionEEC': 'InitiateCheckout',\n      'gtm4wp.checkoutStepEEC': 'AddPaymentInfo',\n      'gtm4wp.orderCompletedEEC': 'Purchase'\n    };\n\n    if (!mapFacebookEventName[eventName]) {\n      return eventName;\n    }\n\n    return mapFacebookEventName[eventName];\n  }\n\n  return data.eventName === 'standard' ? data.eventNameStandard : data.eventNameCustom;\n}\n\nfunction getCommand(eventName) {\n  return [\n    'AddPaymentInfo',\n    'AddToCart',\n    'AddToWishlist',\n    'CompleteRegistration',\n    'Contact',\n    'CustomizeProduct',\n    'Donate',\n    'FindLocation',\n    'InitiateCheckout',\n    'Lead',\n    'PageView',\n    'Purchase',\n    'Schedule',\n    'Search',\n    'StartTrial',\n    'SubmitApplication',\n    'Subscribe',\n    'ViewContent'\n  ].indexOf(eventName) === -1\n    ? 'trackSingleCustom'\n    : 'trackSingle';\n}\n\nfunction getUserData(isConsentRevoked) {\n  if (!data.enableEdvancedMatching) {\n    return;\n  }\n\n  let userData = {};\n\n  if (data.enableEventEnhancement) {\n    userData = getEventEnhancement(isConsentRevoked);\n  }\n\n  if (data.enableDataLayerMapping) {\n    let userDataFromDataLayer = getDL('user_data');\n\n    if (getType(userDataFromDataLayer) === 'object') {\n      parseUserData(userData, userDataFromDataLayer, true);\n    }\n  }\n\n  if (getType(data.userDataFromVariable) === 'object') {\n    parseUserData(userData, data.userDataFromVariable, false);\n  }\n\n  if (data.userDataList && data.userDataList.length) {\n    userData = mergeObjects(userData, makeTableMap(data.userDataList, 'name', 'value'));\n  }\n\n  if (objIsEmptyOrContainsOnlyFalsyValues(userData)) {\n    return;\n  }\n\n  if (data.enableEventEnhancement) {\n    storeEventEnhancement(isConsentRevoked, userData);\n  }\n\n  return userData;\n}\n\nfunction getEventData(eventName) {\n  let objectProperties = {};\n\n  if (data.enableDataLayerMapping) {\n    let ecommerce = getDL('ecommerce');\n    if (getType(ecommerce) !== 'object') {\n      ecommerce = {};\n    }\n\n    objectProperties = getUAEventData(eventName, objectProperties, ecommerce);\n\n    if (!objectProperties.content_type) {\n      objectProperties = getGA4EventData(eventName, objectProperties, ecommerce);\n    }\n  }\n\n  if (getType(data.objectPropertiesFromVariable) === 'object') {\n    mergeObjects(objectProperties, data.objectPropertiesFromVariable);\n  }\n\n  if (data.objectPropertiesList && data.objectPropertiesList.length) {\n    objectProperties = mergeObjects(\n      objectProperties,\n      makeTableMap(data.objectPropertiesList, 'name', 'value')\n    );\n  }\n\n  return objectProperties;\n}\n\nfunction getEventEnhancement(isConsentRevoked) {\n  if (!isConsentRevoked && localStorage) {\n    const gtmeec = localStorage.getItem('gtmeec');\n\n    if (gtmeec) {\n      const gtmeecParsed = JSON.parse(gtmeec);\n\n      if (getType(gtmeecParsed) === 'object') {\n        return gtmeecParsed;\n      }\n    }\n  }\n\n  return {};\n}\n\nfunction normalizeBasedOnSchemaKey(schemaKey, identifier) {\n  if (schemaKey === 'ph') return normalizePhoneNumber(identifier);\n  else if (schemaKey === 'ct' || schemaKey === 'st' || schemaKey === 'zp') {\n    return removeWhiteSpace(identifier);\n  } else return identifier;\n}\n\nfunction hashUserDataFields(userData, storeUserDataInLocalStorage) {\n  const canUseHashSync = getType(copyFromWindow('dataTag256')) === 'function';\n  const hashAsyncHelpers = {\n    pendingHashs: 0,\n    maybeFinish: (userDataHashed) => {\n      if (hashAsyncHelpers.pendingHashs === 0) storeUserDataInLocalStorage(userDataHashed);\n    }\n  };\n\n  const userDataHashed = {};\n\n  const fieldNames = Object.keys(userData);\n  fieldNames.forEach((fieldName) => {\n    const value = userData[fieldName];\n\n    if (value === undefined || value === null || value === '') return;\n    if (isHashed(value)) {\n      userDataHashed[fieldName] = value;\n      return;\n    }\n\n    const normalizedValue = makeString(normalizeBasedOnSchemaKey(fieldName, value))\n      .toLowerCase()\n      .trim();\n    if (canUseHashSync) {\n      userDataHashed[fieldName] = callInWindow('dataTag256', normalizedValue, 'HEX');\n    } else {\n      hashAsyncHelpers.pendingHashs++;\n      sha256(\n        normalizedValue,\n        (digest) => {\n          userDataHashed[fieldName] = digest;\n          hashAsyncHelpers.pendingHashs--;\n          hashAsyncHelpers.maybeFinish(userDataHashed);\n        },\n        () => {\n          hashAsyncHelpers.pendingHashs--;\n        },\n        { outputEncoding: 'hex' }\n      );\n    }\n  });\n\n  if (canUseHashSync) {\n    storeUserDataInLocalStorage(userDataHashed);\n    return userDataHashed;\n  } else {\n    hashAsyncHelpers.maybeFinish(userDataHashed);\n    return;\n  }\n}\n\nfunction storeUserDataInLocalStorage(userData) {\n  if (!objHasProps(userData)) return;\n  const gtmeec = JSON.stringify(userData);\n  localStorage.setItem('gtmeec', gtmeec);\n}\n\nfunction storeEventEnhancement(isConsentRevoked, userData) {\n  if (!isConsentRevoked && localStorage && objHasProps(userData)) {\n    if (!data.storeUserDataHashed) storeUserDataInLocalStorage(userData);\n    else hashUserDataFields(userData, storeUserDataInLocalStorage);\n  }\n}\n\nfunction sendDataLayerPush() {\n  if (data.dataLayerEventPush) {\n    const dataLayerQueueName = data.dataLayerVariableName || 'dataLayer';\n    const dataLayerPush = createQueue(dataLayerQueueName);\n\n    dataLayerPush({ eventId: data.eventId, event: data.dataLayerEventName || 'DefaultTagEvent' });\n  }\n}\n\nfunction parseUserData(userData, userDataFrom, useDL) {\n  let email =\n    userDataFrom.email ||\n    userDataFrom.sha256_email_address ||\n    userDataFrom.email_address ||\n    userDataFrom.em;\n  const emailType = getType(email);\n  if (emailType === 'array' || emailType === 'object') email = email[0];\n  if (email) userData.em = email;\n\n  let phone =\n    userDataFrom.phone ||\n    userDataFrom.sha256_phone_number ||\n    userDataFrom.phone_number ||\n    userDataFrom.ph;\n  const phoneType = getType(phone);\n  if (phoneType === 'array' || phoneType === 'object') phone = phone[0];\n  if (phone) userData.ph = phone;\n\n  const firstName =\n    userDataFrom.firstName ||\n    userDataFrom.nameFirst ||\n    userDataFrom.first_name ||\n    userDataFrom.fn ||\n    (userDataFrom.address && userDataFrom.address.sha256_first_name\n      ? userDataFrom.address.sha256_first_name\n      : undefined) ||\n    (userDataFrom.address && userDataFrom.address[0] && userDataFrom.address[0].sha256_first_name\n      ? userDataFrom.address[0].sha256_first_name\n      : undefined) ||\n    (userDataFrom.address && userDataFrom.address.first_name\n      ? userDataFrom.address.first_name\n      : undefined) ||\n    (userDataFrom.address && userDataFrom.address[0] && userDataFrom.address[0].first_name\n      ? userDataFrom.address[0].first_name\n      : undefined);\n  if (firstName) userData.fn = firstName;\n\n  const lastName =\n    userDataFrom.lastName ||\n    userDataFrom.nameLast ||\n    userDataFrom.last_name ||\n    userDataFrom.ln ||\n    (userDataFrom.address && userDataFrom.address.sha256_last_name\n      ? userDataFrom.address.sha256_last_name\n      : undefined) ||\n    (userDataFrom.address && userDataFrom.address[0] && userDataFrom.address[0].sha256_last_name\n      ? userDataFrom.address[0].sha256_last_name\n      : undefined) ||\n    (userDataFrom.address && userDataFrom.address.last_name\n      ? userDataFrom.address.last_name\n      : undefined) ||\n    (userDataFrom.address && userDataFrom.address[0] && userDataFrom.address[0].last_name\n      ? userDataFrom.address[0].last_name\n      : undefined);\n  if (lastName) userData.ln = lastName;\n\n  if (userDataFrom.ge) userData.ge = userDataFrom.ge;\n  if (userDataFrom.db) userData.db = userDataFrom.db;\n\n  const city =\n    userDataFrom.city ||\n    userDataFrom.ct ||\n    (userDataFrom.address && userDataFrom.address.city ? userDataFrom.address.city : undefined) ||\n    (userDataFrom.address && userDataFrom.address[0] && userDataFrom.address[0].city\n      ? userDataFrom.address[0].city\n      : undefined);\n  if (city) userData.ct = city;\n\n  const state =\n    userDataFrom.state ||\n    userDataFrom.region ||\n    userDataFrom.st ||\n    (userDataFrom.address && userDataFrom.address.state ? userDataFrom.address.state : undefined) ||\n    (userDataFrom.address && userDataFrom.address[0] && userDataFrom.address[0].state\n      ? userDataFrom.address[0].state\n      : undefined) ||\n    (userDataFrom.address && userDataFrom.address.region\n      ? userDataFrom.address.region\n      : undefined) ||\n    (userDataFrom.address && userDataFrom.address[0] && userDataFrom.address[0].region\n      ? userDataFrom.address[0].region\n      : undefined);\n  if (state) userData.st = state;\n\n  const zip =\n    userDataFrom.zip ||\n    userDataFrom.postal_code ||\n    userDataFrom.zp ||\n    (userDataFrom.address && userDataFrom.address.postal_code\n      ? userDataFrom.address.postal_code\n      : undefined) ||\n    (userDataFrom.address && userDataFrom.address[0] && userDataFrom.address[0].postal_code\n      ? userDataFrom.address[0].postal_code\n      : undefined) ||\n    (userDataFrom.address && userDataFrom.address.zip ? userDataFrom.address.zip : undefined) ||\n    (userDataFrom.address && userDataFrom.address[0] && userDataFrom.address[0].zip\n      ? userDataFrom.address[0].zip\n      : undefined);\n  if (zip) userData.zp = zip;\n\n  const country =\n    userDataFrom.country ||\n    (userDataFrom.address && userDataFrom.address.country\n      ? userDataFrom.address.country\n      : undefined) ||\n    (userDataFrom.address && userDataFrom.address[0] && userDataFrom.address[0].country\n      ? userDataFrom.address[0].country\n      : undefined);\n  if (country) userData.country = country;\n\n  const externalId =\n    userDataFrom.external_id ||\n    userDataFrom.user_id ||\n    userDataFrom.userId ||\n    (useDL ? getDL('external_id') || getDL('user_id') || getDL('userId') || undefined : undefined);\n  if (externalId) userData.external_id = externalId;\n\n  return userData;\n}\n\nfunction getUAEventData(eventName, objectProperties, ecommerce) {\n  const eventActionMap = {\n    ViewContent: 'detail',\n    AddToCart: 'add',\n    InitiateCheckout: 'checkout',\n    Purchase: 'purchase'\n  };\n\n  if (eventActionMap[eventName]) {\n    const action = eventActionMap[eventName];\n\n    if (\n      ecommerce[action] &&\n      ecommerce[action].products &&\n      getType(ecommerce[action].products) === 'array'\n    ) {\n      objectProperties = {\n        content_type: 'product',\n        contents: ecommerce[action].products.map((prod) => ({\n          id: prod.id,\n          quantity: makeNumber(prod.quantity) || 1,\n          item_price: makeNumber(prod.price)\n        })),\n        content_ids: ecommerce[action].products.map((prod) => prod.id),\n        value: ecommerce[action].products.reduce((acc, cur) => {\n          const curVal = math.round(makeNumber(cur.price || 0) * (cur.quantity || 1) * 100) / 100;\n          return acc + curVal;\n        }, 0.0),\n        currency: ecommerce.currencyCode || 'USD'\n      };\n\n      if (['InitiateCheckout', 'Purchase'].indexOf(eventName) > -1)\n        objectProperties.num_items = ecommerce[action].products.reduce((acc, cur) => {\n          return acc + makeNumber(cur.quantity || 1);\n        }, 0);\n    }\n  }\n\n  return objectProperties;\n}\n\nfunction getGA4EventData(eventName, objectProperties, ecommerce) {\n  const items = getDL('items') || ecommerce.items;\n  let currencyFromItems = '';\n  let valueFromItems = 0;\n\n  if (items && items[0]) {\n    objectProperties.contents = [];\n    objectProperties.content_ids = [];\n    objectProperties.content_type = 'product';\n    if (['InitiateCheckout', 'Purchase'].indexOf(eventName) > -1) {\n      objectProperties.num_items = 0;\n    }\n    currencyFromItems = items[0].currency;\n\n    if (!items[1]) {\n      if (items[0].item_name) objectProperties.content_name = items[0].item_name;\n      if (items[0].item_category) objectProperties.content_category = items[0].item_category;\n      if (items[0].price)\n        objectProperties.value = items[0].quantity\n          ? items[0].quantity * items[0].price\n          : items[0].price;\n    }\n\n    items.forEach((d) => {\n      const content = {};\n      if (d.item_id) content.id = d.item_id;\n      content.quantity = makeNumber(d.quantity) || 1;\n\n      if (d.price) {\n        const item_price = makeNumber(d.price);\n        valueFromItems += d.quantity ? d.quantity * item_price : item_price;\n        content.item_price = item_price;\n      }\n\n      objectProperties.contents.push(content);\n      objectProperties.content_ids.push(content.id);\n      if (['InitiateCheckout', 'Purchase'].indexOf(eventName) > -1) {\n        objectProperties.num_items = objectProperties.num_items + content.quantity || 1;\n      }\n    });\n  }\n\n  const value = ecommerce.value || valueFromItems || getDL('value');\n  if (value) objectProperties.value = value;\n\n  const currency = ecommerce.currency || currencyFromItems || getDL('currency');\n  if (currency) objectProperties.currency = currency;\n\n  const searchTerm = getDL('search_term');\n  if (searchTerm) objectProperties.search_string = searchTerm;\n\n  if (eventName === 'Purchase') {\n    if (!objectProperties.currency) objectProperties.currency = 'USD';\n    if (!objectProperties.value) objectProperties.value = valueFromItems ? valueFromItems : 0;\n  }\n\n  return objectProperties;\n}\n\nfunction getDL(name) {\n  const dataLayerVersion = data.enableCurrentDataLayerOnly ? 1 : 2;\n  return copyFromDataLayer(name, dataLayerVersion);\n}\n\nfunction loadScripts(isParamBuilderSdkEnabled) {\n  injectScript(\n    'https://connect.facebook.net/en_US/fbevents.js',\n    () => {\n      setFbqConsent('grant'); // It needs to be called to unlock the queue after the SDK loads.\n      return gtmOnSuccess();\n    },\n    gtmOnFailure,\n    'metaPixel'\n  );\n\n  const isParamBuilderSdkLoadedOrLoading = !!copyFromWindow('_meta_param_builder_sdk_status');\n  if (isParamBuilderSdkEnabled && !isParamBuilderSdkLoadedOrLoading && !isMagento2Checkout()) {\n    setInWindow('_meta_param_builder_sdk_status', 'loading', true);\n    injectScript(\n      'https://unpkg.com/meta-capi-param-builder-clientjs/dist/clientParamBuilder.bundle.js',\n      () => {\n        setInWindow('_meta_param_builder_sdk_status', 'loaded', true);\n        if (copyFromWindow('clientParamBuilder.processAndCollectAllParams')) {\n          callInWindow('clientParamBuilder.processAndCollectAllParams');\n        } else if (copyFromWindow('clientParamBuilder.processAndCollectParams')) {\n          callInWindow('clientParamBuilder.processAndCollectParams');\n        }\n      },\n      () => {\n        setInWindow('_meta_param_builder_sdk_status', undefined, true);\n      },\n      'metaParamBuilderSdk'\n    );\n  }\n}\n\n/*==============================================================================\n  Helpers\n==============================================================================*/\n\nfunction mergeObjects(obj1, obj2) {\n  Object.keys(obj2).forEach((key) => {\n    obj1[key] = obj2[key];\n  });\n\n  return obj1;\n}\n\nfunction objHasProps(obj) {\n  return getType(obj) === 'object' && Object.keys(obj).length > 0;\n}\n\nfunction objIsEmptyOrContainsOnlyFalsyValues(obj) {\n  if (getType(obj) !== 'object') return;\n  const objValues = Object.values(obj);\n  if (objValues.length === 0 || objValues.every((v) => !v)) return true;\n}\n\nfunction isHashed(value) {\n  if (!value) return false;\n  return makeString(value).match('^[A-Fa-f0-9]{64}$') !== null;\n}\n\nfunction normalizePhoneNumber(phoneNumber) {\n  if (!phoneNumber) return phoneNumber;\n  return makeString(phoneNumber)\n    .split('+')\n    .join('')\n    .split(' ')\n    .join('')\n    .split('-')\n    .join('')\n    .split('(')\n    .join('')\n    .split(')')\n    .join('');\n}\n\nfunction removeWhiteSpace(input) {\n  if (!input) return input;\n  return makeString(input).split(' ').join('');\n}\n\nfunction isMagento2Checkout() {\n  const checkoutConfig = copyFromWindow('checkoutConfig');\n\n  return (\n    getType(checkoutConfig) === 'object' &&\n    getType(checkoutConfig.quoteData) === 'object' &&\n    checkoutConfig.hasOwnProperty('defaultSuccessPageUrl') &&\n    checkoutConfig.hasOwnProperty('storeCode')\n  );\n}\n\n\n___WEB_PERMISSIONS___\n\n[\n  {\n    \"instance\": {\n      \"key\": {\n        \"publicId\": \"access_globals\",\n        \"versionId\": \"1\"\n      },\n      \"param\": [\n        {\n          \"key\": \"keys\",\n          \"value\": {\n            \"type\": 2,\n            \"listItem\": [\n              {\n                \"type\": 3,\n                \"mapKey\": [\n                  {\n                    \"type\": 1,\n                    \"string\": \"key\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"read\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"write\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"execute\"\n                  }\n                ],\n                \"mapValue\": [\n                  {\n                    \"type\": 1,\n                    \"string\": \"fbq\"\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": true\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": true\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": false\n                  }\n                ]\n              },\n              {\n                \"type\": 3,\n                \"mapKey\": [\n                  {\n                    \"type\": 1,\n                    \"string\": \"key\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"read\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"write\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"execute\"\n                  }\n                ],\n                \"mapValue\": [\n                  {\n                    \"type\": 1,\n                    \"string\": \"_meta_gtm_ids\"\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": true\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": true\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": false\n                  }\n                ]\n              },\n              {\n                \"type\": 3,\n                \"mapKey\": [\n                  {\n                    \"type\": 1,\n                    \"string\": \"key\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"read\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"write\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"execute\"\n                  }\n                ],\n                \"mapValue\": [\n                  {\n                    \"type\": 1,\n                    \"string\": \"_fbq\"\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": false\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": true\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": false\n                  }\n                ]\n              },\n              {\n                \"type\": 3,\n                \"mapKey\": [\n                  {\n                    \"type\": 1,\n                    \"string\": \"key\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"read\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"write\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"execute\"\n                  }\n                ],\n                \"mapValue\": [\n                  {\n                    \"type\": 1,\n                    \"string\": \"fbq.callMethod.apply\"\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": true\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": false\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": true\n                  }\n                ]\n              },\n              {\n                \"type\": 3,\n                \"mapKey\": [\n                  {\n                    \"type\": 1,\n                    \"string\": \"key\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"read\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"write\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"execute\"\n                  }\n                ],\n                \"mapValue\": [\n                  {\n                    \"type\": 1,\n                    \"string\": \"fbq.queue.push\"\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": false\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": false\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": true\n                  }\n                ]\n              },\n              {\n                \"type\": 3,\n                \"mapKey\": [\n                  {\n                    \"type\": 1,\n                    \"string\": \"key\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"read\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"write\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"execute\"\n                  }\n                ],\n                \"mapValue\": [\n                  {\n                    \"type\": 1,\n                    \"string\": \"fbq.queue\"\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": true\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": true\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": false\n                  }\n                ]\n              },\n              {\n                \"type\": 3,\n                \"mapKey\": [\n                  {\n                    \"type\": 1,\n                    \"string\": \"key\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"read\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"write\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"execute\"\n                  }\n                ],\n                \"mapValue\": [\n                  {\n                    \"type\": 1,\n                    \"string\": \"fbq.disablePushState\"\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": true\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": true\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": false\n                  }\n                ]\n              },\n              {\n                \"type\": 3,\n                \"mapKey\": [\n                  {\n                    \"type\": 1,\n                    \"string\": \"key\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"read\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"write\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"execute\"\n                  }\n                ],\n                \"mapValue\": [\n                  {\n                    \"type\": 1,\n                    \"string\": \"dataLayer\"\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": true\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": true\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": true\n                  }\n                ]\n              },\n              {\n                \"type\": 3,\n                \"mapKey\": [\n                  {\n                    \"type\": 1,\n                    \"string\": \"key\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"read\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"write\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"execute\"\n                  }\n                ],\n                \"mapValue\": [\n                  {\n                    \"type\": 1,\n                    \"string\": \"dataTag256\"\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": true\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": false\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": true\n                  }\n                ]\n              },\n              {\n                \"type\": 3,\n                \"mapKey\": [\n                  {\n                    \"type\": 1,\n                    \"string\": \"key\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"read\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"write\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"execute\"\n                  }\n                ],\n                \"mapValue\": [\n                  {\n                    \"type\": 1,\n                    \"string\": \"clientParamBuilder.processAndCollectAllParams\"\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": true\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": false\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": true\n                  }\n                ]\n              },\n              {\n                \"type\": 3,\n                \"mapKey\": [\n                  {\n                    \"type\": 1,\n                    \"string\": \"key\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"read\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"write\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"execute\"\n                  }\n                ],\n                \"mapValue\": [\n                  {\n                    \"type\": 1,\n                    \"string\": \"clientParamBuilder.processAndCollectParams\"\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": true\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": false\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": true\n                  }\n                ]\n              },\n              {\n                \"type\": 3,\n                \"mapKey\": [\n                  {\n                    \"type\": 1,\n                    \"string\": \"key\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"read\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"write\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"execute\"\n                  }\n                ],\n                \"mapValue\": [\n                  {\n                    \"type\": 1,\n                    \"string\": \"_meta_param_builder_sdk_status\"\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": true\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": true\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": false\n                  }\n                ]\n              },\n              {\n                \"type\": 3,\n                \"mapKey\": [\n                  {\n                    \"type\": 1,\n                    \"string\": \"key\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"read\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"write\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"execute\"\n                  }\n                ],\n                \"mapValue\": [\n                  {\n                    \"type\": 1,\n                    \"string\": \"checkoutConfig\"\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": true\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": false\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": false\n                  }\n                ]\n              }\n            ]\n          }\n        }\n      ]\n    },\n    \"clientAnnotations\": {\n      \"isEditedByUser\": true\n    },\n    \"isRequired\": true\n  },\n  {\n    \"instance\": {\n      \"key\": {\n        \"publicId\": \"read_data_layer\",\n        \"versionId\": \"1\"\n      },\n      \"param\": [\n        {\n          \"key\": \"allowedKeys\",\n          \"value\": {\n            \"type\": 1,\n            \"string\": \"any\"\n          }\n        }\n      ]\n    },\n    \"clientAnnotations\": {\n      \"isEditedByUser\": true\n    },\n    \"isRequired\": true\n  },\n  {\n    \"instance\": {\n      \"key\": {\n        \"publicId\": \"inject_script\",\n        \"versionId\": \"1\"\n      },\n      \"param\": [\n        {\n          \"key\": \"urls\",\n          \"value\": {\n            \"type\": 2,\n            \"listItem\": [\n              {\n                \"type\": 1,\n                \"string\": \"https://connect.facebook.net/en_US/fbevents.js\"\n              },\n              {\n                \"type\": 1,\n                \"string\": \"https://unpkg.com/meta-capi-param-builder-clientjs/dist/clientParamBuilder.bundle.js\"\n              }\n            ]\n          }\n        }\n      ]\n    },\n    \"clientAnnotations\": {\n      \"isEditedByUser\": true\n    },\n    \"isRequired\": true\n  },\n  {\n    \"instance\": {\n      \"key\": {\n        \"publicId\": \"access_local_storage\",\n        \"versionId\": \"1\"\n      },\n      \"param\": [\n        {\n          \"key\": \"keys\",\n          \"value\": {\n            \"type\": 2,\n            \"listItem\": [\n              {\n                \"type\": 3,\n                \"mapKey\": [\n                  {\n                    \"type\": 1,\n                    \"string\": \"key\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"read\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"write\"\n                  }\n                ],\n                \"mapValue\": [\n                  {\n                    \"type\": 1,\n                    \"string\": \"gtmeec\"\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": true\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": true\n                  }\n                ]\n              }\n            ]\n          }\n        }\n      ]\n    },\n    \"clientAnnotations\": {\n      \"isEditedByUser\": true\n    },\n    \"isRequired\": true\n  },\n  {\n    \"instance\": {\n      \"key\": {\n        \"publicId\": \"access_consent\",\n        \"versionId\": \"1\"\n      },\n      \"param\": [\n        {\n          \"key\": \"consentTypes\",\n          \"value\": {\n            \"type\": 2,\n            \"listItem\": [\n              {\n                \"type\": 3,\n                \"mapKey\": [\n                  {\n                    \"type\": 1,\n                    \"string\": \"consentType\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"read\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"write\"\n                  }\n                ],\n                \"mapValue\": [\n                  {\n                    \"type\": 1,\n                    \"string\": \"ad_storage\"\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": true\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": false\n                  }\n                ]\n              }\n            ]\n          }\n        }\n      ]\n    },\n    \"clientAnnotations\": {\n      \"isEditedByUser\": true\n    },\n    \"isRequired\": true\n  },\n  {\n    \"instance\": {\n      \"key\": {\n        \"publicId\": \"access_template_storage\",\n        \"versionId\": \"1\"\n      },\n      \"param\": []\n    },\n    \"isRequired\": true\n  }\n]\n\n\n___TESTS___\n\nscenarios:\n- name: '[Happy Path] PageView fires init, agent, trackSingle and injects both scripts'\n  code: |-\n    runCode(mockData);\n\n    const consentGrants = fbqCalls.filter((c) => c[0] === 'consent' && c[1] === 'grant');\n    assertThat(consentGrants.length).isGreaterThan(0);\n\n    const initCalls = fbqCalls.filter((c) => c[0] === 'init');\n    assertThat(initCalls.length).isEqualTo(1);\n    assertThat(initCalls[0][1]).isEqualTo('123456789');\n\n    const agentCalls = fbqCalls.filter((c) => c[0] === 'set' && c[1] === 'agent');\n    assertThat(agentCalls.length).isEqualTo(1);\n    assertThat(agentCalls[0][2]).isEqualTo(PARTNER_AGENT_VERSION + '-pb');\n    assertThat(agentCalls[0][3]).isEqualTo('123456789');\n\n    const trackCalls = fbqCalls.filter((c) => c[0] === 'trackSingle');\n    assertThat(trackCalls.length).isEqualTo(1);\n    assertThat(trackCalls[0][1]).isEqualTo('123456789');\n    assertThat(trackCalls[0][2]).isEqualTo('PageView');\n\n    assertThat(injectScriptCalls.length).isEqualTo(2);\n    assertThat(injectScriptCalls[0].url).isEqualTo('https://connect.facebook.net/en_US/fbevents.js');\n    assertThat(injectScriptCalls[1].url).isEqualTo('https://unpkg.com/meta-capi-param-builder-clientjs/dist/clientParamBuilder.bundle.js');\n\n    assertApi('gtmOnSuccess').wasCalled();\n    assertApi('gtmOnFailure').wasNotCalled();\n- name: '[Multiple Pixels] Each pixel gets separate init, agent, and track calls'\n  code: |-\n    mockData.pixelIds = '111,222,333';\n\n    runCode(mockData);\n\n    const initCalls = fbqCalls.filter((c) => c[0] === 'init');\n    assertThat(initCalls.length).isEqualTo(3);\n    assertThat(initCalls[0][1]).isEqualTo('111');\n    assertThat(initCalls[1][1]).isEqualTo('222');\n    assertThat(initCalls[2][1]).isEqualTo('333');\n\n    const trackCalls = fbqCalls.filter((c) => c[0] === 'trackSingle');\n    assertThat(trackCalls.length).isEqualTo(3);\n    assertThat(trackCalls[0][1]).isEqualTo('111');\n    assertThat(trackCalls[1][1]).isEqualTo('222');\n    assertThat(trackCalls[2][1]).isEqualTo('333');\n\n    const agentCalls = fbqCalls.filter((c) => c[0] === 'set' && c[1] === 'agent');\n    assertThat(agentCalls.length).isEqualTo(3);\n\n    assertApi('gtmOnSuccess').wasCalled();\n    assertApi('gtmOnFailure').wasNotCalled();\n- name: '[Consent] Manual consent=false revokes fbq and calls gtmOnSuccess without\n    scripts'\n  code: |-\n    mockData.consent = false;\n\n    runCode(mockData);\n\n    const revokeCalls = fbqCalls.filter((c) => c[0] === 'consent' && c[1] === 'revoke');\n    assertThat(revokeCalls.length).isEqualTo(1);\n\n    const grantCalls = fbqCalls.filter((c) => c[0] === 'consent' && c[1] === 'grant');\n    assertThat(grantCalls.length).isEqualTo(0);\n\n    assertThat(injectScriptCalls.length).isEqualTo(0);\n\n    assertApi('gtmOnSuccess').wasCalled();\n    assertApi('gtmOnFailure').wasNotCalled();\n- name: '[Consent] GTM consent mode denied revokes and calls gtmOnSuccess without\n    scripts'\n  code: |-\n    mockData.enableConsentMode = true;\n    mock('isConsentGranted', () => false);\n\n    runCode(mockData);\n\n    const revokeCalls = fbqCalls.filter((c) => c[0] === 'consent' && c[1] === 'revoke');\n    assertThat(revokeCalls.length).isEqualTo(1);\n\n    assertThat(injectScriptCalls.length).isEqualTo(0);\n\n    assertApi('addConsentListener').wasCalled();\n    assertApi('gtmOnSuccess').wasCalled();\n    assertApi('gtmOnFailure').wasNotCalled();\n- name: '[Consent] Listener fires queued callbacks when consent is later granted'\n  code: |-\n    mockData.enableConsentMode = true;\n    mock('isConsentGranted', () => false);\n\n    let consentListenerCallback;\n    mock('addConsentListener', (type, callback) => {\n      consentListenerCallback = callback;\n    });\n\n    runCode(mockData);\n\n    assertThat(injectScriptCalls.length).isEqualTo(0);\n    assertApi('gtmOnSuccess').wasCalled();\n    assertApi('gtmOnFailure').wasNotCalled();\n\n    consentListenerCallback('ad_storage', true);\n\n    assertThat(injectScriptCalls.length).isEqualTo(2);\n    assertThat(injectScriptCalls[0].url).isEqualTo('https://connect.facebook.net/en_US/fbevents.js');\n\n    const grantCalls = fbqCalls.filter((c) => c[0] === 'consent' && c[1] === 'grant');\n    assertThat(grantCalls.length).isGreaterThan(0);\n- name: '[Consent] setFbqConsent skips duplicate revoke when one is already queued'\n  code: |-\n    const mockFbqWithQueue = function() {\n      const args = [];\n      for (let i = 0; i < arguments.length; i++) {\n        args.push(arguments[i]);\n      }\n      fbqCalls.push(args);\n    };\n    mockFbqWithQueue.queue = [['consent', 'revoke']];\n\n    mock('copyFromWindow', (key) => {\n      if (key === 'fbq') return mockFbqWithQueue;\n      return undefined;\n    });\n\n    mockData.consent = false;\n\n    runCode(mockData);\n\n    const revokeCalls = fbqCalls.filter((c) => c[0] === 'consent' && c[1] === 'revoke');\n    assertThat(revokeCalls.length).isEqualTo(0);\n\n    assertApi('gtmOnSuccess').wasCalled();\n    assertApi('gtmOnFailure').wasNotCalled();\n- name: '[Consent] LDU sets dataProcessingOptions with country and state'\n  code: |-\n    mockData.dpoLDU = true;\n    mockData.dpoCountry = '1';\n    mockData.dpoState = '1000';\n\n    runCode(mockData);\n\n    const dpoCalls = fbqCalls.filter((c) => c[0] === 'dataProcessingOptions');\n    assertThat(dpoCalls.length).isEqualTo(1);\n    assertThat(dpoCalls[0][1]).isEqualTo(['LDU']);\n    assertThat(dpoCalls[0][2]).isEqualTo(1);\n    assertThat(dpoCalls[0][3]).isEqualTo(1000);\n\n    assertApi('gtmOnSuccess').wasCalled();\n    assertApi('gtmOnFailure').wasNotCalled();\n- name: '[Event Name] Maps GA4, stape, and gtm4wp events from DataLayer'\n  code: |-\n    [\n      { dlEvent: 'page_view', expected: 'PageView' },\n      { dlEvent: 'add_to_cart', expected: 'AddToCart' },\n      { dlEvent: 'purchase', expected: 'Purchase' },\n      { dlEvent: 'begin_checkout', expected: 'InitiateCheckout' },\n      { dlEvent: 'view_item', expected: 'ViewContent' },\n      { dlEvent: 'sign_up', expected: 'CompleteRegistration' },\n      { dlEvent: 'generate_lead', expected: 'Lead' },\n      { dlEvent: 'search', expected: 'Search' },\n      { dlEvent: 'add_to_wishlist', expected: 'AddToWishlist' },\n      { dlEvent: 'contact', expected: 'Contact' },\n      { dlEvent: 'subscribe', expected: 'Subscribe' },\n      { dlEvent: 'page_view_stape', expected: 'PageView' },\n      { dlEvent: 'purchase_stape', expected: 'Purchase' },\n      { dlEvent: 'add_to_cart_stape', expected: 'AddToCart' },\n      { dlEvent: 'gtm4wp.orderCompletedEEC', expected: 'Purchase' },\n      { dlEvent: 'gtm4wp.addProductToCartEEC', expected: 'AddToCart' },\n      { dlEvent: 'gtm4wp.productClickEEC', expected: 'ViewContent' }\n    ].forEach((scenario) => {\n      fbqCalls = [];\n      injectScriptCalls = [];\n\n      const testData = assign(assign({}, mockData), { inheritEventName: 'inherit' });\n\n      mock('copyFromDataLayer', (key) => {\n        if (key === 'event') return scenario.dlEvent;\n        return undefined;\n      });\n\n      mock('injectScript', (url, onsuccess) => {\n        injectScriptCalls.push({ url: url });\n        onsuccess();\n      });\n\n      runCode(testData);\n\n      const trackCalls = fbqCalls.filter((c) => c[0] === 'trackSingle' || c[0] === 'trackSingleCustom');\n      assertThat(trackCalls.length).isEqualTo(1);\n      assertThat(trackCalls[0][2]).isEqualTo(scenario.expected);\n\n      assertApi('gtmOnSuccess').wasCalled();\n      assertApi('gtmOnFailure').wasNotCalled();\n    });\n- name: '[Event Name] Unmapped event from DataLayer passes through as-is'\n  code: |-\n    mockData.inheritEventName = 'inherit';\n\n    mock('copyFromDataLayer', (key) => {\n      if (key === 'event') return 'my_custom_dl_event';\n      return undefined;\n    });\n\n    runCode(mockData);\n\n    const trackCalls = fbqCalls.filter((c) => c[0] === 'trackSingleCustom');\n    assertThat(trackCalls.length).isEqualTo(1);\n    assertThat(trackCalls[0][2]).isEqualTo('my_custom_dl_event');\n\n    assertApi('gtmOnSuccess').wasCalled();\n    assertApi('gtmOnFailure').wasNotCalled();\n- name: '[Event Name] UA ecommerce fallback when no DL event name'\n  code: |-\n    [\n      { ecommerceKey: 'detail', expected: 'ViewContent' },\n      { ecommerceKey: 'add', expected: 'AddToCart' },\n      { ecommerceKey: 'checkout', expected: 'InitiateCheckout' },\n      { ecommerceKey: 'purchase', expected: 'Purchase' }\n    ].forEach((scenario) => {\n      fbqCalls = [];\n      injectScriptCalls = [];\n\n      const testData = assign(assign({}, mockData), { inheritEventName: 'inherit' });\n      const ecommerceData = {};\n      ecommerceData[scenario.ecommerceKey] = true;\n\n      mock('copyFromDataLayer', (key, version) => {\n        if (key === 'event') return undefined;\n        if (key === 'ecommerce' && version === 1) return ecommerceData;\n        return undefined;\n      });\n\n      mock('injectScript', (url, onsuccess) => {\n        injectScriptCalls.push({ url: url });\n        onsuccess();\n      });\n\n      runCode(testData);\n\n      const trackCalls = fbqCalls.filter((c) => c[0] === 'trackSingle');\n      assertThat(trackCalls.length).isEqualTo(1);\n      assertThat(trackCalls[0][2]).isEqualTo(scenario.expected);\n\n      assertApi('gtmOnSuccess').wasCalled();\n      assertApi('gtmOnFailure').wasNotCalled();\n    });\n- name: '[Event Name] Override with standard and custom event types'\n  code: |-\n    const testData1 = assign(assign({}, mockData), {\n      inheritEventName: 'override',\n      eventName: 'standard',\n      eventNameStandard: 'AddToCart'\n    });\n\n    runCode(testData1);\n\n    let trackCalls = fbqCalls.filter((c) => c[0] === 'trackSingle');\n    assertThat(trackCalls.length).isEqualTo(1);\n    assertThat(trackCalls[0][2]).isEqualTo('AddToCart');\n\n    assertApi('gtmOnSuccess').wasCalled();\n    assertApi('gtmOnFailure').wasNotCalled();\n\n    fbqCalls = [];\n    injectScriptCalls = [];\n\n    const testData2 = assign(assign({}, mockData), {\n      inheritEventName: 'override',\n      eventName: 'custom',\n      eventNameCustom: 'MyCustomEvent'\n    });\n\n    mock('injectScript', (url, onsuccess) => {\n      injectScriptCalls.push({ url: url });\n      onsuccess();\n    });\n\n    runCode(testData2);\n\n    trackCalls = fbqCalls.filter((c) => c[0] === 'trackSingleCustom');\n    assertThat(trackCalls.length).isEqualTo(1);\n    assertThat(trackCalls[0][2]).isEqualTo('MyCustomEvent');\n\n    assertApi('gtmOnSuccess').wasCalled();\n    assertApi('gtmOnFailure').wasNotCalled();\n- name: '[Pixel Init] Already initialized pixel skips re-init and settings'\n  code: |-\n    mock('copyFromWindow', (key) => {\n      if (key === 'fbq') return mockFbq;\n      if (key === '_meta_gtm_ids') return ['123456789'];\n      return undefined;\n    });\n\n    runCode(mockData);\n\n    const initCalls = fbqCalls.filter((c) => c[0] === 'init');\n    assertThat(initCalls.length).isEqualTo(0);\n\n    const autoConfigCalls = fbqCalls.filter((c) => c[0] === 'set' && c[1] === 'autoConfig');\n    assertThat(autoConfigCalls.length).isEqualTo(0);\n\n    const trackCalls = fbqCalls.filter((c) => c[0] === 'trackSingle');\n    assertThat(trackCalls.length).isEqualTo(1);\n\n    assertApi('gtmOnSuccess').wasCalled();\n    assertApi('gtmOnFailure').wasNotCalled();\n- name: '[Advanced Matching] User data from variable and table merged into init'\n  code: |-\n    const testData = assign(assign({}, mockData), {\n      enableEdvancedMatching: true,\n      userDataFromVariable: { email: 'test@example.com', phone: '1234567890' },\n      userDataList: [{ name: 'fn', value: 'John' }, { name: 'ln', value: 'Doe' }]\n    });\n\n    runCode(testData);\n\n    const initCalls = fbqCalls.filter((c) => c[0] === 'init');\n    assertThat(initCalls.length).isEqualTo(1);\n\n    const userData = initCalls[0][2];\n    assertThat(userData.em).isEqualTo('test@example.com');\n    assertThat(userData.ph).isEqualTo('1234567890');\n    assertThat(userData.fn).isEqualTo('John');\n    assertThat(userData.ln).isEqualTo('Doe');\n\n    assertApi('gtmOnSuccess').wasCalled();\n    assertApi('gtmOnFailure').wasNotCalled();\n- name: '[Advanced Matching] runInitOnce prevents re-init for initialized pixel'\n  code: |-\n    const testData = assign(assign({}, mockData), {\n      enableEdvancedMatching: true,\n      runInitOnce: true,\n      userDataFromVariable: { email: 'test@example.com' }\n    });\n\n    mock('copyFromWindow', (key) => {\n      if (key === 'fbq') return mockFbq;\n      if (key === '_meta_gtm_ids') return ['123456789'];\n      return undefined;\n    });\n\n    runCode(testData);\n\n    const initCalls = fbqCalls.filter((c) => c[0] === 'init');\n    assertThat(initCalls.length).isEqualTo(0);\n\n    const trackCalls = fbqCalls.filter((c) => c[0] === 'trackSingle');\n    assertThat(trackCalls.length).isEqualTo(1);\n\n    assertApi('gtmOnSuccess').wasCalled();\n    assertApi('gtmOnFailure').wasNotCalled();\n- name: '[User Data] Parses all fields from DataLayer user_data object'\n  code: |-\n    const testData = assign(assign({}, mockData), {\n      enableEdvancedMatching: true,\n      enableDataLayerMapping: true\n    });\n\n    mock('copyFromDataLayer', (key) => {\n      if (key === 'user_data') return {\n        email: 'dl@example.com',\n        phone: '1555000000',\n        firstName: 'Jane',\n        lastName: 'Smith',\n        city: 'New York',\n        state: 'NY',\n        zip: '10001',\n        country: 'US',\n        external_id: 'ext123',\n        ge: 'f',\n        db: '19900101'\n      };\n      return undefined;\n    });\n\n    runCode(testData);\n\n    const initCalls = fbqCalls.filter((c) => c[0] === 'init');\n    const userData = initCalls[0][2];\n    assertThat(userData.em).isEqualTo('dl@example.com');\n    assertThat(userData.ph).isEqualTo('1555000000');\n    assertThat(userData.fn).isEqualTo('Jane');\n    assertThat(userData.ln).isEqualTo('Smith');\n    assertThat(userData.ct).isEqualTo('New York');\n    assertThat(userData.st).isEqualTo('NY');\n    assertThat(userData.zp).isEqualTo('10001');\n    assertThat(userData.country).isEqualTo('US');\n    assertThat(userData.external_id).isEqualTo('ext123');\n    assertThat(userData.ge).isEqualTo('f');\n    assertThat(userData.db).isEqualTo('19900101');\n\n    assertApi('gtmOnSuccess').wasCalled();\n    assertApi('gtmOnFailure').wasNotCalled();\n- name: '[User Data] Array email and phone values take the first element'\n  code: |-\n    const testData = assign(assign({}, mockData), {\n      enableEdvancedMatching: true,\n      userDataFromVariable: {\n        email: ['first@example.com', 'second@example.com'],\n        phone: ['111', '222']\n      }\n    });\n\n    runCode(testData);\n\n    const initCalls = fbqCalls.filter((c) => c[0] === 'init');\n    const userData = initCalls[0][2];\n    assertThat(userData.em).isEqualTo('first@example.com');\n    assertThat(userData.ph).isEqualTo('111');\n\n    assertApi('gtmOnSuccess').wasCalled();\n    assertApi('gtmOnFailure').wasNotCalled();\n- name: '[User Data] Address-nested fields are parsed correctly'\n  code: |-\n    const testData = assign(assign({}, mockData), {\n      enableEdvancedMatching: true,\n      userDataFromVariable: {\n        address: {\n          first_name: 'Nested',\n          last_name: 'User',\n          city: 'Boston',\n          state: 'MA',\n          postal_code: '02101',\n          country: 'US'\n        }\n      }\n    });\n\n    runCode(testData);\n\n    const initCalls = fbqCalls.filter((c) => c[0] === 'init');\n    const userData = initCalls[0][2];\n    assertThat(userData.fn).isEqualTo('Nested');\n    assertThat(userData.ln).isEqualTo('User');\n    assertThat(userData.ct).isEqualTo('Boston');\n    assertThat(userData.st).isEqualTo('MA');\n    assertThat(userData.zp).isEqualTo('02101');\n    assertThat(userData.country).isEqualTo('US');\n\n    assertApi('gtmOnSuccess').wasCalled();\n    assertApi('gtmOnFailure').wasNotCalled();\n- name: '[User Data] Empty or all-falsy user data returns undefined'\n  code: |-\n    [\n      { description: 'empty object', userData: {} },\n      { description: 'all-falsy values', userData: { email: '', phone: null } }\n    ].forEach((scenario) => {\n      fbqCalls = [];\n      const testData = assign(assign({}, mockData), {\n        enableEdvancedMatching: true,\n        userDataFromVariable: scenario.userData\n      });\n\n      runCode(testData);\n\n      const initCalls = fbqCalls.filter((c) => c[0] === 'init');\n      assertThat(initCalls.length).isEqualTo(1);\n      assertThat(initCalls[0][2]).isUndefined();\n\n      assertApi('gtmOnSuccess').wasCalled();\n      assertApi('gtmOnFailure').wasNotCalled();\n    });\n- name: '[User Data] External ID falls back to DataLayer when useDL is true'\n  code: |-\n    const testData = assign(assign({}, mockData), {\n      enableEdvancedMatching: true,\n      enableDataLayerMapping: true\n    });\n\n    mock('copyFromDataLayer', (key) => {\n      if (key === 'user_data') return { email: 'test@example.com' };\n      if (key === 'external_id') return 'dl-ext-id';\n      return undefined;\n    });\n\n    runCode(testData);\n\n    const initCalls = fbqCalls.filter((c) => c[0] === 'init');\n    const userData = initCalls[0][2];\n    assertThat(userData.external_id).isEqualTo('dl-ext-id');\n\n    assertApi('gtmOnSuccess').wasCalled();\n    assertApi('gtmOnFailure').wasNotCalled();\n- name: '[Event Data] GA4 Purchase with multiple items builds correct properties'\n  code: |-\n    const testData = assign(assign({}, mockData), {\n      eventNameStandard: 'Purchase',\n      enableDataLayerMapping: true\n    });\n\n    mock('copyFromDataLayer', (key) => {\n      if (key === 'items') return [\n        { item_id: 'SKU1', item_name: 'Product 1', price: 10, quantity: 2, currency: 'EUR' },\n        { item_id: 'SKU2', item_name: 'Product 2', price: 25, quantity: 1 }\n      ];\n      if (key === 'value') return 45;\n      if (key === 'currency') return 'EUR';\n      return undefined;\n    });\n\n    runCode(testData);\n\n    const trackCalls = fbqCalls.filter((c) => c[0] === 'trackSingle');\n    assertThat(trackCalls.length).isEqualTo(1);\n\n    const eventData = trackCalls[0][3];\n    assertThat(eventData.content_type).isEqualTo('product');\n    assertThat(eventData.content_ids).isEqualTo(['SKU1', 'SKU2']);\n    assertThat(eventData.contents.length).isEqualTo(2);\n    assertThat(eventData.contents[0].id).isEqualTo('SKU1');\n    assertThat(eventData.contents[0].quantity).isEqualTo(2);\n    assertThat(eventData.contents[1].id).isEqualTo('SKU2');\n    assertThat(eventData.contents[1].quantity).isEqualTo(1);\n    assertThat(eventData.value).isEqualTo(45);\n    assertThat(eventData.currency).isEqualTo('EUR');\n    assertThat(eventData.num_items).isDefined();\n\n    assertApi('gtmOnSuccess').wasCalled();\n    assertApi('gtmOnFailure').wasNotCalled();\n- name: '[Event Data] GA4 single item includes content_name and content_category'\n  code: |-\n    const testData = assign(assign({}, mockData), {\n      eventNameStandard: 'ViewContent',\n      enableDataLayerMapping: true\n    });\n\n    mock('copyFromDataLayer', (key) => {\n      if (key === 'items') return [\n        { item_id: 'SINGLE1', item_name: 'My Product', item_category: 'Electronics', price: 99, quantity: 1 }\n      ];\n      return undefined;\n    });\n\n    runCode(testData);\n\n    const trackCalls = fbqCalls.filter((c) => c[0] === 'trackSingle');\n    const eventData = trackCalls[0][3];\n    assertThat(eventData.content_name).isEqualTo('My Product');\n    assertThat(eventData.content_category).isEqualTo('Electronics');\n    assertThat(eventData.content_type).isEqualTo('product');\n\n    assertApi('gtmOnSuccess').wasCalled();\n    assertApi('gtmOnFailure').wasNotCalled();\n- name: '[Event Data] UA Purchase with products builds correct properties'\n  code: |-\n    const testData = assign(assign({}, mockData), {\n      eventNameStandard: 'Purchase',\n      enableDataLayerMapping: true\n    });\n\n    mock('copyFromDataLayer', (key) => {\n      if (key === 'ecommerce') return {\n        currencyCode: 'GBP',\n        purchase: {\n          products: [\n            { id: 'P1', price: '15.99', quantity: '3' },\n            { id: 'P2', price: '8.50', quantity: '1' }\n          ]\n        }\n      };\n      return undefined;\n    });\n\n    runCode(testData);\n\n    const trackCalls = fbqCalls.filter((c) => c[0] === 'trackSingle');\n    assertThat(trackCalls.length).isEqualTo(1);\n\n    const eventData = trackCalls[0][3];\n    assertThat(eventData.content_type).isEqualTo('product');\n    assertThat(eventData.content_ids).isEqualTo(['P1', 'P2']);\n    assertThat(eventData.currency).isEqualTo('GBP');\n    assertThat(eventData.contents.length).isEqualTo(2);\n    assertThat(eventData.num_items).isDefined();\n\n    assertApi('gtmOnSuccess').wasCalled();\n    assertApi('gtmOnFailure').wasNotCalled();\n- name: '[Event Data] Properties from variable and table list merge correctly'\n  code: |-\n    const testData = assign(assign({}, mockData), {\n      objectPropertiesFromVariable: { content_name: 'My Product', value: 99 },\n      objectPropertiesList: [\n        { name: 'currency', value: 'USD' },\n        { name: 'content_type', value: 'product' }\n      ]\n    });\n\n    runCode(testData);\n\n    const trackCalls = fbqCalls.filter((c) => c[0] === 'trackSingle');\n    const eventData = trackCalls[0][3];\n    assertThat(eventData.content_name).isEqualTo('My Product');\n    assertThat(eventData.value).isEqualTo(99);\n    assertThat(eventData.currency).isEqualTo('USD');\n    assertThat(eventData.content_type).isEqualTo('product');\n\n    assertApi('gtmOnSuccess').wasCalled();\n    assertApi('gtmOnFailure').wasNotCalled();\n- name: '[Event Data] GA4 Search event includes search_string'\n  code: |-\n    const testData = assign(assign({}, mockData), {\n      eventNameStandard: 'Search',\n      enableDataLayerMapping: true\n    });\n\n    mock('copyFromDataLayer', (key) => {\n      if (key === 'search_term') return 'blue shoes';\n      return undefined;\n    });\n\n    runCode(testData);\n\n    const trackCalls = fbqCalls.filter((c) => c[0] === 'trackSingle');\n    const eventData = trackCalls[0][3];\n    assertThat(eventData.search_string).isEqualTo('blue shoes');\n\n    assertApi('gtmOnSuccess').wasCalled();\n    assertApi('gtmOnFailure').wasNotCalled();\n- name: '[Event Data] GA4 Purchase defaults currency to USD and value to 0'\n  code: |-\n    const testData = assign(assign({}, mockData), {\n      eventNameStandard: 'Purchase',\n      enableDataLayerMapping: true\n    });\n\n    mock('copyFromDataLayer', () => undefined);\n\n    runCode(testData);\n\n    const trackCalls = fbqCalls.filter((c) => c[0] === 'trackSingle');\n    const eventData = trackCalls[0][3];\n    assertThat(eventData.currency).isEqualTo('USD');\n    assertThat(eventData.value).isEqualTo(0);\n\n    assertApi('gtmOnSuccess').wasCalled();\n    assertApi('gtmOnFailure').wasNotCalled();\n- name: '[Settings] disableAutoConfig and disablePushState are applied correctly'\n  code: |-\n    const testData = assign(assign({}, mockData), {\n      disableAutoConfig: true,\n      disablePushState: true\n    });\n\n    runCode(testData);\n\n    const autoConfigCalls = fbqCalls.filter((c) => c[0] === 'set' && c[1] === 'autoConfig');\n    assertThat(autoConfigCalls.length).isEqualTo(1);\n    assertThat(autoConfigCalls[0][2]).isFalse();\n    assertThat(autoConfigCalls[0][3]).isEqualTo('123456789');\n\n    const pushStateCalls = setInWindowCalls.filter((c) => c[0] === 'fbq.disablePushState');\n    assertThat(pushStateCalls.length).isEqualTo(1);\n    assertThat(pushStateCalls[0][1]).isTrue();\n\n    assertApi('gtmOnSuccess').wasCalled();\n    assertApi('gtmOnFailure').wasNotCalled();\n- name: '[DataLayer Push] Pushes event with custom and default settings'\n  code: |-\n    [\n      {\n        desc: 'custom name and layer',\n        dataLayerEventName: 'fb_pageview',\n        dataLayerVariableName: 'myDataLayer',\n        eventId: 'evt-123',\n        expectedLayer: 'myDataLayer',\n        expectedEvent: 'fb_pageview'\n      },\n      {\n        desc: 'defaults when not specified',\n        dataLayerEventName: undefined,\n        dataLayerVariableName: undefined,\n        eventId: 'evt-456',\n        expectedLayer: 'dataLayer',\n        expectedEvent: 'DefaultTagEvent'\n      }\n    ].forEach((scenario) => {\n      createQueueItems = [];\n      const testData = assign(assign({}, mockData), {\n        dataLayerEventPush: true,\n        dataLayerEventName: scenario.dataLayerEventName,\n        dataLayerVariableName: scenario.dataLayerVariableName,\n        eventId: scenario.eventId\n      });\n\n      runCode(testData);\n\n      const dlPushes = createQueueItems.filter((c) => c[0] === scenario.expectedLayer);\n      assertThat(dlPushes.length).isEqualTo(1);\n      assertThat(dlPushes[0][1].event).isEqualTo(scenario.expectedEvent);\n      assertThat(dlPushes[0][1].eventId).isEqualTo(scenario.eventId);\n\n      assertApi('gtmOnSuccess').wasCalled();\n      assertApi('gtmOnFailure').wasNotCalled();\n    });\n- name: '[Scripts] Param builder calls processAndCollectAllParams when available'\n  code: |-\n    mock('copyFromWindow', (key) => {\n      if (key === 'fbq') return mockFbq;\n      if (key === 'clientParamBuilder.processAndCollectAllParams') return function() {};\n      return undefined;\n    });\n\n    runCode(mockData);\n\n    assertThat(injectScriptCalls.length).isEqualTo(2);\n    assertApi('callInWindow').wasCalledWith('clientParamBuilder.processAndCollectAllParams');\n    assertApi('gtmOnSuccess').wasCalled();\n    assertApi('gtmOnFailure').wasNotCalled();\n- name: '[Scripts] Param builder disabled injects only fbevents and removes -pb suffix'\n  code: |-\n    const testData = assign(assign({}, mockData), { enableParamBuilderSdk: false });\n\n    runCode(testData);\n\n    assertThat(injectScriptCalls.length).isEqualTo(1);\n    assertThat(injectScriptCalls[0].url).isEqualTo('https://connect.facebook.net/en_US/fbevents.js');\n\n    const agentCalls = fbqCalls.filter((c) => c[0] === 'set' && c[1] === 'agent');\n    assertThat(agentCalls[0][2]).isEqualTo(PARTNER_AGENT_VERSION);\n\n    assertApi('gtmOnSuccess').wasCalled();\n    assertApi('gtmOnFailure').wasNotCalled();\n- name: '[Scripts] Param builder not injected again when already loaded or loading'\n  code: |2-\n       ['loading', 'loaded'].forEach((status) => {\n          injectScriptCalls = [];\n\n          mock('copyFromWindow', (key) => {\n            if (key === 'fbq') return mockFbq;\n            if (key === '_meta_param_builder_sdk_status') return status;\n            return undefined;\n          });\n\n          runCode(mockData);\n\n          assertThat(injectScriptCalls.length).isEqualTo(1);\n          assertThat(injectScriptCalls[0].url).isEqualTo('https://connect.facebook.net/en_US/fbevents.js');\n\n          assertApi('gtmOnSuccess').wasCalled();\n          assertApi('gtmOnFailure').wasNotCalled();\n        });\n- name: '[Scripts] Param builder not injected on Magento 2 Checkout'\n  code: |2-\n       const checkoutConfig = {};\n        checkoutConfig.quoteData = {};\n        checkoutConfig.defaultSuccessPageUrl = '/checkout/success';\n        checkoutConfig.storeCode = 'default';\n\n        mock('copyFromWindow', (key) => {\n          if (key === 'fbq') return mockFbq;\n          if (key === 'checkoutConfig') return checkoutConfig;\n          return undefined;\n        });\n\n        runCode(mockData);\n\n        assertThat(injectScriptCalls.length).isEqualTo(1);\n        assertThat(injectScriptCalls[0].url).isEqualTo('https://connect.facebook.net/en_US/fbevents.js');\n\n        assertApi('gtmOnSuccess').wasCalled();\n        assertApi('gtmOnFailure').wasNotCalled();\n- name: '[Scripts] fbevents failure calls gtmOnFailure'\n  code: |-\n    mock('injectScript', (url, onsuccess, onfailure) => {\n      if (url === 'https://connect.facebook.net/en_US/fbevents.js') {\n        onfailure();\n      }\n    });\n\n    runCode(mockData);\n\n    assertApi('gtmOnSuccess').wasNotCalled();\n    assertApi('gtmOnFailure').wasCalled();\n- name: '[Event Enhancement] Reads stored data from localStorage and writes back'\n  code: |-\n    localStorageData.gtmeec = '{\"em\":\"stored@example.com\"}';\n\n    const testData = assign(assign({}, mockData), {\n      enableEdvancedMatching: true,\n      enableEventEnhancement: true,\n      userDataFromVariable: { ph: '1999999999' }\n    });\n\n    runCode(testData);\n\n    const initCalls = fbqCalls.filter((c) => c[0] === 'init');\n    const userData = initCalls[0][2];\n    assertThat(userData.em).isEqualTo('stored@example.com');\n    assertThat(userData.ph).isEqualTo('1999999999');\n\n    assertThat(localStorageData.gtmeec).isDefined();\n    const stored = JSON.parse(localStorageData.gtmeec);\n    assertThat(stored.em).isEqualTo('stored@example.com');\n    assertThat(stored.ph).isEqualTo('1999999999');\n\n    assertApi('gtmOnSuccess').wasCalled();\n    assertApi('gtmOnFailure').wasNotCalled();\n- name: '[Event Enhancement] Skips localStorage read and write when consent is revoked'\n  code: |-\n    let getItemCalled = false;\n    let setItemCalled = false;\n    mockObject('localStorage', {\n      getItem: (key) => { getItemCalled = true; return localStorageData[key]; },\n      setItem: (key, value) => { setItemCalled = true; localStorageData[key] = value; }\n    });\n\n    localStorageData.gtmeec = '{\"em\":\"stored@example.com\"}';\n\n    const testData = assign(assign({}, mockData), {\n      consent: false,\n      enableEdvancedMatching: true,\n      enableEventEnhancement: true,\n      userDataFromVariable: { ph: '1999999999' }\n    });\n\n    runCode(testData);\n\n    assertThat(getItemCalled).isFalse();\n    assertThat(setItemCalled).isFalse();\n\n    const initCalls = fbqCalls.filter((c) => c[0] === 'init');\n    const userData = initCalls[0][2];\n    assertThat(userData.em).isUndefined();\n    assertThat(userData.ph).isEqualTo('1999999999');\n\n    assertApi('gtmOnSuccess').wasCalled();\n    assertApi('gtmOnFailure').wasNotCalled();\n- name: '[Event Enhancement] Hashed storage calls hashUserDataFields with sync hash'\n  code: |-\n    mock('copyFromWindow', (key) => {\n      if (key === 'fbq') return mockFbq;\n      if (key === 'dataTag256') return function() { return 'abc123hash'; };\n      return undefined;\n    });\n\n    mock('callInWindow', (key) => {\n      if (key === 'dataTag256') return 'abc123hash';\n      return undefined;\n    });\n\n\n    const testData = assign(assign({}, mockData), {\n      enableEdvancedMatching: true,\n      enableEventEnhancement: true,\n      storeUserDataHashed: true,\n      userDataFromVariable: { email: 'test@example.com' }\n    });\n\n    runCode(testData);\n\n    assertThat(localStorageData.gtmeec).isDefined();\n    const stored = JSON.parse(localStorageData.gtmeec);\n    assertThat(stored.em).isEqualTo('abc123hash');\n\n    assertApi('callInWindow').wasCalledWith('dataTag256', 'test@example.com', 'HEX');\n    assertApi('gtmOnSuccess').wasCalled();\n    assertApi('gtmOnFailure').wasNotCalled();\n- name: '[Event Enhancement] Hashed storage with async sha256 stores hashed data'\n  code: |-\n    mock('sha256', (input, successCb, errorCb, options) => {\n      successCb('async_hashed_' + input);\n    });\n\n    mock('copyFromWindow', (key) => {\n      if (key === 'fbq') return mockFbq;\n      return undefined;\n    });\n\n    const testData = assign(assign({}, mockData), {\n      enableEdvancedMatching: true,\n      enableEventEnhancement: true,\n      storeUserDataHashed: true,\n      userDataFromVariable: { email: 'test@example.com' }\n    });\n\n    runCode(testData);\n\n    assertThat(localStorageData.gtmeec).isDefined();\n    const stored = JSON.parse(localStorageData.gtmeec);\n    assertThat(stored.em).isEqualTo('async_hashed_test@example.com');\n\n    assertApi('gtmOnSuccess').wasCalled();\n    assertApi('gtmOnFailure').wasNotCalled();\n- name: '[Event ID] Passes eventID option in track call'\n  code: |-\n    mockData.eventId = 'evt-abc-123';\n\n    runCode(mockData);\n\n    const trackCalls = fbqCalls.filter((c) => c[0] === 'trackSingle');\n    assertThat(trackCalls.length).isEqualTo(1);\n    assertThat(trackCalls[0][4]).isEqualTo({ eventID: 'evt-abc-123' });\n\n    assertApi('gtmOnSuccess').wasCalled();\n    assertApi('gtmOnFailure').wasNotCalled();\n- name: '[Advanced Matching] Re-inits initialized pixel when runInitOnce is false'\n  code: |-\n    const testData = assign(assign({}, mockData), {\n      enableEdvancedMatching: true,\n      runInitOnce: false,\n      userDataFromVariable: { email: 'test@example.com' }\n    });\n\n    mock('copyFromWindow', (key) => {\n      if (key === 'fbq') return mockFbq;\n      if (key === '_meta_gtm_ids') return ['123456789'];\n      return undefined;\n    });\n\n    runCode(testData);\n\n    const initCalls = fbqCalls.filter((c) => c[0] === 'init');\n    assertThat(initCalls.length).isEqualTo(1);\n    assertThat(initCalls[0][2].em).isEqualTo('test@example.com');\n\n    assertApi('gtmOnSuccess').wasCalled();\n    assertApi('gtmOnFailure').wasNotCalled();\n- name: '[DL Version] enableCurrentDataLayerOnly uses DL version 1'\n  code: |-\n    let capturedVersion;\n    mock('copyFromDataLayer', (key, version) => {\n      if (key === 'search_term') {\n        capturedVersion = version;\n        return 'test query';\n      }\n      return undefined;\n    });\n\n    const testData = assign(assign({}, mockData), {\n      enableDataLayerMapping: true,\n      enableCurrentDataLayerOnly: true,\n      eventNameStandard: 'Search'\n    });\n\n    runCode(testData);\n\n    assertThat(capturedVersion).isEqualTo(1);\n\n    assertApi('gtmOnSuccess').wasCalled();\n    assertApi('gtmOnFailure').wasNotCalled();\nsetup: |-\n  const JSON = require('JSON');\n  const Object = require('Object');\n\n  const PARTNER_AGENT_VERSION = 'stape-gtm-1.2.0';\n\n  const assign = (target, source) => {\n    if (!source) return target;\n    Object.keys(source).forEach((key) => { target[key] = source[key]; });\n    return target;\n  };\n\n  let fbqCalls = [];\n  const mockFbq = function() {\n    const args = [];\n    for (let i = 0; i < arguments.length; i++) {\n      args.push(arguments[i]);\n    }\n    fbqCalls.push(args);\n  };\n  mockFbq.queue = [];\n\n  let setInWindowCalls = [];\n  mock('setInWindow', (key, value, override) => {\n    setInWindowCalls.push([key, value, override]);\n  });\n\n  let injectScriptCalls = [];\n  mock('injectScript', (url, onsuccess, onfailure, cacheToken) => {\n    injectScriptCalls.push({ url: url, onsuccess: onsuccess, onfailure: onfailure, cacheToken: cacheToken });\n    onsuccess();\n  });\n\n  mock('copyFromWindow', (key) => {\n    if (key === 'fbq') return mockFbq;\n    return undefined;\n  });\n\n  mock('aliasInWindow', () => true);\n\n  let createQueueItems = [];\n  mock('createQueue', (name) => {\n    return (item) => { createQueueItems.push([name, item]); };\n  });\n\n  mock('copyFromDataLayer', () => undefined);\n  mock('isConsentGranted', () => true);\n  mock('addConsentListener', () => {});\n\n  let templateStorageData = {};\n  mockObject('templateStorage', {\n    getItem: (key) => templateStorageData[key],\n    setItem: (key, value) => { templateStorageData[key] = value; }\n  });\n\n  let localStorageData = {};\n  mockObject('localStorage', {\n    getItem: (key) => localStorageData[key],\n    setItem: (key, value) => { localStorageData[key] = value; }\n  });\n\n  const mockData = {\n    pixelIds: '123456789',\n    consent: true,\n    enableConsentMode: false,\n    inheritEventName: 'override',\n    eventName: 'standard',\n    eventNameStandard: 'PageView',\n    enableDataLayerMapping: false,\n    enableEdvancedMatching: false,\n    enableParamBuilderSdk: true,\n    dpoLDU: false,\n    disableAutoConfig: false,\n    disablePushState: false,\n    dataLayerEventPush: false,\n    enableEventEnhancement: false,\n    storeUserDataHashed: false,\n    runInitOnce: false,\n    enableCurrentDataLayerOnly: false\n  };\n\n\n___NOTES___\n\n2026-06-09 - Change Notes:\n  - Forced casting to string before normalization when storing User Data in hashed format.\n  - Improved legibility of user data presence checking from multiple sources.\n  - Code formatting.\n\n2026-05-13 - Change Notes:\n  - Prevent Param Builder SDK from being re-injected when it is already loading or has loaded, using a window-level status flag (_meta_param_builder_sdk_status)\n  - Skip Param Builder SDK injection on Magento 2 checkout pages to avoid compatibility conflicts\n\n2026-04-09 - Change Notes:\n  - Add optional Meta Parameter Builder SDK integration (enabled by default) to improve _fbp and _fbc cookie coverage, including backup Click ID retrieval from in-app browsers\n  - Add consent-aware event enhancement: user data is now only read from/written to localStorage when consent is granted\n  - Bump version to stape-gtm-1.2.0 (with -pb suffix when Param Builder SDK is active)\n\nCreated on 08/15/2025, 08:58:45 AM\n\n\n",
                "galleryReference": {
                    "host": "github.com",
                    "owner": "stape-io",
                    "repository": "fb-tag",
                    "version": "bbdd7aa222cf69015f717b01c95f1f80621352e9",
                    "signature": "a3069ba2e47368bcfd0c14cc4a888e0c2bed7f004076b48990cb33312de671cb",
                    "galleryTemplateId": "KFNBV"
                }
            },
            {
                "accountId": "6268264869",
                "containerId": "255515747",
                "templateId": "7",
                "name": "TikTok Pixel by Stape",
                "fingerprint": "1781525163482",
                "templateData": "___TERMS_OF_SERVICE___\n\nBy creating or modifying this file you agree to Google Tag Manager's Community\nTemplate Gallery Developer Terms of Service available at\nhttps://developers.google.com/tag-manager/gallery-tos (or such other URL as\nGoogle may provide), as modified from time to time.\n\n\n___INFO___\n\n{\n  \"type\": \"TAG\",\n  \"id\": \"cvt_KF8K9\",\n  \"version\": 1,\n  \"displayName\": \"TikTok Pixel by Stape\",\n  \"categories\": [\n    \"ADVERTISING\",\n    \"ANALYTICS\",\n    \"CONVERSIONS\",\n    \"MARKETING\",\n    \"REMARKETING\"\n  ],\n  \"brand\": {\n    \"id\": \"github.com_stape-io\",\n    \"displayName\": \"stape-io\",\n    \"thumbnail\": \"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAlgAAAJYCAYAAAC+ZpjcAAAphElEQVR4Ae3dfazdd33Y8Y+fn0h8AxlPapLrZh0F4viyVWHjYTERUksDStJ/6kInO0JKB9KII7US1SrZaalAmrY4mQRTJWpnWhH/ORGlndYqdkSpRrViA9lG11I7SSsoCpKdNECeyM7nHN/k+vpe3/PwPef39HpJR8dxbgOirfzm+/n+Pr91EfFyADTMy//u5wKgrtYHAABFCSwAgMIEFgBAYQILAKAwgQUAUJjAAgAoTGABABQmsAAAChNYAACFCSwAgMIEFgBAYQILAKAwgQUAUJjAAgAoTGABABQmsAAAChNYAACFCSwAgMIEFgBAYQILAKAwgQUAUJjAAgAoTGABABQmsAAAChNYAACFCSwAgMIEFgBAYQILAKAwgQUAUJjAAgAoTGABABQmsAAAChNYAACFCSwAgMIEFgBAYQILAKAwgQUAUJjAAgAoTGABABQmsAAAChNYAACFCSwAgMIEFgBAYQILAKAwgQUAUJjAAgAoTGABABQmsAAAChNYAACFCSwAgMIEFgBAYQILAKAwgQUAUJjAAgAoTGABABQmsAAAChNYAACFCSwAgMIEFgBAYQILAKAwgQUAUJjAAgAoTGABABQmsAAAChNYAACFCSwAgMIEFgBAYQILAKAwgQUAUJjAAgAoTGABABQmsAAAChNYAACFCSwAgMIEFgBAYQILAKAwgQUAUJjAAgAoTGABABQmsAAAChNYAACFCSwAgMIEFgBAYQILAKAwgQUAUJjAAgAoTGABABQmsAAAChNYAACFCSwAgMIEFgBAYQILAKAwgQUAUJjAAgAoTGABABQmsAAAChNYAACFCSwAgMIEFgBAYQILAKAwgQUAUJjAAgAoTGABABQmsAAAChNYAACFCSwAgMIEFgBAYQILAKAwgQUAUJjAAgAoTGABABQmsAAAChNYAACFCSwAgMIEFgBAYQILAKAwgQUAUJjAAgAoTGABABQmsAAAChNYAACFCSwAgMIEFgBAYQILAKAwgQUAUJjAAgAoTGABABQmsAAAChNYAACFCSwAgMIEFgBAYQILAKAwgQUAUJjAAgAoTGABABQmsAAAChNYAACFCSwAgMIEFgBAYQILAKAwgQUAUJjAAgAoTGABABQmsAAAChNYAACFCSygkc4+83wA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\\u003d\"\n  },\n  \"description\": \"Tag that integrates TikTok Pixel into the page and allows easy tracking. ✅ Note: this tag does not require the Base Code installed as a Custom HTML tag to work.\",\n  \"containerContexts\": [\n    \"WEB\"\n  ]\n}\n\n\n___TEMPLATE_PARAMETERS___\n\n[\n  {\n    \"type\": \"GROUP\",\n    \"name\": \"baseConfigurationGroup\",\n    \"subParams\": [\n      {\n        \"type\": \"TEXT\",\n        \"name\": \"pixelIds\",\n        \"displayName\": \"TikTok Pixel ID(s)\",\n        \"simpleValueType\": true,\n        \"valueHint\": \"CSQ69...,D69E2...\",\n        \"valueValidators\": [\n          {\n            \"type\": \"NON_EMPTY\"\n          }\n        ],\n        \"help\": \"Array, single item string or comma separated string of Pixel IDs.\",\n        \"alwaysInSummary\": true\n      },\n      {\n        \"type\": \"SELECT\",\n        \"name\": \"eventNameSetupMethod\",\n        \"displayName\": \"Event Name Setup Method\",\n        \"selectItems\": [\n          {\n            \"value\": \"inherit\",\n            \"displayValue\": \"Inherit from DataLayer\"\n          },\n          {\n            \"value\": \"override\",\n            \"displayValue\": \"Override\"\n          }\n        ],\n        \"simpleValueType\": true,\n        \"subParams\": [\n          {\n            \"type\": \"RADIO\",\n            \"name\": \"eventName\",\n            \"radioItems\": [\n              {\n                \"value\": \"standard\",\n                \"displayValue\": \"Standard\",\n                \"subParams\": [\n                  {\n                    \"type\": \"SELECT\",\n                    \"name\": \"eventNameStandard\",\n                    \"macrosInSelect\": false,\n                    \"selectItems\": [\n                      {\n                        \"value\": \"Pageview\",\n                        \"displayValue\": \"Pageview\"\n                      },\n                      {\n                        \"value\": \"AddPaymentInfo\",\n                        \"displayValue\": \"AddPaymentInfo\"\n                      },\n                      {\n                        \"value\": \"AddToCart\",\n                        \"displayValue\": \"AddToCart\"\n                      },\n                      {\n                        \"value\": \"AddToWishlist\",\n                        \"displayValue\": \"AddToWishlist\"\n                      },\n                      {\n                        \"value\": \"ApplicationApproval\",\n                        \"displayValue\": \"ApplicationApproval\"\n                      },\n                      {\n                        \"value\": \"CompleteRegistration\",\n                        \"displayValue\": \"CompleteRegistration\"\n                      },\n                      {\n                        \"value\": \"Contact\",\n                        \"displayValue\": \"Contact\"\n                      },\n                      {\n                        \"value\": \"CustomizeProduct\",\n                        \"displayValue\": \"CustomizeProduct\"\n                      },\n                      {\n                        \"value\": \"Download\",\n                        \"displayValue\": \"Download\"\n                      },\n                      {\n                        \"value\": \"FindLocation\",\n                        \"displayValue\": \"FindLocation\"\n                      },\n                      {\n                        \"value\": \"InitiateCheckout\",\n                        \"displayValue\": \"InitiateCheckout\"\n                      },\n                      {\n                        \"value\": \"Lead\",\n                        \"displayValue\": \"Lead\"\n                      },\n                      {\n                        \"value\": \"Purchase\",\n                        \"displayValue\": \"Purchase\"\n                      },\n                      {\n                        \"value\": \"Schedule\",\n                        \"displayValue\": \"Schedule\"\n                      },\n                      {\n                        \"value\": \"Search\",\n                        \"displayValue\": \"Search\"\n                      },\n                      {\n                        \"value\": \"StartTrial\",\n                        \"displayValue\": \"StartTrial\"\n                      },\n                      {\n                        \"value\": \"SubmitApplication\",\n                        \"displayValue\": \"SubmitApplication\"\n                      },\n                      {\n                        \"value\": \"Subscribe\",\n                        \"displayValue\": \"Subscribe\"\n                      },\n                      {\n                        \"value\": \"ViewContent\",\n                        \"displayValue\": \"ViewContent\"\n                      }\n                    ],\n                    \"simpleValueType\": true,\n                    \"displayName\": \"Event Name\",\n                    \"defaultValue\": \"Pageview\"\n                  }\n                ]\n              },\n              {\n                \"value\": \"custom\",\n                \"displayValue\": \"Custom\",\n                \"subParams\": [\n                  {\n                    \"type\": \"TEXT\",\n                    \"name\": \"eventNameCustom\",\n                    \"simpleValueType\": true,\n                    \"displayName\": \"Event Name\",\n                    \"valueValidators\": [\n                      {\n                        \"type\": \"NON_EMPTY\"\n                      }\n                    ]\n                  }\n                ]\n              }\n            ],\n            \"simpleValueType\": true,\n            \"enablingConditions\": [\n              {\n                \"paramName\": \"eventNameSetupMethod\",\n                \"paramValue\": \"override\",\n                \"type\": \"EQUALS\"\n              }\n            ],\n            \"displayName\": \"Event Type\"\n          }\n        ],\n        \"defaultValue\": \"override\",\n        \"alwaysInSummary\": true\n      },\n      {\n        \"type\": \"CHECKBOX\",\n        \"name\": \"enableDataLayerMapping\",\n        \"checkboxText\": \"Enable automatic User Data and Event Parameters mapping from the Data Layer\",\n        \"simpleValueType\": true,\n        \"help\": \"If enabled, the TikTok tag will map standard User Data and Event Parameters automatically from the Data Layer.\\n\\u003cbr/\\u003e\\u003cbr/\\u003e\\nThe tag parses the Universal Analytics,  \\u003ca href\\u003d\\\"https://developers.google.com/analytics/devguides/collection/ga4/ecommerce\\\"\\u003eGA4\\u003c/a\\u003e and \\u003ca href\\u003d\\\"https://developers.google.com/tag-platform/tag-manager/server-side/common-event-data\\\"\\u003eCommon Event Data\\u003c/a\\u003e formats.\\n\\u003cbr/\\u003e\\u003cbr/\\u003e\\n\\u003cb\\u003eEvent Parameters\\u003c/b\\u003e auto-mapped parameters:\\n\\u003cul\\u003e\\n\\u003cli\\u003e\\u003cb\\u003econtents\\u003c/b\\u003e: GA4 \\u003ci\\u003eitem[]\\u003c/i\\u003e or  UA \\u003ci\\u003eecommerce[action].products[]\\u003c/i\\u003e from Data Layer\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003cb\\u003econtent_ids\\u003c/b\\u003e: GA4 \\u003ci\\u003eitem[].item_id\\u003c/i\\u003e or  UA \\u003ci\\u003eecommerce[action].products[].id\\u003c/i\\u003e from Data Layer\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003cb\\u003econtent_type\\u003c/b\\u003e: if products are found in Data Layer, it\\u0027ll always be mapped \\u003ci\\u003e\\\"product\\\"\\u003c/i\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003cb\\u003enum_items\\u003c/b\\u003e: Sum of GA4 \\u003ci\\u003eitem[].quantity\\u003c/i\\u003e or  UA \\u003ci\\u003eecommerce[action].products[].quantity\\u003c/i\\u003e from Data Layer\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003cb\\u003evalue\\u003c/b\\u003e: GA4 \\u003ci\\u003evalue\\u003c/i\\u003e or UA \\u003ci\\u003eecommerce[action].revenue\\u003c/i\\u003e from Data Layer, or Sum of GA4 \\u003ci\\u003eitem[].quantity\\u003c/i\\u003e * \\u003ci\\u003eitem[].price\\u003c/i\\u003e or  UA \\u003ci\\u003eecommerce[action].products[].quantity\\u003c/i\\u003e * \\u003ci\\u003eecommerce[action].products[].price\\u003c/i\\u003e from Data Layer\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003cb\\u003ecurrency\\u003c/b\\u003e: GA4 \\u003ci\\u003eitem[0].currency\\u003c/i\\u003e or GA4 \\u003ci\\u003ecurrency\\u003c/i\\u003e or  UA \\u003ci\\u003eecommerce.currencyCode\\u003c/i\\u003e from Data Layer\\u003c/li\\u003e\\n or  UA \\u003ci\\u003eecommerce[action].products[].id\\u003c/i\\u003e from Data Layer\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003cb\\u003esearch_string\\u003c/b\\u003e: GA4 \\u003ci\\u003esearch_term\\u003c/i\\u003e from Data Layer\\u003c/li\\u003e\\n\\u003c/ul\\u003e\\n\\u003cbr/\\u003e\\n\\u003cb\\u003eUser Data\\u003c/b\\u003e auto-mapped parameters:\\n\\u003cul\\u003e\\n\\u003cli\\u003e\\u003cb\\u003eEmail\\u003c/b\\u003e: GA4 \\u003ci\\u003eemail\\u003c/i\\u003e, \\u003ci\\u003esha256_email_address\\u003c/i\\u003e, \\u003ci\\u003eemail_address\\u003c/i\\u003e, \\u003ci\\u003eemail\\u003c/i\\u003e or \\u003ci\\u003eem\\u003c/i\\u003e keys from  \\u003ci\\u003euser_data\\u003c/i\\u003e object in the Data Layer\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003cb\\u003ePhone Number\\u003c/b\\u003e: GA4 \\u003ci\\u003ephone\\u003c/i\\u003e, \\u003ci\\u003esha256_phone_number\\u003c/i\\u003e, \\u003ci\\u003ephone_number\\u003c/i\\u003e or \\u003ci\\u003eph\\u003c/i\\u003e keys from  \\u003ci\\u003euser_data\\u003c/i\\u003e object in the Data Layer\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003cb\\u003eExternal ID\\u003c/b\\u003e:  GA4 \\u003ci\\u003euser_id\\u003c/i\\u003e, \\u003ci\\u003euserId\\u003c/i\\u003e, or \\u003ci\\u003eexternal_id\\u003c/i\\u003e keys from the Data Layer or from the \\u003ci\\u003euser_data\\u003c/i\\u003e object in the Data Layer\\u003c/li\\u003e\\n\\u003c/ul\\u003e\",\n        \"defaultValue\": true,\n        \"subParams\": [\n          {\n            \"type\": \"CHECKBOX\",\n            \"name\": \"enableMostRecentDataLayerEventOnly\",\n            \"checkboxText\": \"Use data only from the most recent Data Layer event where the data can be found (ignore recursive merges)\",\n            \"simpleValueType\": true,\n            \"help\": \"If enabled, the tag will take data only from the most recent Data Layer event where the data can be found. \\n\\u003cbr/\\u003e\\u003cbr/\\u003e\\nIn other words, the tag will ignore recursive merges for Data Layer variables and take only the most recent value of the data. \\u003ca href\\u003d\\\"https://www.simoahava.com/gtm-tips/data-layer-variable-versions-explained/\\\"\\u003eLearn more\\u003c/a\\u003e.\",\n            \"defaultValue\": false,\n            \"enablingConditions\": [\n              {\n                \"paramName\": \"enableDataLayerMapping\",\n                \"paramValue\": true,\n                \"type\": \"EQUALS\"\n              }\n            ]\n          }\n        ],\n        \"alwaysInSummary\": true\n      },\n      {\n        \"type\": \"CHECKBOX\",\n        \"name\": \"enableAdvancedMatching\",\n        \"checkboxText\": \"Enable Advanced Matching\",\n        \"simpleValueType\": true,\n        \"help\": \"Advanced Matching helps you optimize your TikTok ads and drive performance by matching User Data with people on TikTok. Hashed User Data can be shared with any TikTok event to attribute more conversions, build bigger audiences and improve campaign optimization.\\n\\u003cbr/\\u003e\\u003cbr/\\u003e\\nNote: if a TikTok Pixel ID on the page is using User Data, then all the TikTok Pixel IDs implemented on the page will use this User Data too (even the ones that don\\u0027t have the \\\"Enabled Advanced Matching\\\" option toggled on). The TikTok Pixel does not support a per-Pixel ID usage.\\n\\u003cbr/\\u003e\\u003cbr/\\u003e\\n\\u003ca href\\u003d\\\"https://business-api.tiktok.com/portal/docs?rid\\u003d5ipocbxyw8v\\u0026id\\u003d1739585700402178\\\"\\u003eLearn more\\u003c/a\\u003e.\",\n        \"subParams\": [\n          {\n            \"type\": \"CHECKBOX\",\n            \"name\": \"enableEventUserDataEnhancement\",\n            \"checkboxText\": \"Enable Event User Data Enhancement\",\n            \"simpleValueType\": true,\n            \"help\": \"Enable the use of \\u003ci\\u003elocalStorage\\u003c/i\\u003e to store data for enhanced User Data tracking.\\n\\u003cbr/\\u003e\\u003cbr/\\u003e\\nNote: If the \\u003ci\\u003eEnable automatic data population from the Data Layer\\u003c/i\\u003e option is selected, all User Data found in the Data Layer will be stored, not just the fields explicitly defined in the User Data section.\\n\\u003cbr/\\u003e\\u003cbr/\\u003e\\nThis feature is a convenience and is not part of the default TikTok Pixel behavior. It is not integrated with the TikTok Pixel consent features (from the \\u003ci\\u003eCompliance Settings\\u003c/i\\u003e section below).\",\n            \"subParams\": [\n              {\n                \"type\": \"CHECKBOX\",\n                \"name\": \"storeUserDataHashed\",\n                \"checkboxText\": \"Store User Data hashed\",\n                \"simpleValueType\": true,\n                \"help\": \"The User Data will be stored hashed in \\u003ci\\u003elocalStorage\\u003c/i\\u003e.\",\n                \"enablingConditions\": [\n                  {\n                    \"paramName\": \"enableEventUserDataEnhancement\",\n                    \"paramValue\": true,\n                    \"type\": \"EQUALS\"\n                  }\n                ]\n              }\n            ],\n            \"enablingConditions\": [\n              {\n                \"paramName\": \"enableAdvancedMatching\",\n                \"paramValue\": true,\n                \"type\": \"EQUALS\"\n              }\n            ]\n          }\n        ],\n        \"defaultValue\": true,\n        \"alwaysInSummary\": true\n      }\n    ]\n  },\n  {\n    \"type\": \"GROUP\",\n    \"name\": \"complianceSettingsGroup\",\n    \"displayName\": \"Compliance Settings\",\n    \"groupStyle\": \"ZIPPY_OPEN_ON_PARAM\",\n    \"subParams\": [\n      {\n        \"type\": \"SELECT\",\n        \"name\": \"consentOptMode\",\n        \"displayName\": \"Default TikTok Consent Mode\",\n        \"macrosInSelect\": false,\n        \"selectItems\": [\n          {\n            \"value\": \"optout\",\n            \"displayValue\": \"User Opt-out\"\n          },\n          {\n            \"value\": \"optin\",\n            \"displayValue\": \"User Opt-in\"\n          }\n        ],\n        \"simpleValueType\": true,\n        \"help\": \"\\u003cb\\u003eUser Opt-in\\u003c/b\\u003e: this solution will prevent pixels from sharing data with TikTok until user consent is explicitly granted. After consent is granted on the page, events that were previously queued in the page before consent was granted will be sent.\\n\\u003cbr/\\u003e\\u003cbr/\\u003e\\n\\u003cb\\u003eUser Opt-out\\u003c/b\\u003e (default): this solution will allow pixels to share data with TikTok until user consent is explicitly revoked. Events already sent to TikTok won\\u0027t be affected.\\n\\u003cbr/\\u003e\\u003cbr/\\u003e\\n\\u003ca href\\u003d\\\"https://business-api.tiktok.com/portal/docs?id\\u003d1795929012554754\\\"\\u003eLearn more\\u003c/a\\u003e (note that the opt-in and opt-out definition is switched).\",\n        \"defaultValue\": \"optout\",\n        \"alwaysInSummary\": true\n      },\n      {\n        \"type\": \"SELECT\",\n        \"name\": \"consent\",\n        \"displayName\": \"Consent\",\n        \"macrosInSelect\": true,\n        \"selectItems\": [\n          {\n            \"value\": \"granted\",\n            \"displayValue\": \"granted\"\n          },\n          {\n            \"value\": \"denied\",\n            \"displayValue\": \"denied\"\n          }\n        ],\n        \"simpleValueType\": true,\n        \"help\": \"\\u003cb\\u003eConsent Granted\\u003c/b\\u003e accepted values: \\u003ci\\u003etrue\\u003c/i\\u003e, \\u003ci\\u003e\\\"true\\\"\\u003c/i\\u003e, \\u003ci\\u003e1\\u003c/i\\u003e, \\u003ci\\u003e\\\"1\\\"\\u003c/i\\u003e, or \\u003ci\\u003e\\\"granted\\\"\\u003c/i\\u003e.\\n\\u003cbr/\\u003e\\u003cbr/\\u003e\\n\\u003cb\\u003eConsent Denied\\u003c/b\\u003e accepted values: \\u003ci\\u003efalse\\u003c/i\\u003e, \\u003ci\\u003e\\\"false\\\"\\u003c/i\\u003e, \\u003ci\\u003e0\\u003c/i\\u003e, \\u003ci\\u003e\\\"0\\\"\\u003c/i\\u003e, or \\u003ci\\u003e\\\"denied\\\"\\u003c/i\\u003e.\\n\\u003cbr/\\u003e\\u003cbr/\\u003e\\nAny other value will be considered as \\u003cb\\u003eConsent Unknown\\u003c/b\\u003e.\\n\\u003cbr/\\u003e\\u003cbr/\\u003e\\nWhen \\u003cb\\u003eConsent Denied\\u003c/b\\u003e, events won\\u0027t be sent. The tracking resumes only when an event fires with \\u003cb\\u003eConsent Granted\\u003c/b\\u003e.\\n\\u003cbr/\\u003e\\u003cbr/\\u003e\\n\\u003ca href\\u003d\\\"https://business-api.tiktok.com/portal/docs?id\\u003d1795929012554754\\\"\\u003eLearn more\\u003c/a\\u003e.\",\n        \"notSetText\": \"(not set)\",\n        \"enablingConditions\": [\n          {\n            \"paramName\": \"enableGoogleConsentMode\",\n            \"paramValue\": false,\n            \"type\": \"EQUALS\"\n          }\n        ]\n      },\n      {\n        \"type\": \"CHECKBOX\",\n        \"name\": \"enableGoogleConsentMode\",\n        \"checkboxText\": \"Enable Google Consent Mode support\",\n        \"simpleValueType\": true,\n        \"help\": \"When enabled, this tag checks for the Google Consent Mode \\u003ci\\u003ead_storage\\u003c/i\\u003e consent.\\n\\u003cbr/\\u003e\\nIf consent is not granted, the TikTok pixel consent is set as revoked or on hold (check the \\u003ci\\u003eDefault TikTok Consent Mode\\u003c/i\\u003e above). \\n\\u003cbr/\\u003e\\nIf consent is granted (initially or later), the pixel consent is automatically granted.\\n\\u003cbr/\\u003e\\u003cbr/\\u003e\\n\\u003ca href\\u003d\\\"https://business-api.tiktok.com/portal/docs?id\\u003d1795929012554754\\\"\\u003eLearn more\\u003c/a\\u003e (note that the opt-in and opt-out definition is switched).\",\n        \"subParams\": []\n      },\n      {\n        \"type\": \"CHECKBOX\",\n        \"name\": \"enableLDU\",\n        \"checkboxText\": \"Enable Limited Data Use (LDU)\",\n        \"simpleValueType\": true,\n        \"help\": \"Limited Data Use is a feature to give businesses more control over how their event data is used in TikTok\\u0027s systems under certain U.S. state privacy laws. \\u003ca href\\u003d\\\"https://business-api.tiktok.com/portal/docs?id\\u003d1770092377990145\\\"\\u003eLearn more\\u003c/a\\u003e.\",\n        \"subParams\": [\n          {\n            \"type\": \"SELECT\",\n            \"name\": \"modeLDU\",\n            \"displayName\": \"LDU Mode\",\n            \"macrosInSelect\": false,\n            \"selectItems\": [\n              {\n                \"value\": \"all\",\n                \"displayValue\": \"All Events\"\n              },\n              {\n                \"value\": \"single\",\n                \"displayValue\": \"Single Event\"\n              }\n            ],\n            \"simpleValueType\": true,\n            \"help\": \"Choose whether the Limited Data Use (LDU) will be applied to all events, or to the specific event triggered by this tag.\",\n            \"defaultValue\": \"all\",\n            \"enablingConditions\": [\n              {\n                \"paramName\": \"enableLDU\",\n                \"paramValue\": true,\n                \"type\": \"EQUALS\"\n              }\n            ]\n          }\n        ]\n      }\n    ]\n  },\n  {\n    \"displayName\": \"User Data\",\n    \"name\": \"userDataGroup\",\n    \"groupStyle\": \"ZIPPY_OPEN_ON_PARAM\",\n    \"type\": \"GROUP\",\n    \"subParams\": [\n      {\n        \"type\": \"LABEL\",\n        \"name\": \"userDataLabel\",\n        \"displayName\": \"Check this \\u003ca href\\u003d\\\"https://business-api.tiktok.com/portal/docs?rid\\u003d5ipocbxyw8v\\u0026id\\u003d1739585700402178\\\"\\u003edocumentation\\u003c/a\\u003e for more details on accepted User Data parameters.\\n\\u003cbr/\\u003e\\nThe tag will automatically hash parameters that need it, pre-hashed data is also accepted.\\n\\u003cbr/\\u003e\\u003cbr/\\u003e\"\n      },\n      {\n        \"type\": \"SELECT\",\n        \"name\": \"userDataFromVariable\",\n        \"displayName\": \"Load Parameters From Variable\",\n        \"macrosInSelect\": true,\n        \"selectItems\": [\n          {\n            \"value\": false,\n            \"displayValue\": \"False\"\n          }\n        ],\n        \"simpleValueType\": true,\n        \"help\": \"You can use a standard User-Provided Data variable or create a variable that returns a JavaScript object containing the desired User Data parameters. This object will merge with additional parameters from the table below, with any conflicts resolved in favor of the table entries.\"\n      },\n      {\n        \"name\": \"userDataList\",\n        \"simpleTableColumns\": [\n          {\n            \"valueValidators\": [\n              {\n                \"type\": \"NON_EMPTY\"\n              }\n            ],\n            \"displayName\": \"Parameter Name\",\n            \"name\": \"name\",\n            \"isUnique\": true,\n            \"type\": \"SELECT\",\n            \"selectItems\": [\n              {\n                \"value\": \"email\",\n                \"displayValue\": \"Email Address\"\n              },\n              {\n                \"value\": \"phone_number\",\n                \"displayValue\": \"Phone Number\"\n              },\n              {\n                \"value\": \"external_id\",\n                \"displayValue\": \"External ID\"\n              }\n            ],\n            \"defaultValue\": \"\"\n          },\n          {\n            \"defaultValue\": \"\",\n            \"displayName\": \"Parameter Value\",\n            \"name\": \"value\",\n            \"type\": \"TEXT\",\n            \"valueValidators\": []\n          }\n        ],\n        \"type\": \"SIMPLE_TABLE\",\n        \"newRowButtonText\": \"Add parameter\"\n      }\n    ],\n    \"enablingConditions\": [\n      {\n        \"paramName\": \"enableAdvancedMatching\",\n        \"paramValue\": true,\n        \"type\": \"EQUALS\"\n      }\n    ]\n  },\n  {\n    \"displayName\": \"Event Parameters\",\n    \"name\": \"eventParametersGroup\",\n    \"groupStyle\": \"ZIPPY_OPEN_ON_PARAM\",\n    \"type\": \"GROUP\",\n    \"subParams\": [\n      {\n        \"type\": \"LABEL\",\n        \"name\": \"eventParametersLabel\",\n        \"displayName\": \"Check this \\u003ca href\\u003d\\\"https://business-api.tiktok.com/portal/docs?rid\\u003d5ipocbxyw8v\\u0026id\\u003d1739585702922241#item-link-Parameters\\\"\\u003edocumentation\\u003c/a\\u003e for more details on accepted Event Parameters.\\n\\u003cbr/\\u003e\\u003cbr/\\u003e\"\n      },\n      {\n        \"type\": \"SELECT\",\n        \"name\": \"eventParametersFromVariable\",\n        \"displayName\": \"Load Parameters From Variable\",\n        \"macrosInSelect\": true,\n        \"selectItems\": [\n          {\n            \"value\": false,\n            \"displayValue\": \"False\"\n          }\n        ],\n        \"simpleValueType\": true,\n        \"help\": \"You can create a variable that returns a JavaScript object with the desired Event Parameters. This object will merge with additional parameters from the table below, with any conflicts resolved in favor of the table entries.\"\n      },\n      {\n        \"name\": \"eventParametersList\",\n        \"simpleTableColumns\": [\n          {\n            \"valueValidators\": [\n              {\n                \"type\": \"NON_EMPTY\"\n              }\n            ],\n            \"defaultValue\": \"\",\n            \"displayName\": \"Parameter Name\",\n            \"name\": \"name\",\n            \"isUnique\": true,\n            \"type\": \"SELECT\",\n            \"selectItems\": [\n              {\n                \"value\": \"content_type\",\n                \"displayValue\": \"content_type\"\n              },\n              {\n                \"value\": \"content_ids\",\n                \"displayValue\": \"content_ids\"\n              },\n              {\n                \"value\": \"contents\",\n                \"displayValue\": \"contents\"\n              },\n              {\n                \"value\": \"currency\",\n                \"displayValue\": \"currency\"\n              },\n              {\n                \"value\": \"value\",\n                \"displayValue\": \"value\"\n              },\n              {\n                \"value\": \"num_items\",\n                \"displayValue\": \"num_items\"\n              },\n              {\n                \"value\": \"search_string\",\n                \"displayValue\": \"search_string\"\n              },\n              {\n                \"value\": \"description\",\n                \"displayValue\": \"description\"\n              },\n              {\n                \"value\": \"status\",\n                \"displayValue\": \"status\"\n              },\n              {\n                \"value\": \"delivery_category\",\n                \"displayValue\": \"delivery_category\"\n              },\n              {\n                \"value\": \"order_id\",\n                \"displayValue\": \"order_id\"\n              }\n            ]\n          },\n          {\n            \"defaultValue\": \"\",\n            \"displayName\": \"Parameter Value\",\n            \"name\": \"value\",\n            \"type\": \"TEXT\"\n          }\n        ],\n        \"type\": \"SIMPLE_TABLE\",\n        \"newRowButtonText\": \"Add parameter\"\n      }\n    ]\n  },\n  {\n    \"displayName\": \"Additional Event Parameters\",\n    \"name\": \"additionalEventParametersGroup\",\n    \"groupStyle\": \"ZIPPY_OPEN_ON_PARAM\",\n    \"type\": \"GROUP\",\n    \"subParams\": [\n      {\n        \"type\": \"LABEL\",\n        \"name\": \"additionalEventParametersLabel\",\n        \"displayName\": \"Use Additional Event Parameters to send any custom parameter or parameters specific to a vertical (Travel, Automotive etc.).\\n\\u003cbr/\\u003e\\nCheck these documentations for more details on Additional Event Parameters for \\u003ca href\\u003d\\\"https://ads.tiktok.com/help/article/available-events-and-parameters-for-travel-ads?lang\\u003den\\n\\\"\\u003eTravel Ads\\u003c/a\\u003e and \\u003ca href\\u003d\\\"https://ads.tiktok.com/help/article/available-parameters-for-automotive-ads?lang\\u003den\\\"\\u003eAutomotive Ads\\u003c/a\\u003e.\\n\\u003cbr/\\u003e\\u003cbr/\\u003e\"\n      },\n      {\n        \"type\": \"SELECT\",\n        \"name\": \"additionalEventParametersFromVariable\",\n        \"displayName\": \"Load Parameters From Variable\",\n        \"macrosInSelect\": true,\n        \"selectItems\": [\n          {\n            \"value\": false,\n            \"displayValue\": \"False\"\n          }\n        ],\n        \"simpleValueType\": true,\n        \"help\": \"You can create a variable that returns a JavaScript object with the desired Additional Event Parameters. This object will merge with additional parameters from the table below, with any conflicts resolved in favor of the table entries.\"\n      },\n      {\n        \"name\": \"additionalEventParametersList\",\n        \"simpleTableColumns\": [\n          {\n            \"valueValidators\": [\n              {\n                \"type\": \"NON_EMPTY\"\n              }\n            ],\n            \"defaultValue\": \"\",\n            \"displayName\": \"Parameter Name\",\n            \"name\": \"name\",\n            \"isUnique\": true,\n            \"type\": \"TEXT\"\n          },\n          {\n            \"defaultValue\": \"\",\n            \"displayName\": \"Parameter Value\",\n            \"name\": \"value\",\n            \"type\": \"TEXT\"\n          }\n        ],\n        \"type\": \"SIMPLE_TABLE\",\n        \"newRowButtonText\": \"Add parameter\"\n      }\n    ]\n  },\n  {\n    \"type\": \"GROUP\",\n    \"name\": \"serverSideSettingsGroup\",\n    \"displayName\": \"Server Side Tracking Settings\",\n    \"groupStyle\": \"ZIPPY_OPEN_ON_PARAM\",\n    \"subParams\": [\n      {\n        \"type\": \"TEXT\",\n        \"name\": \"eventId\",\n        \"displayName\": \"Event ID\",\n        \"simpleValueType\": true,\n        \"help\": \"Set the Event ID parameter in case you are tracking the same event via server-side using the Conversion API (Events API).\\n\\u003cbr/\\u003e\\nThe Event ID can be used to deduplicate the same event if sent from multiple sources. Learn more: \\u003ca href\\u003d\\\"https://business-api.tiktok.com/portal/docs?id\\u003d1799004097478658#item-link-How%20to%20set%20up%20deduplication\\\"\\u003e[1]\\u003c/a\\u003e,\\n\\u003ca href\\u003d\\\"https://ads.tiktok.com/help/article/event-deduplication?lang\\u003den\\\"\\u003e[2]\\u003c/a\\u003e and \\u003ca href\\u003d\\\"https://business-api.tiktok.com/portal/docs?id\\u003d1739584864945154\\\"\\u003e[3]\\u003c/a\\u003e\"\n      },\n      {\n        \"type\": \"GROUP\",\n        \"name\": \"advancedSettingsGroup\",\n        \"displayName\": \"Advanced Settings\",\n        \"groupStyle\": \"ZIPPY_OPEN_ON_PARAM\",\n        \"subParams\": [\n          {\n            \"type\": \"CHECKBOX\",\n            \"name\": \"pushEventIdToDataLayer\",\n            \"checkboxText\": \"Push event to DataLayer with the Event ID\",\n            \"simpleValueType\": true,\n            \"help\": \"It\\u0027s helpful for easier events deduplication with the server.-side event. You can use this event to trigger the tag that send data to the server container and forward the correct Event ID.\",\n            \"defaultValue\": false\n          },\n          {\n            \"type\": \"GROUP\",\n            \"name\": \"eventIdDataLayerConfigGroup\",\n            \"subParams\": [\n              {\n                \"type\": \"TEXT\",\n                \"name\": \"eventIdDataLayerEventName\",\n                \"displayName\": \"DataLayer Event Name\",\n                \"simpleValueType\": true,\n                \"valueValidators\": [\n                  {\n                    \"type\": \"NON_EMPTY\"\n                  }\n                ],\n                \"valueHint\": \"page_view_unique\",\n                \"help\": \"Be careful not to use an Event Name that can trigger this tag, otherwise the tag will enter in an infinite loop.\"\n              },\n              {\n                \"type\": \"TEXT\",\n                \"name\": \"eventIdDataLayerVariableName\",\n                \"displayName\": \"DataLayer Array Name\",\n                \"simpleValueType\": true,\n                \"valueValidators\": [\n                  {\n                    \"type\": \"NON_EMPTY\"\n                  }\n                ],\n                \"defaultValue\": \"dataLayer\",\n                \"help\": \"Use dataLayer by default. Modify only if you renamed dataLayer object name.\"\n              }\n            ],\n            \"enablingConditions\": [\n              {\n                \"paramName\": \"pushEventIdToDataLayer\",\n                \"paramValue\": true,\n                \"type\": \"EQUALS\"\n              }\n            ]\n          }\n        ]\n      }\n    ]\n  },\n  {\n    \"type\": \"GROUP\",\n    \"name\": \"additionalSettingsGroup\",\n    \"displayName\": \"Additional Settings\",\n    \"groupStyle\": \"ZIPPY_OPEN_ON_PARAM\",\n    \"subParams\": [\n      {\n        \"type\": \"CHECKBOX\",\n        \"name\": \"disableHistoryObserver\",\n        \"checkboxText\": \"Disable History Event Tracking\",\n        \"simpleValueType\": true,\n        \"help\": \"The TikTok Pixel \\u003ca href\\u003d\\\"https://business-api.tiktok.com/portal/docs?id\\u003d1801524003169281\\\"\\u003eautomatically tracks history events\\u003c/a\\u003e (pushState and replaceState) as a \\u003ci\\u003ePageview\\u003c/i\\u003e. These automatically collected events don\\u0027t carry the parameters defined by the user (such as Event ID etc.).\\n\\u003cbr/\\u003e\\u003cbr/\\u003e\\nCheck this box to \\u003cb\\u003edisable\\u003c/b\\u003e this automatic tracking. Make sure to implement it manually instead.\\n\\u003cbr/\\u003e\\u003cbr/\\u003e\\nDisabling it can be useful to deduplicate (\\u003ca href\\u003d\\\"https://ads.tiktok.com/help/article/event-deduplication?lang\\u003den\\\"\\u003e[1]\\u003c/a\\u003e and \\u003ca href\\u003d\\\"https://business-api.tiktok.com/portal/docs?id\\u003d1739584864945154\\\"\\u003e[2]\\u003c/a\\u003e) the \\u003ci\\u003ePageview\\u003c/i\\u003e event when using the Conversions API (Events API). This way you can make sure to send the correct Event ID in both web and server events.\"\n      }\n    ]\n  }\n]\n\n\n___SANDBOXED_JS_FOR_WEB_TEMPLATE___\n\nconst addConsentListener = require('addConsentListener');\nconst callInWindow = require('callInWindow');\nconst copyFromDataLayer = require('copyFromDataLayer');\nconst copyFromWindow = require('copyFromWindow');\nconst createQueue = require('createQueue');\nconst encodeUriComponent = require('encodeUriComponent');\nconst getTimestampMillis = require('getTimestampMillis');\nconst getType = require('getType');\nconst injectScript = require('injectScript');\nconst isConsentGranted = require('isConsentGranted');\nconst JSON = require('JSON');\nconst localStorage = require('localStorage');\nconst makeNumber = require('makeNumber');\nconst makeString = require('makeString');\nconst makeTableMap = require('makeTableMap');\nconst Object = require('Object');\nconst setInWindow = require('setInWindow');\nconst sha256 = require('sha256');\nconst templateStorage = require('templateStorage');\n\n// Call-once methods.\nlet gtmOnSuccess = () => {\n  gtmOnSuccess = () => {};\n  return data.gtmOnSuccess();\n};\n\nlet gtmOnFailure = () => {\n  gtmOnFailure = () => {};\n  return data.gtmOnFailure();\n};\n\n/*==============================================================================\n==============================================================================*/\n\nconst PARTNER_NAME = 'stape_gtm_1_2_0';\nconst queueName = 'ttq';\n\nconst queue = getOrCreateTikTokQueue(queueName);\n\nconst isConsentExplicitlyRevokedAndNotOptInMode =\n  data.consentOptMode !== 'optin' &&\n  (data.enableGoogleConsentMode\n    ? !isConsentGranted('ad_storage')\n    : isUIConsentFieldDenied(data.consent));\nif (isConsentExplicitlyRevokedAndNotOptInMode) {\n  // Only adds .revokeConsent if the queue was already taken over by SDK.\n  // Otherwise (not taken over yet), .track/.identify commands collect prior to consent granted will be executed when calling .load and .grantConsent.\n  const queueWasTakenOverBySDK = queue && (queue.initialize || queue._mounted);\n  if (queueWasTakenOverBySDK) {\n    callInWindow(queueName + '.revokeConsent');\n  }\n\n  return gtmOnSuccess();\n}\n\nsetConsent(data, queueName);\nsendEvent(data, queueName);\n\n/*==============================================================================\n  Vendor related functions\n==============================================================================*/\n\nfunction getOrCreateTikTokQueue(queueName) {\n  const existingQueue = copyFromWindow(queueName);\n  if (existingQueue) return existingQueue;\n\n  setInWindow('TiktokAnalyticsObject', queueName);\n  const newQueue = [];\n\n  // prettier-ignore\n  newQueue.methods = ['page','track','identify','instances','debug','on','off','once','ready','alias','group','enableCookie','disableCookie','holdConsent','revokeConsent','grantConsent'];\n\n  // \"pixelId\" parameter is not present in the original method.\n  // We need it to determine which queue to be used during the execution of the inner function.\n  newQueue.setAndDefer = (queue, command, pixelId) => {\n    // Do not use arrow function here to avoid problems with 'arguments'.\n    queue[command] = function () {\n      const currentQueue = copyFromWindow(queueName);\n      const currentPixelQueue = pixelId\n        ? (currentQueue._i[pixelId] = currentQueue._i[pixelId] || [])\n        : undefined;\n      (pixelId ? currentPixelQueue : currentQueue).push(\n        [command].concat(convertArgumentstoArray(arguments))\n      );\n      if (pixelId) setInWindow(queueName + '._i', currentQueue._i, true);\n      else setInWindow(queueName, currentQueue, true);\n    };\n  };\n\n  newQueue.methods.forEach((method) => newQueue.setAndDefer(newQueue, method));\n\n  newQueue.instance = (pixelId) => {\n    const _i = copyFromWindow(queueName + '._i');\n    const currentPixelQueue = (_i[pixelId] = _i[pixelId] || []);\n    newQueue.methods.forEach((method) => newQueue.setAndDefer(currentPixelQueue, method, pixelId));\n    setInWindow(queueName + '._i', _i, true);\n    return currentPixelQueue;\n  };\n\n  newQueue.load = (pixelId, options, asyncScriptLoadManagerStorageConfig) => {\n    const scriptBaseUrl = 'https://analytics.tiktok.com/i18n/pixel/events.js';\n    const scriptUrl = scriptBaseUrl + '?sdkid=' + encodeUriComponent(pixelId) + '&lib=' + queueName;\n\n    const _i = copyFromWindow(queueName + '._i') || {};\n    _i[pixelId] = [];\n    _i[pixelId]._u = scriptBaseUrl;\n    setInWindow(queueName + '._i', _i, true);\n\n    const _t = copyFromWindow(queueName + '._t') || {};\n    _t[pixelId] = getTimestampMillis();\n    setInWindow(queueName + '._t', _t, true);\n\n    const _o = copyFromWindow(queueName + '._o') || {};\n    _o[pixelId] = options || {};\n    setInWindow(queueName + '._o', _o, true);\n\n    let asyncManager;\n    if (\n      getType(asyncScriptLoadManagerStorageConfig) === 'object' &&\n      asyncScriptLoadManagerStorageConfig.key\n    ) {\n      asyncManager = getAsyncScriptLoadManager(asyncScriptLoadManagerStorageConfig.key);\n      asyncManager.addPendingCall();\n    }\n\n    injectScript(\n      scriptUrl,\n      () => {\n        if (asyncManager) asyncManager.completeCall();\n      },\n      () => {\n        if (asyncManager) {\n          asyncManager.markFailed();\n          asyncManager.completeCall();\n        }\n      },\n      'ttqPixel-' + pixelId\n    );\n  };\n\n  setInWindow(queueName, newQueue, true);\n  return newQueue;\n}\n\nfunction deferUntilGoogleConsentGranted(isConsentGranted, callback) {\n  if (isConsentGranted) {\n    callback();\n    return;\n  }\n\n  const callbacksKey = 'ttq_consent_callbacks_ad_storage';\n  const callbacks = templateStorage.getItem(callbacksKey) || [];\n  callbacks.push(callback);\n  templateStorage.setItem(callbacksKey, callbacks);\n\n  const listenerAddedKey = 'ttq_consent_listener_added_ad_storage';\n  if (!templateStorage.getItem(listenerAddedKey)) {\n    templateStorage.setItem(listenerAddedKey, true);\n    addConsentListener('ad_storage', (type, granted) => {\n      if (type !== 'ad_storage' || !granted) return;\n      const queuedCallbacks = templateStorage.getItem(callbacksKey) || [];\n      templateStorage.setItem(callbacksKey, []);\n      queuedCallbacks.forEach((cb) => cb());\n    });\n  }\n}\n\nfunction setConsent(data, queueName) {\n  if (data.enableGoogleConsentMode) {\n    if (data.consentOptMode === 'optin' && !isTrackingPermitted(data)) {\n      callInWindow(queueName + '.holdConsent');\n    }\n\n    deferUntilGoogleConsentGranted(isTrackingPermitted(data), () => {\n      callInWindow(queueName + '.grantConsent');\n    });\n  } else {\n    // Manual consent\n    if (!isTrackingPermitted(data)) {\n      callInWindow(queueName + '.holdConsent');\n    } else {\n      callInWindow(queueName + '.grantConsent');\n    }\n  }\n}\n\nfunction getLoadOptions(data) {\n  const loadOptions = {};\n  if (data.disableHistoryObserver) loadOptions.historyObserver = false;\n  if (data.enableLDU && data.modeLDU === 'all') loadOptions.limited_data_use = true;\n  return loadOptions;\n}\n\nfunction getEventName(data) {\n  if (data.eventNameSetupMethod === 'inherit') {\n    const eventName = copyFromDataLayer('event');\n\n    const ga4ToTikTokEventName = {\n      page_view: 'Pageview',\n      'gtm.dom': 'Pageview',\n      add_payment_info: 'AddPaymentInfo',\n      add_to_cart: 'AddToCart',\n      add_to_wishlist: 'AddToWishlist',\n      sign_up: 'CompleteRegistration',\n      begin_checkout: 'InitiateCheckout',\n      generate_lead: 'Lead',\n      purchase: 'Purchase',\n      search: 'Search',\n      view_item: 'ViewContent',\n\n      contact: 'Contact',\n      customize_product: 'CustomizeProduct',\n      donate: 'Donate',\n      find_location: 'FindLocation',\n      schedule: 'Schedule',\n      start_trial: 'StartTrial',\n      submit_application: 'SubmitApplication',\n      subscribe: 'Subscribe',\n\n      page_view_stape: 'Pageview',\n      add_payment_info_stape: 'AddPaymentInfo',\n      add_to_cart_stape: 'AddToCart',\n      sign_up_stape: 'CompleteRegistration',\n      begin_checkout_stape: 'InitiateCheckout',\n      purchase_stape: 'Purchase',\n      view_item_stape: 'ViewContent',\n\n      'gtm4wp.addProductToCartEEC': 'AddToCart',\n      'gtm4wp.productClickEEC': 'ViewContent',\n      'gtm4wp.checkoutOptionEEC': 'InitiateCheckout',\n      'gtm4wp.checkoutStepEEC': 'AddPaymentInfo',\n      'gtm4wp.orderCompletedEEC': 'Purchase'\n    };\n\n    return ga4ToTikTokEventName[eventName] || eventName;\n  }\n\n  return data.eventName === 'standard' ? data.eventNameStandard : data.eventNameCustom;\n}\n\nfunction pushEventIdToDataLayer(data) {\n  if (!data.pushEventIdToDataLayer) return;\n\n  const dataLayerQueueName = data.eventIdDataLayerVariableName || 'dataLayer';\n  const dataLayerPush = createQueue(dataLayerQueueName);\n  dataLayerPush({\n    eventId: data.eventId,\n    event: data.eventIdDataLayerEventName || 'tiktokPixelDataLayerPush'\n  });\n}\n\nfunction getEventUserDataEnhancement(canInteractWithStorage) {\n  if (!canInteractWithStorage || !localStorage) return {};\n\n  const gtmeec = localStorage.getItem('gtmeec-tt');\n  if (gtmeec) {\n    const gtmeecParsed = JSON.parse(gtmeec);\n    if (getType(gtmeecParsed) === 'object') return gtmeecParsed;\n  }\n\n  return {};\n}\n\nfunction normalizeBasedOnSchemaKey(schemaKey, identifier) {\n  switch (schemaKey) {\n    case 'phone_number':\n      return normalizePhoneNumber(identifier);\n    case 'email':\n      return normalizeEmail(identifier);\n    case 'external_id':\n      return removeWhiteSpace(identifier);\n    default:\n      return identifier;\n  }\n}\n\nfunction hashUserDataFields(userData, storeUserDataInLocalStorage) {\n  const canUseHashSync = getType(copyFromWindow('dataTag256')) === 'function';\n  const hashAsyncHelpers = {\n    pendingHashs: 0,\n    maybeFinish: (userDataHashed) => {\n      if (hashAsyncHelpers.pendingHashs === 0) storeUserDataInLocalStorage(userDataHashed);\n    }\n  };\n\n  const userDataHashed = {};\n\n  const fieldNames = Object.keys(userData);\n  fieldNames.forEach((fieldName) => {\n    const value = userData[fieldName];\n\n    if (value === undefined || value === null || value === '') return;\n    if (isHashed(value)) {\n      userDataHashed[fieldName] = value;\n      return;\n    }\n\n    const normalizedValue = makeString(normalizeBasedOnSchemaKey(fieldName, value)).trim();\n    if (canUseHashSync) {\n      userDataHashed[fieldName] = callInWindow('dataTag256', normalizedValue, 'HEX');\n    } else {\n      hashAsyncHelpers.pendingHashs++;\n      sha256(\n        normalizedValue,\n        (digest) => {\n          userDataHashed[fieldName] = digest;\n          hashAsyncHelpers.pendingHashs--;\n          hashAsyncHelpers.maybeFinish(userDataHashed);\n        },\n        () => {\n          hashAsyncHelpers.pendingHashs--;\n        },\n        { outputEncoding: 'hex' }\n      );\n    }\n  });\n\n  if (canUseHashSync) {\n    storeUserDataInLocalStorage(userDataHashed);\n    return userDataHashed;\n  } else {\n    hashAsyncHelpers.maybeFinish(userDataHashed);\n    return;\n  }\n}\n\nfunction storeUserDataInLocalStorage(userData) {\n  if (!localStorage || !objHasProps(userData)) return;\n\n  const gtmeec = JSON.stringify(userData);\n  localStorage.setItem('gtmeec-tt', gtmeec);\n}\n\nfunction storeEventUserDataEnhancement(data, canInteractWithStorage, userData) {\n  if (!canInteractWithStorage || !localStorage || !objHasProps(userData)) return;\n\n  if (!data.storeUserDataHashed) storeUserDataInLocalStorage(userData);\n  else hashUserDataFields(userData, storeUserDataInLocalStorage);\n}\n\nfunction addUserData(userData, userDataFrom, useDL) {\n  let email =\n    userDataFrom.email ||\n    userDataFrom.sha256_email_address ||\n    userDataFrom.email_address ||\n    userDataFrom.em;\n  const emailType = getType(email);\n  if (emailType === 'array' || emailType === 'object') email = email[0];\n  if (email) userData.email = email;\n\n  let phone =\n    userDataFrom.phone ||\n    userDataFrom.sha256_phone_number ||\n    userDataFrom.phone_number ||\n    userDataFrom.ph;\n  const phoneType = getType(phone);\n  if (phoneType === 'array' || phoneType === 'object') phone = phone[0];\n  if (phone) userData.phone_number = phone;\n\n  if (userDataFrom.external_id) userData.external_id = userDataFrom.external_id;\n  else if (userDataFrom.user_id) userData.external_id = userDataFrom.user_id;\n  else if (userDataFrom.userId) userData.external_id = userDataFrom.userId;\n  else if (useDL && copyFromDataLayerWithVersion('external_id'))\n    userData.external_id = copyFromDataLayerWithVersion('external_id');\n  else if (useDL && copyFromDataLayerWithVersion('user_id'))\n    userData.external_id = copyFromDataLayerWithVersion('user_id');\n  else if (useDL && copyFromDataLayerWithVersion('userId'))\n    userData.external_id = copyFromDataLayerWithVersion('userId');\n\n  return userData;\n}\n\nfunction isTrackingPermitted(data) {\n  if (data.enableGoogleConsentMode) {\n    return isConsentGranted('ad_storage');\n  } else {\n    // Manual consent\n    return (\n      data.consentOptMode !== 'optin' ||\n      (data.consentOptMode === 'optin' && isUIConsentFieldGranted(data.consent))\n    );\n  }\n}\n\nfunction getUserData(data) {\n  if (!data.enableAdvancedMatching) return;\n\n  const canInteractWithStorage = isTrackingPermitted(data);\n  let userData = {};\n\n  if (data.enableEventUserDataEnhancement) {\n    userData = getEventUserDataEnhancement(canInteractWithStorage);\n  }\n\n  if (data.enableDataLayerMapping) {\n    const userDataFromDataLayer = copyFromDataLayerWithVersion('user_data');\n    if (getType(userDataFromDataLayer) === 'object') {\n      addUserData(userData, userDataFromDataLayer, true);\n    }\n  }\n\n  if (getType(data.userDataFromVariable) === 'object') {\n    addUserData(userData, data.userDataFromVariable, false);\n  }\n\n  if (data.userDataList && data.userDataList.length) {\n    mergeObj(userData, makeTableMap(data.userDataList, 'name', 'value'));\n  }\n\n  if (objIsEmptyOrContainsOnlyFalsyValues(userData)) return;\n\n  if (data.enableEventUserDataEnhancement) {\n    storeEventUserDataEnhancement(data, canInteractWithStorage, userData);\n  }\n\n  return userData;\n}\n\nfunction addUAEventParameters(eventName, eventParameters, ecommerce) {\n  const eventActionMap = {\n    ViewContent: 'detail',\n    AddToCart: 'add',\n    InitiateCheckout: 'checkout',\n    Purchase: 'purchase'\n  };\n\n  if (eventActionMap[eventName]) {\n    const action = eventActionMap[eventName];\n    const hasActionObject = getType(ecommerce[action]) === 'object';\n    const hasActionFieldObject =\n      hasActionObject && getType(ecommerce[action].actionField) === 'object';\n    let valueFromItems = 0;\n\n    if (\n      hasActionObject &&\n      getType(ecommerce[action].products) === 'array' &&\n      ecommerce[action].products.length\n    ) {\n      eventParameters.contents = [];\n      eventParameters.content_ids = [];\n      eventParameters.content_type = 'product';\n      eventParameters.num_items = 0;\n\n      ecommerce[action].products.forEach((d) => {\n        const content = {};\n        if (d.id) content.content_id = makeString(d.id);\n        content.quantity = makeNumber(d.quantity) || 1;\n        if (d.price) {\n          const price = makeNumber(d.price);\n          valueFromItems += content.quantity ? content.quantity * price : price;\n          content.price = price;\n        }\n        if (d.category) content.content_category = makeString(d.category);\n        if (d.name) content.content_name = makeString(d.name);\n        if (d.brand) content.brand = makeString(d.brand);\n\n        eventParameters.contents.push(content);\n        eventParameters.num_items += content.quantity || 1;\n        eventParameters.content_ids.push(content.content_id);\n      });\n    }\n\n    const value =\n      (hasActionFieldObject && ecommerce[action].actionField.revenue\n        ? ecommerce[action].actionField.revenue\n        : undefined) || valueFromItems;\n    if (value) eventParameters.value = makeNumber(value);\n\n    const currency = ecommerce.currencyCode;\n    if (currency) eventParameters.currency = ecommerce.currencyCode;\n\n    if (eventName === 'Purchase') {\n      const orderId = hasActionFieldObject ? ecommerce[action].actionField.id : undefined;\n      if (orderId) eventParameters.order_id = orderId;\n    }\n  }\n\n  return eventParameters;\n}\n\nfunction addGA4EventParameters(eventName, eventParameters, ecommerce) {\n  const items = copyFromDataLayerWithVersion('items') || ecommerce.items;\n  let currencyFromItems = '';\n  let valueFromItems = 0;\n\n  if (getType(items) === 'array' && items.length) {\n    eventParameters.contents = [];\n    eventParameters.content_ids = [];\n    eventParameters.content_type = 'product';\n    eventParameters.num_items = 0;\n    currencyFromItems = items[0].currency;\n\n    items.forEach((d) => {\n      const content = {};\n      if (d.item_id) content.content_id = makeString(d.item_id);\n      content.quantity = makeNumber(d.quantity) || 1;\n\n      if (d.price) {\n        const price = makeNumber(d.price);\n        valueFromItems += content.quantity ? content.quantity * price : price;\n        content.price = price;\n      }\n\n      const contentCategories = [];\n      if (d.item_category) contentCategories.push(makeString(d.item_category));\n      if (d.item_category2) contentCategories.push(makeString(d.item_category2));\n      if (d.item_category3) contentCategories.push(makeString(d.item_category3));\n      if (d.item_category4) contentCategories.push(makeString(d.item_category4));\n      if (d.item_category5) contentCategories.push(makeString(d.item_category5));\n      if (contentCategories.length) content.content_category = contentCategories.join(',');\n\n      if (d.item_name) content.content_name = makeString(d.item_name);\n      if (d.item_brand) content.brand = makeString(d.item_brand);\n\n      eventParameters.contents.push(content);\n      eventParameters.num_items += content.quantity || 1;\n      eventParameters.content_ids.push(content.content_id);\n    });\n  }\n\n  const value = ecommerce.value || valueFromItems || copyFromDataLayerWithVersion('value');\n  if (value) eventParameters.value = makeNumber(value);\n\n  const currency =\n    ecommerce.currency || currencyFromItems || copyFromDataLayerWithVersion('currency');\n  if (currency) eventParameters.currency = currency;\n\n  if (eventName === 'Purchase') {\n    const orderId = ecommerce.transaction_id || copyFromDataLayerWithVersion('transaction_id');\n    if (orderId) eventParameters.order_id = orderId;\n  }\n\n  const searchTerm = copyFromDataLayerWithVersion('search_term');\n  if (searchTerm) eventParameters.search_string = makeString(searchTerm);\n\n  return eventParameters;\n}\n\nfunction getEventParameters(data, eventName) {\n  const eventParameters = {\n    gtm_version: PARTNER_NAME,\n    event_trigger_source: 'GoogleTagManagerClient'\n  };\n\n  if (data.enableLDU && data.modeLDU === 'single') eventParameters.limited_data_use = true;\n\n  if (data.enableDataLayerMapping) {\n    let ecommerceObjFromDataLayer = copyFromDataLayerWithVersion('ecommerce');\n    if (getType(ecommerceObjFromDataLayer) !== 'object') {\n      ecommerceObjFromDataLayer = {};\n    }\n\n    addGA4EventParameters(eventName, eventParameters, ecommerceObjFromDataLayer);\n\n    if (!eventParameters.content_type) {\n      addUAEventParameters(eventName, eventParameters, ecommerceObjFromDataLayer);\n    }\n  }\n\n  if (getType(data.eventParametersFromVariable) === 'object') {\n    mergeObj(eventParameters, data.eventParametersFromVariable);\n  }\n\n  if (data.eventParametersList && data.eventParametersList.length) {\n    mergeObj(eventParameters, makeTableMap(data.eventParametersList, 'name', 'value'));\n  }\n\n  if (getType(data.additionalEventParametersFromVariable) === 'object') {\n    mergeObj(eventParameters, data.additionalEventParametersFromVariable);\n  }\n\n  if (data.additionalEventParametersList && data.additionalEventParametersList.length) {\n    mergeObj(eventParameters, makeTableMap(data.additionalEventParametersList, 'name', 'value'));\n  }\n\n  return eventParameters;\n}\n\nfunction sendEvent(data, queueName) {\n  let pixelIds = getType(data.pixelIds) === 'string' ? data.pixelIds.split(',') : data.pixelIds;\n  if (getType(pixelIds) === 'array') {\n    pixelIds = pixelIds.map((p) => makeString(p).trim()).filter((p) => p);\n  }\n  if (getType(pixelIds) !== 'array' || pixelIds.length === 0) return gtmOnFailure();\n\n  const initializedPixelIds = copyFromWindow('_tiktok_gtm_ids') || {};\n  const loadOptions = getLoadOptions(data);\n  const userData = getUserData(data);\n  let identifyWasNotCalled = true;\n  const eventName = getEventName(data);\n  const eventParameters = getEventParameters(data, eventName);\n\n  const asyncManager = initAsyncScriptLoadManager(data);\n\n  pixelIds.forEach((pixelId) => {\n    const pixelIdIsNotInitialized = !initializedPixelIds[pixelId];\n\n    if (pixelIdIsNotInitialized) {\n      const loadPixel = () => {\n        const asyncScriptLoadManagerStorageConfig = {\n          key: asyncManager.key\n        };\n        callInWindow(\n          queueName + '.load',\n          pixelId,\n          loadOptions,\n          asyncScriptLoadManagerStorageConfig\n        );\n      };\n\n      let willLoad = false;\n      if (data.enableGoogleConsentMode) {\n        willLoad = true;\n        deferUntilGoogleConsentGranted(isTrackingPermitted(data), () => loadPixel());\n      } else if (isTrackingPermitted(data)) {\n        // Manual consent\n        willLoad = true;\n        loadPixel();\n      }\n\n      if (willLoad) {\n        initializedPixelIds[pixelId] = true;\n        setInWindow('_tiktok_gtm_ids', initializedPixelIds, true);\n      }\n    }\n\n    if (identifyWasNotCalled && objHasProps(userData)) {\n      identifyWasNotCalled = false;\n      callInWindow(queueName + '.identify', userData);\n    }\n\n    callInWindow(queueName + '.track', eventName, eventParameters, {\n      event_id: data.eventId,\n      pixel_code: pixelId // Ensures the event is sent to this \"pixelId\" only.\n    });\n  });\n\n  pushEventIdToDataLayer(data);\n\n  if (!asyncManager.hasPendingCalls()) {\n    asyncManager.clear();\n    return gtmOnSuccess();\n  }\n}\n\n/*==============================================================================\n  Helpers\n==============================================================================*/\n\n/**\n * The helper object is used to handle multiple asynchronous script injections.\n * It ensures that the tag execution status is reported only after all scripts have finished loading.\n */\nfunction getAsyncScriptLoadManager(key) {\n  return {\n    key: key,\n    addPendingCall: () => {\n      const manager = templateStorage.getItem(key);\n      if (getType(manager) === 'object') {\n        manager.pendingInjectScriptCalls++;\n        templateStorage.setItem(key, manager);\n      }\n    },\n    hasPendingCalls: () => {\n      const manager = templateStorage.getItem(key);\n      return getType(manager) === 'object' && manager.pendingInjectScriptCalls > 0;\n    },\n    markFailed: () => {\n      const manager = templateStorage.getItem(key);\n      if (getType(manager) === 'object') {\n        manager.someFailed = true;\n        templateStorage.setItem(key, manager);\n      }\n    },\n    completeCall: () => {\n      const manager = templateStorage.getItem(key);\n      if (getType(manager) === 'object') {\n        manager.pendingInjectScriptCalls--;\n        if (manager.pendingInjectScriptCalls <= 0) {\n          templateStorage.removeItem(key);\n          return manager.someFailed ? manager.onFailure() : manager.onSuccess();\n        }\n        templateStorage.setItem(key, manager);\n      }\n    },\n    clear: () => {\n      templateStorage.removeItem(key);\n    }\n  };\n}\n\nfunction initAsyncScriptLoadManager(data) {\n  const tagExecutionId = data.gtmTagId + '-' + data.gtmEventId + '-' + getTimestampMillis();\n  const key = 'asyncScriptLoadManager-' + tagExecutionId;\n  templateStorage.setItem(key, {\n    pendingInjectScriptCalls: 0,\n    someFailed: false,\n    onSuccess: data.gtmOnSuccess,\n    onFailure: data.gtmOnFailure\n  });\n  return getAsyncScriptLoadManager(key);\n}\n\nfunction convertArgumentstoArray(args) {\n  const argumentsAsArray = [];\n  for (let i = 0; i < args.length; i++) argumentsAsArray.push(args[i]);\n  return argumentsAsArray;\n}\n\nfunction isUIConsentFieldGranted(field) {\n  return [true, 'true', 1, '1', 'granted'].indexOf(field) !== -1;\n}\n\nfunction isUIConsentFieldDenied(field) {\n  return [false, 'false', 0, '0', 'denied'].indexOf(field) !== -1;\n}\n\nfunction objHasProps(obj) {\n  return getType(obj) === 'object' && Object.keys(obj).length > 0;\n}\n\nfunction objIsEmptyOrContainsOnlyFalsyValues(obj) {\n  if (getType(obj) !== 'object') return;\n  const objValues = Object.values(obj);\n  if (objValues.length === 0 || objValues.every((v) => !v)) return true;\n}\n\nfunction mergeObj(target, source) {\n  for (const key in source) {\n    if (source.hasOwnProperty(key)) target[key] = source[key];\n  }\n  return target;\n}\n\nfunction isHashed(value) {\n  if (!value) return false;\n  return makeString(value).match('^[A-Fa-f0-9]{64}$') !== null;\n}\n\nfunction normalizePhoneNumber(phoneNumber) {\n  if (!phoneNumber) return;\n  phoneNumber = makeString(phoneNumber)\n    .split('+')\n    .join('')\n    .split(' ')\n    .join('')\n    .split('-')\n    .join('')\n    .split('(')\n    .join('')\n    .split(')')\n    .join('');\n  if (phoneNumber[0] !== '+') phoneNumber = '+' + phoneNumber;\n  return phoneNumber;\n}\n\nfunction normalizeEmail(email) {\n  if (!email) return;\n  return removeWhiteSpace(makeString(email)).toLowerCase();\n}\n\nfunction removeWhiteSpace(input) {\n  if (!input) return;\n  return makeString(input).split(' ').join('');\n}\n\nfunction copyFromDataLayerWithVersion(key) {\n  const dataLayerVersion = data.enableMostRecentDataLayerEventOnly ? 1 : 2;\n  return copyFromDataLayer(key, dataLayerVersion);\n}\n\n\n___WEB_PERMISSIONS___\n\n[\n  {\n    \"instance\": {\n      \"key\": {\n        \"publicId\": \"access_globals\",\n        \"versionId\": \"1\"\n      },\n      \"param\": [\n        {\n          \"key\": \"keys\",\n          \"value\": {\n            \"type\": 2,\n            \"listItem\": [\n              {\n                \"type\": 3,\n                \"mapKey\": [\n                  {\n                    \"type\": 1,\n                    \"string\": \"key\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"read\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"write\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"execute\"\n                  }\n                ],\n                \"mapValue\": [\n                  {\n                    \"type\": 1,\n                    \"string\": \"_tiktok_gtm_ids\"\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": true\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": true\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": false\n                  }\n                ]\n              },\n              {\n                \"type\": 3,\n                \"mapKey\": [\n                  {\n                    \"type\": 1,\n                    \"string\": \"key\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"read\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"write\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"execute\"\n                  }\n                ],\n                \"mapValue\": [\n                  {\n                    \"type\": 1,\n                    \"string\": \"TiktokAnalyticsObject\"\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": true\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": true\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": false\n                  }\n                ]\n              },\n              {\n                \"type\": 3,\n                \"mapKey\": [\n                  {\n                    \"type\": 1,\n                    \"string\": \"key\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"read\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"write\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"execute\"\n                  }\n                ],\n                \"mapValue\": [\n                  {\n                    \"type\": 1,\n                    \"string\": \"ttq\"\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": true\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": true\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": false\n                  }\n                ]\n              },\n              {\n                \"type\": 3,\n                \"mapKey\": [\n                  {\n                    \"type\": 1,\n                    \"string\": \"key\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"read\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"write\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"execute\"\n                  }\n                ],\n                \"mapValue\": [\n                  {\n                    \"type\": 1,\n                    \"string\": \"ttq.track\"\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": false\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": false\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": true\n                  }\n                ]\n              },\n              {\n                \"type\": 3,\n                \"mapKey\": [\n                  {\n                    \"type\": 1,\n                    \"string\": \"key\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"read\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"write\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"execute\"\n                  }\n                ],\n                \"mapValue\": [\n                  {\n                    \"type\": 1,\n                    \"string\": \"ttq.identify\"\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": false\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": false\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": true\n                  }\n                ]\n              },\n              {\n                \"type\": 3,\n                \"mapKey\": [\n                  {\n                    \"type\": 1,\n                    \"string\": \"key\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"read\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"write\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"execute\"\n                  }\n                ],\n                \"mapValue\": [\n                  {\n                    \"type\": 1,\n                    \"string\": \"ttq.load\"\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": false\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": false\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": true\n                  }\n                ]\n              },\n              {\n                \"type\": 3,\n                \"mapKey\": [\n                  {\n                    \"type\": 1,\n                    \"string\": \"key\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"read\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"write\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"execute\"\n                  }\n                ],\n                \"mapValue\": [\n                  {\n                    \"type\": 1,\n                    \"string\": \"ttq.holdConsent\"\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": false\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": false\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": true\n                  }\n                ]\n              },\n              {\n                \"type\": 3,\n                \"mapKey\": [\n                  {\n                    \"type\": 1,\n                    \"string\": \"key\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"read\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"write\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"execute\"\n                  }\n                ],\n                \"mapValue\": [\n                  {\n                    \"type\": 1,\n                    \"string\": \"ttq.revokeConsent\"\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": false\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": false\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": true\n                  }\n                ]\n              },\n              {\n                \"type\": 3,\n                \"mapKey\": [\n                  {\n                    \"type\": 1,\n                    \"string\": \"key\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"read\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"write\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"execute\"\n                  }\n                ],\n                \"mapValue\": [\n                  {\n                    \"type\": 1,\n                    \"string\": \"ttq.grantConsent\"\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": false\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": false\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": true\n                  }\n                ]\n              },\n              {\n                \"type\": 3,\n                \"mapKey\": [\n                  {\n                    \"type\": 1,\n                    \"string\": \"key\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"read\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"write\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"execute\"\n                  }\n                ],\n                \"mapValue\": [\n                  {\n                    \"type\": 1,\n                    \"string\": \"ttq._i\"\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": true\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": true\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": false\n                  }\n                ]\n              },\n              {\n                \"type\": 3,\n                \"mapKey\": [\n                  {\n                    \"type\": 1,\n                    \"string\": \"key\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"read\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"write\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"execute\"\n                  }\n                ],\n                \"mapValue\": [\n                  {\n                    \"type\": 1,\n                    \"string\": \"ttq._t\"\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": true\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": true\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": false\n                  }\n                ]\n              },\n              {\n                \"type\": 3,\n                \"mapKey\": [\n                  {\n                    \"type\": 1,\n                    \"string\": \"key\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"read\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"write\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"execute\"\n                  }\n                ],\n                \"mapValue\": [\n                  {\n                    \"type\": 1,\n                    \"string\": \"ttq._o\"\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": true\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": true\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": false\n                  }\n                ]\n              },\n              {\n                \"type\": 3,\n                \"mapKey\": [\n                  {\n                    \"type\": 1,\n                    \"string\": \"key\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"read\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"write\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"execute\"\n                  }\n                ],\n                \"mapValue\": [\n                  {\n                    \"type\": 1,\n                    \"string\": \"dataLayer\"\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": true\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": true\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": false\n                  }\n                ]\n              },\n              {\n                \"type\": 3,\n                \"mapKey\": [\n                  {\n                    \"type\": 1,\n                    \"string\": \"key\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"read\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"write\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"execute\"\n                  }\n                ],\n                \"mapValue\": [\n                  {\n                    \"type\": 1,\n                    \"string\": \"dataTag256\"\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": true\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": false\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": true\n                  }\n                ]\n              }\n            ]\n          }\n        }\n      ]\n    },\n    \"clientAnnotations\": {\n      \"isEditedByUser\": true\n    },\n    \"isRequired\": true\n  },\n  {\n    \"instance\": {\n      \"key\": {\n        \"publicId\": \"inject_script\",\n        \"versionId\": \"1\"\n      },\n      \"param\": [\n        {\n          \"key\": \"urls\",\n          \"value\": {\n            \"type\": 2,\n            \"listItem\": [\n              {\n                \"type\": 1,\n                \"string\": \"https://analytics.tiktok.com/*\"\n              }\n            ]\n          }\n        }\n      ]\n    },\n    \"clientAnnotations\": {\n      \"isEditedByUser\": true\n    },\n    \"isRequired\": true\n  },\n  {\n    \"instance\": {\n      \"key\": {\n        \"publicId\": \"read_data_layer\",\n        \"versionId\": \"1\"\n      },\n      \"param\": [\n        {\n          \"key\": \"allowedKeys\",\n          \"value\": {\n            \"type\": 1,\n            \"string\": \"any\"\n          }\n        }\n      ]\n    },\n    \"clientAnnotations\": {\n      \"isEditedByUser\": true\n    },\n    \"isRequired\": true\n  },\n  {\n    \"instance\": {\n      \"key\": {\n        \"publicId\": \"access_consent\",\n        \"versionId\": \"1\"\n      },\n      \"param\": [\n        {\n          \"key\": \"consentTypes\",\n          \"value\": {\n            \"type\": 2,\n            \"listItem\": [\n              {\n                \"type\": 3,\n                \"mapKey\": [\n                  {\n                    \"type\": 1,\n                    \"string\": \"consentType\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"read\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"write\"\n                  }\n                ],\n                \"mapValue\": [\n                  {\n                    \"type\": 1,\n                    \"string\": \"ad_storage\"\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": true\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": false\n                  }\n                ]\n              }\n            ]\n          }\n        }\n      ]\n    },\n    \"clientAnnotations\": {\n      \"isEditedByUser\": true\n    },\n    \"isRequired\": true\n  },\n  {\n    \"instance\": {\n      \"key\": {\n        \"publicId\": \"access_local_storage\",\n        \"versionId\": \"1\"\n      },\n      \"param\": [\n        {\n          \"key\": \"keys\",\n          \"value\": {\n            \"type\": 2,\n            \"listItem\": [\n              {\n                \"type\": 3,\n                \"mapKey\": [\n                  {\n                    \"type\": 1,\n                    \"string\": \"key\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"read\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"write\"\n                  }\n                ],\n                \"mapValue\": [\n                  {\n                    \"type\": 1,\n                    \"string\": \"gtmeec-tt\"\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": true\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": true\n                  }\n                ]\n              }\n            ]\n          }\n        }\n      ]\n    },\n    \"clientAnnotations\": {\n      \"isEditedByUser\": true\n    },\n    \"isRequired\": true\n  },\n  {\n    \"instance\": {\n      \"key\": {\n        \"publicId\": \"access_template_storage\",\n        \"versionId\": \"1\"\n      },\n      \"param\": []\n    },\n    \"isRequired\": true\n  }\n]\n\n\n___TESTS___\n\nscenarios:\n- name: '[Happy Path] Pageview fires load, track and injects script'\n  code: |-\n    runCode(mockData);\n\n    // Verify TiktokAnalyticsObject definition\n    assertThat(windowData.TiktokAnalyticsObject).isEqualTo('ttq');\n\n    // Verify ttq internal state was populated successfully inside load\n    assertThat(getType(windowData.ttq._i)).isEqualTo('object');\n    assertThat(windowData.ttq._i['PIXEL123']._u).isEqualTo('https://analytics.tiktok.com/i18n/pixel/events.js');\n    assertThat(getType(windowData.ttq._t['PIXEL123'])).isEqualTo('number');\n    assertThat(getType(windowData.ttq._o['PIXEL123'])).isEqualTo('object');\n\n    const loadCalls = callInWindowCalls.filter((c) => c[0] === 'ttq.load');\n    assertThat(loadCalls.length).isEqualTo(1);\n    assertThat(loadCalls[0][1]).isEqualTo('PIXEL123');\n\n    const trackCalls = callInWindowCalls.filter((c) => c[0] === 'ttq.track');\n    assertThat(trackCalls.length).isEqualTo(1);\n    assertThat(trackCalls[0][1]).isEqualTo('Pageview');\n    assertThat(trackCalls[0][2].gtm_version).isEqualTo('stape_gtm_1_2_0');\n    assertThat(trackCalls[0][2].event_trigger_source).isEqualTo('GoogleTagManagerClient');\n    assertThat(trackCalls[0][3].pixel_code).isEqualTo('PIXEL123');\n\n    assertThat(injectScriptCalls.length).isEqualTo(1);\n    assertThat(injectScriptCalls[0].url).contains('analytics.tiktok.com');\n    assertThat(injectScriptCalls[0].url).contains('sdkid=PIXEL123');\n    assertThat(injectScriptCalls[0].url).contains('lib=ttq');\n    assertThat(injectScriptCalls[0].cacheToken).isEqualTo('ttqPixel-PIXEL123');\n\n    assertApi('gtmOnSuccess').wasCalled();\n    assertApi('gtmOnFailure').wasNotCalled();\n- name: '[Multiple Pixels] Each pixel gets separate load and track calls'\n  code: |-\n    mockData.pixelIds = 'AAA,BBB,CCC';\n\n    runCode(mockData);\n\n    const loadCalls = callInWindowCalls.filter((c) => c[0] === 'ttq.load');\n    assertThat(loadCalls.length).isEqualTo(3);\n    assertThat(loadCalls[0][1]).isEqualTo('AAA');\n    assertThat(loadCalls[1][1]).isEqualTo('BBB');\n    assertThat(loadCalls[2][1]).isEqualTo('CCC');\n\n    const trackCalls = callInWindowCalls.filter((c) => c[0] === 'ttq.track');\n    assertThat(trackCalls.length).isEqualTo(3);\n    assertThat(trackCalls[0][3].pixel_code).isEqualTo('AAA');\n    assertThat(trackCalls[1][3].pixel_code).isEqualTo('BBB');\n    assertThat(trackCalls[2][3].pixel_code).isEqualTo('CCC');\n\n    assertApi('gtmOnSuccess').wasCalled();\n    assertApi('gtmOnFailure').wasNotCalled();\n- name: '[Pixel Init] Already initialized pixel skips re-load but still tracks'\n  code: |-\n    mock('copyFromWindow', (key) => {\n      if (key === 'ttq') return {};\n      if (key === '_tiktok_gtm_ids') return { 'PIXEL123': true };\n      return undefined;\n    });\n\n    runCode(mockData);\n\n    const loadCalls = callInWindowCalls.filter((c) => c[0] === 'ttq.load');\n    assertThat(loadCalls.length).isEqualTo(0);\n\n    const trackCalls = callInWindowCalls.filter((c) => c[0] === 'ttq.track');\n    assertThat(trackCalls.length).isEqualTo(1);\n\n    assertApi('gtmOnSuccess').wasCalled();\n    assertApi('gtmOnFailure').wasNotCalled();\n- name: '[Consent] Manual consent evaluates granted/denied/modes'\n  code: |-\n    [\n      { value: true, action: 'grantConsent', expectLoad: true },\n      { value: 'granted', action: 'grantConsent', expectLoad: true },\n      { value: false, earlyExit: true },\n      { value: 'denied', earlyExit: true },\n      { value: undefined, action: 'grantConsent', expectLoad: true },\n      { optMode: 'optin', value: undefined, action: 'holdConsent', expectLoad: false },\n      { optMode: 'optin', value: true, action: 'grantConsent', expectLoad: true },\n      { optMode: 'optout', value: 'denied', earlyExit: true }\n    ].forEach((scenario) => {\n      callInWindowCalls = [];\n      injectScriptCalls = [];\n      windowData = {};\n      templateStorageData = {};\n\n      const testData = assign(assign({}, mockData), {\n        consent: scenario.value\n      });\n      if (scenario.optMode) {\n        testData.consentOptMode = scenario.optMode;\n      }\n\n      mock('injectScript', (url, onsuccess) => {\n        injectScriptCalls.push({ url: url });\n        onsuccess();\n      });\n\n      runCode(testData);\n\n      if (scenario.earlyExit) {\n        assertThat(callInWindowCalls.length).isEqualTo(0);\n      } else {\n        const actionCalls = callInWindowCalls.filter((c) => c[0] === 'ttq.' + scenario.action);\n        assertThat(actionCalls.length).isEqualTo(1);\n\n        const loadCalls = callInWindowCalls.filter((c) => c[0] === 'ttq.load');\n        if (scenario.expectLoad) {\n          assertThat(loadCalls.length).isEqualTo(1);\n        } else {\n          assertThat(loadCalls.length).isEqualTo(0);\n        }\n      }\n\n      assertApi('gtmOnSuccess').wasCalled();\n      assertApi('gtmOnFailure').wasNotCalled();\n    });\n- name: '[Consent] GTM consent mode behavior'\n  code: |-\n    [\n      { isGranted: false, earlyExit: true },\n      { isGranted: false, optMode: 'optin', expectAction: 'holdConsent', expectLoad: false, expectListener: true },\n      { isGranted: true, expectAction: 'grantConsent', expectLoad: true, expectListener: false },\n      { isGranted: true, optMode: 'optin', expectAction: 'grantConsent', expectLoad: true, expectListener: false }\n    ].forEach((scenario) => {\n      callInWindowCalls = [];\n      injectScriptCalls = [];\n      windowData = {};\n      templateStorageData = {};\n\n      const testData = assign(assign({}, mockData), {\n        enableGoogleConsentMode: true\n      });\n      if (scenario.optMode) {\n        testData.consentOptMode = scenario.optMode;\n      }\n\n      mock('isConsentGranted', () => scenario.isGranted);\n\n      let listenerCalled = false;\n      mock('addConsentListener', () => { listenerCalled = true; });\n\n      mock('injectScript', (url, onsuccess) => {\n        injectScriptCalls.push({ url: url });\n        onsuccess();\n      });\n\n      runCode(testData);\n\n      if (scenario.earlyExit) {\n        assertThat(callInWindowCalls.length).isEqualTo(0);\n      } else {\n        const actionCalls = callInWindowCalls.filter((c) => c[0] === 'ttq.' + scenario.expectAction);\n        assertThat(actionCalls.length).isEqualTo(1);\n\n        const loadCalls = callInWindowCalls.filter((c) => c[0] === 'ttq.load');\n        if (scenario.expectLoad) {\n          assertThat(loadCalls.length).isEqualTo(1);\n        } else {\n          assertThat(loadCalls.length).isEqualTo(0);\n        }\n\n        if (scenario.expectListener) {\n          assertThat(listenerCalled).isTrue();\n        }\n      }\n\n      assertApi('gtmOnSuccess').wasCalled();\n      assertApi('gtmOnFailure').wasNotCalled();\n    });\n- name: '[Consent] Listener fires queued callbacks when consent is later granted'\n  code: |-\n    mockData.enableGoogleConsentMode = true;\n    mockData.consentOptMode = 'optin';\n    mock('isConsentGranted', () => false);\n\n    let consentListenerCallback;\n    mock('addConsentListener', (type, callback) => {\n      consentListenerCallback = callback;\n    });\n\n    runCode(mockData);\n\n    const loadCallsBefore = callInWindowCalls.filter((c) => c[0] === 'ttq.load');\n    assertThat(loadCallsBefore.length).isEqualTo(0);\n\n    assertApi('gtmOnSuccess').wasCalled();\n    assertApi('gtmOnFailure').wasNotCalled();\n\n    consentListenerCallback('ad_storage', true);\n\n    const grantCalls = callInWindowCalls.filter((c) => c[0] === 'ttq.grantConsent');\n    assertThat(grantCalls.length).isGreaterThan(0);\n\n    const loadCallsAfter = callInWindowCalls.filter((c) => c[0] === 'ttq.load');\n    assertThat(loadCallsAfter.length).isEqualTo(1);\n- name: '[Event Name] Resolves inherited and overridden event names'\n  code: |-\n    [\n      { method: 'inherit', dlEvent: 'page_view', expected: 'Pageview' },\n      { method: 'inherit', dlEvent: 'purchase', expected: 'Purchase' },\n      { method: 'inherit', dlEvent: 'page_view_stape', expected: 'Pageview' },\n      { method: 'inherit', dlEvent: 'gtm4wp.productClickEEC', expected: 'ViewContent' },\n      { method: 'inherit', dlEvent: 'my_custom_dl_event', expected: 'my_custom_dl_event' },\n      { method: 'override', eventName: 'standard', eventNameStandard: 'AddToCart', expected: 'AddToCart' },\n      { method: 'override', eventName: 'custom', eventNameCustom: 'MyCustomEvent', expected: 'MyCustomEvent' }\n    ].forEach((scenario) => {\n      callInWindowCalls = [];\n      injectScriptCalls = [];\n\n      const testData = assign(assign({}, mockData), {\n        eventNameSetupMethod: scenario.method\n      });\n      if (scenario.eventName) testData.eventName = scenario.eventName;\n      if (scenario.eventNameStandard) testData.eventNameStandard = scenario.eventNameStandard;\n      if (scenario.eventNameCustom) testData.eventNameCustom = scenario.eventNameCustom;\n\n      mock('copyFromDataLayer', (key) => {\n        if (key === 'event') return scenario.dlEvent;\n        return undefined;\n      });\n\n      mock('injectScript', (url, onsuccess) => {\n        injectScriptCalls.push({ url: url });\n        onsuccess();\n      });\n\n      runCode(testData);\n\n      const trackCalls = callInWindowCalls.filter((c) => c[0] === 'ttq.track');\n      assertThat(trackCalls.length).isEqualTo(1);\n      assertThat(trackCalls[0][1]).isEqualTo(scenario.expected);\n\n      assertApi('gtmOnSuccess').wasCalled();\n      assertApi('gtmOnFailure').wasNotCalled();\n    });\n- name: '[User Data] Evaluates variables, arrays and tables'\n  code: |-\n    [\n      { desc: 'simple values', ud: { email: 'test@example.com', phone: '+1234567890' }, expectEmail: 'test@example.com', expectPhone: '+1234567890', list: [{ name: 'external_id', value: 'ext123' }], expectExt: 'ext123' },\n      { desc: 'array values', ud: { email: ['first@example.com', 'second@example.com'], phone: ['+111', '+222'] }, expectEmail: 'first@example.com', expectPhone: '+111' }\n    ].forEach((scenario) => {\n      callInWindowCalls = [];\n      const testData = assign(assign({}, mockData), {\n        enableAdvancedMatching: true,\n        userDataFromVariable: scenario.ud\n      });\n      if (scenario.list) testData.userDataList = scenario.list;\n\n      runCode(testData);\n\n      const identifyCalls = callInWindowCalls.filter((c) => c[0] === 'ttq.identify');\n      assertThat(identifyCalls.length).isEqualTo(1);\n      const userData = identifyCalls[0][1];\n      assertThat(userData.email).isEqualTo(scenario.expectEmail);\n      assertThat(userData.phone_number).isEqualTo(scenario.expectPhone);\n      if (scenario.expectExt) {\n        assertThat(userData.external_id).isEqualTo(scenario.expectExt);\n      }\n      assertApi('gtmOnSuccess').wasCalled();\n      assertApi('gtmOnFailure').wasNotCalled();\n    });\n- name: '[User Data] Parses user data and external ID from DataLayer'\n  code: \"[\\n  { desc: 'user_data object', dlKey: 'user_data', dlValue: { email: 'dl@example.com',\\\n    \\ phone: '+1555000000', external_id: 'ext123' }, expectExt: 'ext123', expectEmail:\\\n    \\ 'dl@example.com', expectPhone: '+1555000000' },\\n  { desc: 'dl external_id',\\\n    \\ dlKey: 'external_id', dlValue: 'ext-dl', expectExt: 'ext-dl' },\\n  { desc: 'dl\\\n    \\ user_id', dlKey: 'user_id', dlValue: 'uid-dl', expectExt: 'uid-dl' },\\n  { desc:\\\n    \\ 'dl userId', dlKey: 'userId', dlValue: 'userId-dl', expectExt: 'userId-dl' }\\n\\\n    ].forEach((scenario) => {\\n  callInWindowCalls = [];\\n  injectScriptCalls = [];\\n\\\n    \\n  const testData = assign(assign({}, mockData), {\\n    enableAdvancedMatching:\\\n    \\ true,\\n    enableDataLayerMapping: true\\n  });\\n\\n  if (scenario.dlKey !== 'user_data')\\\n    \\ {\\n    testData.userDataFromVariable = { email: 'test@example.com' };\\n  }\\n\\\n    \\n  mock('copyFromDataLayer', (key) => {\\n    if (scenario.dlKey !== 'user_data'\\\n    \\ && key === 'user_data') {\\n      return { email: 'test@example.com' };\\n   \\\n    \\ }\\n    if (key === scenario.dlKey) {\\n      return scenario.dlValue;\\n    }\\n\\\n    \\    return undefined;\\n  });\\n\\n  mock('injectScript', (url, onsuccess) => {\\n\\\n    \\    injectScriptCalls.push({ url: url });\\n    onsuccess();\\n  });\\n\\n  runCode(testData);\\n\\\n    \\n  const identifyCalls = callInWindowCalls.filter((c) => c[0] === 'ttq.identify');\\n\\\n    \\  assertThat(identifyCalls.length).isEqualTo(1);\\n  \\n  const userData = identifyCalls[0][1];\\n\\\n    \\  if (scenario.expectEmail) assertThat(userData.email).isEqualTo(scenario.expectEmail);\\n\\\n    \\  if (scenario.expectPhone) assertThat(userData.phone_number).isEqualTo(scenario.expectPhone);\\n\\\n    \\  if (scenario.expectExt) assertThat(userData.external_id).isEqualTo(scenario.expectExt);\\n\\\n    \\n  assertApi('gtmOnSuccess').wasCalled();\\n  assertApi('gtmOnFailure').wasNotCalled();\\n\\\n    });\"\n- name: '[User Data] Empty, falsy or disabled skips identify call'\n  code: |-\n    [\n      { desc: 'empty object', ud: {}, am: true },\n      { desc: 'all-falsy values', ud: { email: '', phone: null }, am: true },\n      { desc: 'disabled am', ud: { email: 'test@example.com' }, am: false }\n    ].forEach((scenario) => {\n      callInWindowCalls = [];\n      const testData = assign(assign({}, mockData), {\n        enableAdvancedMatching: scenario.am,\n        userDataFromVariable: scenario.ud\n      });\n\n      runCode(testData);\n\n      const identifyCalls = callInWindowCalls.filter((c) => c[0] === 'ttq.identify');\n      assertThat(identifyCalls.length).isEqualTo(0);\n\n      assertApi('gtmOnSuccess').wasCalled();\n      assertApi('gtmOnFailure').wasNotCalled();\n    });\n- name: '[Event Data] GA4 Purchase with multiple items builds correct properties'\n  code: |-\n    const testData = assign(assign({}, mockData), {\n      eventNameStandard: 'Purchase',\n      enableDataLayerMapping: true\n    });\n\n    mock('copyFromDataLayer', (key) => {\n      if (key === 'items') return [\n        { item_id: 'SKU1', item_name: 'Product 1', price: 10, quantity: 2, currency: 'EUR' },\n        { item_id: 'SKU2', item_name: 'Product 2', price: 25, quantity: 1 }\n      ];\n      if (key === 'value') return 45;\n      if (key === 'currency') return 'EUR';\n      if (key === 'transaction_id') return 'TXN-001';\n      return undefined;\n    });\n\n    runCode(testData);\n\n    const trackCalls = callInWindowCalls.filter((c) => c[0] === 'ttq.track');\n    assertThat(trackCalls.length).isEqualTo(1);\n\n    const eventData = trackCalls[0][2];\n    assertThat(eventData.content_type).isEqualTo('product');\n    assertThat(eventData.content_ids).isEqualTo(['SKU1', 'SKU2']);\n    assertThat(eventData.contents.length).isEqualTo(2);\n    assertThat(eventData.contents[0].content_id).isEqualTo('SKU1');\n    assertThat(eventData.contents[0].quantity).isEqualTo(2);\n    assertThat(eventData.contents[1].content_id).isEqualTo('SKU2');\n    assertThat(eventData.contents[1].quantity).isEqualTo(1);\n    assertThat(eventData.value).isEqualTo(45);\n    assertThat(eventData.currency).isEqualTo('EUR');\n    assertThat(eventData.order_id).isEqualTo('TXN-001');\n    assertThat(eventData.num_items).isDefined();\n\n    assertApi('gtmOnSuccess').wasCalled();\n    assertApi('gtmOnFailure').wasNotCalled();\n- name: '[Event Data] GA4 single item includes content_name and content_category'\n  code: |-\n    const testData = assign(assign({}, mockData), {\n      eventNameStandard: 'ViewContent',\n      enableDataLayerMapping: true\n    });\n\n    mock('copyFromDataLayer', (key) => {\n      if (key === 'items') return [\n        { item_id: 'SINGLE1', item_name: 'My Product', item_category: 'Electronics', price: 99, quantity: 1 }\n      ];\n      return undefined;\n    });\n\n    runCode(testData);\n\n    const trackCalls = callInWindowCalls.filter((c) => c[0] === 'ttq.track');\n    const eventData = trackCalls[0][2];\n    assertThat(eventData.contents[0].content_name).isEqualTo('My Product');\n    assertThat(eventData.contents[0].content_category).isEqualTo('Electronics');\n    assertThat(eventData.content_type).isEqualTo('product');\n\n    assertApi('gtmOnSuccess').wasCalled();\n    assertApi('gtmOnFailure').wasNotCalled();\n- name: '[Event Data] UA Purchase with products builds correct properties'\n  code: |-\n    const testData = assign(assign({}, mockData), {\n      eventNameStandard: 'Purchase',\n      enableDataLayerMapping: true\n    });\n\n    mock('copyFromDataLayer', (key) => {\n      if (key === 'ecommerce') return {\n        currencyCode: 'GBP',\n        purchase: {\n          products: [\n            { id: 'P1', price: '15.99', quantity: '3' },\n            { id: 'P2', price: '8.50', quantity: '1' }\n          ]\n        }\n      };\n      return undefined;\n    });\n\n    runCode(testData);\n\n    const trackCalls = callInWindowCalls.filter((c) => c[0] === 'ttq.track');\n    assertThat(trackCalls.length).isEqualTo(1);\n\n    const eventData = trackCalls[0][2];\n    assertThat(eventData.content_type).isEqualTo('product');\n    assertThat(eventData.content_ids).isEqualTo(['P1', 'P2']);\n    assertThat(eventData.currency).isEqualTo('GBP');\n    assertThat(eventData.contents.length).isEqualTo(2);\n    assertThat(eventData.num_items).isDefined();\n\n    assertApi('gtmOnSuccess').wasCalled();\n    assertApi('gtmOnFailure').wasNotCalled();\n- name: '[Event Data] Parameters and additional parameters merge correctly'\n  code: |-\n    [\n      { type: 'standard', varKey: 'eventParametersFromVariable', listKey: 'eventParametersList', ud: { content_name: 'My Product', value: 99 }, list: [{ name: 'currency', value: 'USD' }, { name: 'content_type', value: 'product' }], expectName: 'My Product', expectValue: 99, expectCurrency: 'USD', expectContentType: 'product' },\n      { type: 'additional', varKey: 'additionalEventParametersFromVariable', listKey: 'additionalEventParametersList', ud: { custom_param: 'foo' }, list: [{ name: 'another_param', value: 'bar' }], expectCustom: 'foo', expectAnother: 'bar' }\n    ].forEach((scenario) => {\n      callInWindowCalls = [];\n      const testData = assign({}, mockData);\n      testData[scenario.varKey] = scenario.ud;\n      testData[scenario.listKey] = scenario.list;\n\n      if (scenario.type === 'standard') {\n         testData.eventNameStandard = 'Search';\n         testData.enableDataLayerMapping = true;\n         mock('copyFromDataLayer', (key) => key === 'search_term' ? 'blue shoes' : undefined);\n      } else {\n         mock('copyFromDataLayer', () => undefined);\n      }\n\n      runCode(testData);\n\n      const trackCalls = callInWindowCalls.filter((c) => c[0] === 'ttq.track');\n      const eventData = trackCalls[0][2];\n\n      if (scenario.type === 'standard') {\n        assertThat(eventData.content_name).isEqualTo(scenario.expectName);\n        assertThat(eventData.value).isEqualTo(scenario.expectValue);\n        assertThat(eventData.currency).isEqualTo(scenario.expectCurrency);\n        assertThat(eventData.content_type).isEqualTo(scenario.expectContentType);\n        assertThat(eventData.search_string).isEqualTo('blue shoes');\n      } else {\n        assertThat(eventData.custom_param).isEqualTo(scenario.expectCustom);\n        assertThat(eventData.another_param).isEqualTo(scenario.expectAnother);\n      }\n      assertApi('gtmOnSuccess').wasCalled();\n      assertApi('gtmOnFailure').wasNotCalled();\n    });\n- name: '[Event ID] Passes event_id in track call options'\n  code: |-\n    mockData.eventId = 'evt-abc-123';\n\n    runCode(mockData);\n\n    const trackCalls = callInWindowCalls.filter((c) => c[0] === 'ttq.track');\n    assertThat(trackCalls.length).isEqualTo(1);\n    assertThat(trackCalls[0][3].event_id).isEqualTo('evt-abc-123');\n\n    assertApi('gtmOnSuccess').wasCalled();\n    assertApi('gtmOnFailure').wasNotCalled();\n- name: '[DataLayer Push] Pushes event with custom and default settings'\n  code: |-\n    [\n      {\n        desc: 'custom name and layer',\n        eventIdDataLayerEventName: 'tt_pageview',\n        eventIdDataLayerVariableName: 'myDataLayer',\n        eventId: 'evt-123',\n        expectedLayer: 'myDataLayer',\n        expectedEvent: 'tt_pageview'\n      },\n      {\n        desc: 'defaults when not specified',\n        eventIdDataLayerEventName: undefined,\n        eventIdDataLayerVariableName: undefined,\n        eventId: 'evt-456',\n        expectedLayer: 'dataLayer',\n        expectedEvent: 'tiktokPixelDataLayerPush'\n      }\n    ].forEach((scenario) => {\n      createQueueItems = [];\n      const testData = assign(assign({}, mockData), {\n        pushEventIdToDataLayer: true,\n        eventIdDataLayerEventName: scenario.eventIdDataLayerEventName,\n        eventIdDataLayerVariableName: scenario.eventIdDataLayerVariableName,\n        eventId: scenario.eventId\n      });\n\n      runCode(testData);\n\n      const dlPushes = createQueueItems.filter((c) => c[0] === scenario.expectedLayer);\n      assertThat(dlPushes.length).isEqualTo(1);\n      assertThat(dlPushes[0][1].event).isEqualTo(scenario.expectedEvent);\n      assertThat(dlPushes[0][1].eventId).isEqualTo(scenario.eventId);\n\n      assertApi('gtmOnSuccess').wasCalled();\n      assertApi('gtmOnFailure').wasNotCalled();\n    });\n- name: '[Scripts] Script load failure calls gtmOnFailure'\n  code: \"// callLater is used to simulate the async calling of onFailure.\\n\\nmock('injectScript',\\\n    \\ (url, onsuccess, onfailure) => {\\n  injectScriptCalls.push({ url: url });\\n\\\n    \\  callLater(() => { onfailure(); }); \\n  onfailure();\\n});\\n\\nrunCode(mockData);\\n\\\n    \\ncallLater(() => {\\n  assertApi('gtmOnSuccess').wasNotCalled();\\n  assertApi('gtmOnFailure').wasCalled();\\n\\\n    });\\n\"\n- name: '[Settings] Passes limited_data_use correctly based on modeLDU'\n  code: |-\n    [\n      { mode: 'all', expectLoadLDU: true, expectTrackLDU: undefined },\n      { mode: 'single', expectLoadLDU: undefined, expectTrackLDU: true }\n    ].forEach((scenario) => {\n      callInWindowCalls = [];\n      const testData = assign(assign({}, mockData), {\n        enableLDU: true,\n        modeLDU: scenario.mode\n      });\n\n      runCode(testData);\n\n      const loadCalls = callInWindowCalls.filter((c) => c[0] === 'ttq.load');\n      const trackCalls = callInWindowCalls.filter((c) => c[0] === 'ttq.track');\n\n      if (scenario.expectLoadLDU) {\n        assertThat(loadCalls.length).isEqualTo(1);\n        assertThat(loadCalls[0][2].limited_data_use).isTrue();\n      }\n      if (scenario.expectTrackLDU) {\n        assertThat(trackCalls.length).isEqualTo(1);\n        assertThat(trackCalls[0][2].limited_data_use).isTrue();\n      }\n\n      assertApi('gtmOnSuccess').wasCalled();\n      assertApi('gtmOnFailure').wasNotCalled();\n    });\n- name: '[Settings] disableHistoryObserver passes historyObserver false in load options'\n  code: |-\n    mockData.disableHistoryObserver = true;\n\n    runCode(mockData);\n\n    const loadCalls = callInWindowCalls.filter((c) => c[0] === 'ttq.load');\n    assertThat(loadCalls.length).isEqualTo(1);\n    assertThat(loadCalls[0][2].historyObserver).isFalse();\n\n    assertApi('gtmOnSuccess').wasCalled();\n    assertApi('gtmOnFailure').wasNotCalled();\n- name: '[Event Enhancement] Uses localStorage for User Data (plain & hashed)'\n  code: |-\n    [\n      { desc: 'reads/writes plain', hash: false, preload: '{\"email\":\"stored@example.com\"}', ud: { phone: '+1999999999' }, expectEmail: 'stored@example.com', expectPhone: '+1999999999' },\n      { desc: 'sync hash', hash: true, preload: undefined, ud: { email: 'test@example.com' }, expectEmail: 'abc123hash', setupSyncHash: true },\n      { desc: 'async hash', hash: true, preload: undefined, ud: { email: 'test@example.com' }, expectEmail: 'async_hashed_test@example.com', setupAsyncHash: true },\n      { desc: 'consent denied skips storage', hash: false, preload: undefined, ud: { email: 'test@example.com' }, consentDenied: true }\n    ].forEach((scenario) => {\n      callInWindowCalls = [];\n      localStorageData = {};\n      windowData = {};\n      mock('sha256', (input, successCb, errorCb, options) => {\n        successCb('hashed_' + input);\n      });\n      if (scenario.preload) localStorageData['gtmeec-tt'] = scenario.preload;\n\n      if (scenario.setupSyncHash) {\n        windowData.dataTag256 = function() { return 'abc123hash'; };\n      }\n      if (scenario.setupAsyncHash) {\n        mock('sha256', (input, successCb) => successCb('async_hashed_' + input));\n      }\n\n      const testData = assign(assign({}, mockData), {\n        enableAdvancedMatching: true,\n        enableEventUserDataEnhancement: true,\n        storeUserDataHashed: scenario.hash,\n        userDataFromVariable: scenario.ud\n      });\n\n      if (scenario.consentDenied) {\n        testData.consentOptMode = 'optin';\n        testData.consent = undefined;\n      }\n\n      runCode(testData);\n\n      if (scenario.consentDenied) {\n        assertThat(localStorageData['gtmeec-tt']).isUndefined();\n      } else {\n        const identifyCalls = callInWindowCalls.filter((c) => c[0] === 'ttq.identify');\n        if (identifyCalls.length > 0) {\n          const userData = identifyCalls[0][1];\n          if (scenario.expectEmail && !scenario.hash) assertThat(userData.email).isEqualTo(scenario.expectEmail);\n          if (scenario.expectPhone) assertThat(userData.phone_number).isEqualTo(scenario.expectPhone);\n        }\n\n        assertThat(localStorageData['gtmeec-tt']).isDefined();\n        const stored = JSON.parse(localStorageData['gtmeec-tt']);\n        if (scenario.expectEmail) assertThat(stored.email).isEqualTo(scenario.expectEmail);\n        if (scenario.expectPhone) assertThat(stored.phone_number).isEqualTo(scenario.expectPhone);\n      }\n\n      assertApi('gtmOnSuccess').wasCalled();\n      assertApi('gtmOnFailure').wasNotCalled();\n    });\n- name: '[DL Version] enableMostRecentDataLayerEventOnly uses DL version 1'\n  code: |-\n    let capturedVersion;\n    mock('copyFromDataLayer', (key, version) => {\n      if (key === 'search_term') {\n        capturedVersion = version;\n        return 'test query';\n      }\n      return undefined;\n    });\n\n    const testData = assign(assign({}, mockData), {\n      enableDataLayerMapping: true,\n      enableMostRecentDataLayerEventOnly: true,\n      eventNameStandard: 'Search'\n    });\n\n    runCode(testData);\n\n    assertThat(capturedVersion).isEqualTo(1);\n\n    assertApi('gtmOnSuccess').wasCalled();\n    assertApi('gtmOnFailure').wasNotCalled();\n- name: '[Validation] Empty pixelIds array calls gtmOnFailure'\n  code: |-\n    mockData.pixelIds = '';\n\n    runCode(mockData);\n\n    assertApi('gtmOnSuccess').wasNotCalled();\n    assertApi('gtmOnFailure').wasCalled();\n- name: '[Queue] Existing ttq queue is reused, not recreated'\n  code: |-\n    // Pre-populate ttq in the simulated window so getOrCreateTikTokQueue\n    // returns early. Also mark the pixel as already initialized so sendEvent\n    // skips calling ttq.load (which doesn't exist on this plain object) and\n    // reaches gtmOnSuccess via the loadWasNotCalled path.\n    windowData.ttq = { existing: true };\n    windowData._tiktok_gtm_ids = { 'PIXEL123': true };\n\n    runCode(mockData);\n\n    assertApi('setInWindow').wasNotCalledWith('TiktokAnalyticsObject', 'ttq');\n\n    assertApi('gtmOnSuccess').wasCalled();\n    assertApi('gtmOnFailure').wasNotCalled();\nsetup: \"const JSON = require('JSON');\\nconst Object = require('Object');\\nconst getType\\\n  \\ = require('getType');\\nconst callLater = require('callLater');\\n\\nconst PARTNER_NAME\\\n  \\ = 'stape_gtm_1_2_0';\\n\\nconst assign = (target, source) => {\\n  if (!source) return\\\n  \\ target;\\n  Object.keys(source).forEach((key) => { target[key] = source[key]; });\\n\\\n  \\  return target;\\n};\\n\\n// Simulated window — shared between setInWindow, copyFromWindow,\\\n  \\ callInWindow\\nlet windowData = {};\\n\\nconst getWindowValue = (key) => {\\n  const\\\n  \\ parts = key.split('.');\\n  let obj = windowData;\\n  for (let i = 0; i < parts.length;\\\n  \\ i++) {\\n    if (obj === undefined || obj === null) return undefined;\\n    obj\\\n  \\ = obj[parts[i]];\\n  }\\n  return obj;\\n};\\n\\nconst setWindowValue = (key, value)\\\n  \\ => {\\n  const parts = key.split('.');\\n  let obj = windowData;\\n  for (let i =\\\n  \\ 0; i < parts.length - 1; i++) {\\n    if (obj[parts[i]] === undefined || obj[parts[i]]\\\n  \\ === null) obj[parts[i]] = {};\\n    obj = obj[parts[i]];\\n  }\\n  obj[parts[parts.length\\\n  \\ - 1]] = value;\\n};\\n\\nlet callInWindowCalls = [];\\n\\nmock('setInWindow', (key,\\\n  \\ value, override) => {\\n  setWindowValue(key, value);\\n});\\n\\nlet injectScriptCalls\\\n  \\ = [];\\nmock('injectScript', (url, onsuccess, onfailure, cacheToken) => {\\n  injectScriptCalls.push({\\\n  \\ url: url, onsuccess: onsuccess, onfailure: onfailure, cacheToken: cacheToken });\\n\\\n  \\  // It runs sync here. In real world is async. \\n  // Wrap the callbacks in callLater()\\\n  \\ if necessary (e.g. callLater(() => { onsuccess(); }). If doing that, also wrap\\\n  \\ the assertions in callLater.\\n  onsuccess();\\n});\\n\\nmock('copyFromWindow', (key)\\\n  \\ => {\\n  return getWindowValue(key);\\n});\\n\\nmock('callInWindow', function() {\\n\\\n  \\  const args = [];\\n  for (let i = 0; i < arguments.length; i++) {\\n    args.push(arguments[i]);\\n\\\n  \\  }\\n  callInWindowCalls.push(args);\\n\\n  const fn = getWindowValue(args[0]);\\n\\\n  \\  if (getType(fn) === 'function') {\\n    return fn(args[1], args[2], args[3], args[4],\\\n  \\ args[5]);\\n  }\\n  return undefined;\\n});\\n\\nlet createQueueItems = [];\\nmock('createQueue',\\\n  \\ (name) => {\\n  return (item) => { createQueueItems.push([name, item]); };\\n});\\n\\\n  \\nmock('copyFromDataLayer', () => undefined);\\nmock('isConsentGranted', () => true);\\n\\\n  mock('addConsentListener', () => {});\\nmock('getTimestampMillis', () => 1234567890);\\n\\\n  mock('encodeUriComponent', (val) => val);\\nmock('makeString', (val) => '' + val);\\n\\\n  mock('makeNumber', (val) => val * 1);\\nmock('getType', (val) => {\\n  if (val ===\\\n  \\ null) return 'null';\\n  if (val === undefined) return 'undefined';\\n  if (getType(val)\\\n  \\ === 'boolean') return 'boolean';\\n  if (getType(val) === 'number') return 'number';\\n\\\n  \\  if (getType(val) === 'string') return 'string';\\n  if (getType(val) === 'function')\\\n  \\ return 'function';\\n  if (getType(val) === 'array') return 'array';\\n  if (getType(val)\\\n  \\ === 'object') return 'object';\\n  return 'object';\\n});\\n\\nlet templateStorageData\\\n  \\ = {};\\nmockObject('templateStorage', {\\n  getItem: (key) => templateStorageData[key],\\n\\\n  \\  setItem: (key, value) => { templateStorageData[key] = value; },\\n  removeItem:\\\n  \\ (key) => { Object.delete(templateStorageData, key); }\\n});\\n\\nlet localStorageData\\\n  \\ = {};\\nmockObject('localStorage', {\\n  getItem: (key) => localStorageData[key],\\n\\\n  \\  setItem: (key, value) => { localStorageData[key] = value; }\\n});\\n\\nmock('makeTableMap',\\\n  \\ (table, keyName, valueName) => {\\n  const result = {};\\n  table.forEach((row)\\\n  \\ => { result[row[keyName]] = row[valueName]; });\\n  return result;\\n});\\n\\nmock('sha256',\\\n  \\ (input, successCb, errorCb, options) => {\\n  successCb('hashed_' + input);\\n});\\n\\\n  \\nconst mockData = {\\n  pixelIds: 'PIXEL123',\\n  consent: true,\\n  enableGoogleConsentMode:\\\n  \\ false,\\n  eventNameSetupMethod: 'override',\\n  eventName: 'standard',\\n  eventNameStandard:\\\n  \\ 'Pageview',\\n  enableDataLayerMapping: false,\\n  enableAdvancedMatching: false,\\n\\\n  \\  enableLDU: false,\\n  disableHistoryObserver: false,\\n  pushEventIdToDataLayer:\\\n  \\ false,\\n  enableEventUserDataEnhancement: false,\\n  storeUserDataHashed: false,\\n\\\n  \\  enableMostRecentDataLayerEventOnly: false,\\n  gtmTagId: 'tag-1',\\n  gtmEventId:\\\n  \\ 'event-1'\\n};\"\n\n\n___NOTES___\n\n2026-04-09 - Change Notes:\n  - Pixel script (.js) now loads only after consent is granted. Previously, the\n  script loaded immediately regardless of consent state.\n  - Added TikTok Consent Mode to Google Consent Mode option.\n  - Fixed \"Additional Event Parameters\" fields not being read due to a field\n  name mismatch between the UI and the tag code.\n  - Updated partner name to stape_gtm_1_2_0.\n  - Removed duplicate email field reference in user data mapping.\n\nCreated on 11/25/2025, 10:44:33 AM\n\n\n",
                "galleryReference": {
                    "host": "github.com",
                    "owner": "stape-io",
                    "repository": "tiktok-web-tag",
                    "version": "285b623469173a25d6b5506bdf49c7d530e8f005",
                    "signature": "d7f67bdeafe587c0a3dc451882c74ad2cb39802ffe07f340038e03ab1dd10a84",
                    "galleryTemplateId": "KF8K9"
                }
            },
            {
                "accountId": "6268264869",
                "containerId": "255515747",
                "templateId": "15",
                "name": "Data Tag",
                "fingerprint": "1781525859919",
                "templateData": "___TERMS_OF_SERVICE___\n\nBy creating or modifying this file you agree to Google Tag Manager's Community\nTemplate Gallery Developer Terms of Service available at\nhttps://developers.google.com/tag-manager/gallery-tos (or such other URL as\nGoogle may provide), as modified from time to time.\n\n\n___INFO___\n\n{\n  \"type\": \"TAG\",\n  \"id\": \"cvt_MBTSV\",\n  \"version\": 1,\n  \"displayName\": \"Data Tag\",\n  \"categories\": [\n    \"ANALYTICS\",\n    \"CONVERSIONS\"\n  ],\n  \"brand\": {\n    \"id\": \"github.com_stape-io\",\n    \"displayName\": \"stape-io\",\n    \"thumbnail\": \"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAgAAAAIACAYAAAD0eNT6AAAACXBIWXMAAAsTAAALEwEAmpwYAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAABjkSURBVHgB7d1dclRXmi7gbymTEyei+kJnBK0aQcmBOFF3FiM4eATAbR8MYgSIEVgUct1aHgHUCFDdVXSJsGoEzh5B66I6oiOszNX5Q7txmR/tzJ2Za+39PBeAfUmIzHd/63vXTsHa5aODw5jEl5FjP1Lej5x2p/97NwBYSHE5/Yy8mv7+59iJ83RycR6sVQrWIh8d7sbk70+mP9BH4cseoKE0ipicx+DW83Tyl1HQOgGgZb74AVq2EyeRhi8EgXYJAC1ajPrTd5HzXgDQoulEIOeH6dTRQFt2glbkxwfPYhxvfPkDrMP0szXFm/lnLa0wAWjB/Acyx3EAsH4pjtMfLp4HKxEAVuTLH2ALhICVCQAryI/+771Ik1cBwObluGsnYHkCwJLy0e/3YjJ25g+wPVcxuP5tOrm8ChqzBLis65+OffkDbNVujAffBEsxAVjC/Ol/fP1jALB9jgKWYgKwjNnTPwBl2Mn3gsZMABrKR/vTkdPw3wOAUtgFWIIJQFPjW5ImQFl2fTY3JwA0lSeHAUBpvgwaEQCa2km/CwBKcxg0IgA0lWM/ACiMWnZTAkAD8/ofAEXyGd2MAAAAPSQAAEAPCQAA0EMCAAD0kAAAAD0kAABADwkAANBDAgAA9JAAAAA9JAAAQA8JAADQQwIAAPSQAABAJ6STv4yCGxMAAKhfisugEQEAgPrl+LegEQEAgA5Ir4NGBAAA6jcYnAeNCAAA1O5PFgCbEwAAqFuOk6AxAQCAmp2n04vzoDEBAIB6DYYPg6UIAABUKp85+1/eMACgOmk0ffp/HixNAACgPpP8Ir309L8KRwAAVCaN0rcXNv9XJAAAUBuj/xY4AgCgIvksvbw4C1ZmAgBAPQa3PP23RAAAoA45v1D7a48jAAAqkEYxHFr8a5EJAAA1eO7pv10CAACFS6P08q9nQasEAADKNo6vgtbZAQCgYPks/fHiMmidCQAA5VL7WxsBAIAyZYt/6yQAAFCgNEqnF8fB2ggAAJTI6H/NBAAACqP2twkCAABlGQzuBmsnAABQkHxm8W8zBAAASnGl9rc5AgAAZcjhbX8bJAAAUAC1v00TAAAogdH/hgkAAGzba7W/zRMAANiuwfBpsHECAABbpPa3LV4HDMCWpNH06d/Z/5aYAACwLd72t0UCAABb4L7/bRMAANi8PLH4t2UCAAAbls/S6dvXwVYJAABslvv+iyAAALA52eJfKdQAAdiQNIrh4CwoggkAAJvi6b8gAgAAG6D2VxoBAID1G8dXQVHsAACwZvks/fHiMiiKCQAA66X2VyQBAID1UfsrlgAAwJqkUTq9OA6KJAAAsC5G/wUTAABoX4pLtb+yCQAAtG9nqPZXOAEAgJblM4t/5XMPAAAtSqMYDJ39V8AEAID25Py9p/86CAAAtETtryYCAABtMfqviAAAQBteq/3VRQAAYHWD4dOgKgIAACtS+6uRGiAAK1D7q5UJAACr8La/SgkAACwpjSz+1UsAAGA5eWLxr2ICAABLyGfp9O3roFoCAADNDW5Z/KucAABAM9niXxeoAQLQQBrF8DcnQfVMAABoYvr0f34VVE8AAOCG1P66RAAA4GYGg7tBZwgAANyA+/67RgAA4PPU/jpHAADg09T+OkkAAOAT0iidXhwHnSMAAPApRv8dJQAA8DHnan/dJQAA8GGD4cOgswQAAD5A7a/rvAsAgH+QRtOnf2f/HScAAPBLk/wivfT033WOAAB4Txqlby+87a8HBAAA3mf03xOOAAB4J5+llxdnQS+YAACw4L7/XhEAAJg+/OcXan/94ggAoPfSKIZDi389YwIAgLf99ZAAANBraeS+/34SAAD6LGf3/feUHQCA3spn6fTtedBLJgAAfaX212sCAEAfZYt/fecIAKB3ZrW/36j99ZwJAED/TJ/+z6+CXhMAAHpF7Y8FAQCgTwaDuwEhAAD0SD6z+Md/EwAA+uFK7Y/3CQAAfZDD2/74BQEAoPPSKJ1eHAe8RwAA6D6jf35FAADotnO1Pz5EAADossHQ2/74IAEAoLPU/vg47wIA6KQ0mj79O/vnowQAgC6a5Bfppad/Ps4RAEDnpFH69sLb/vgkAQCge4z++SxHAACdks/Sy4uzgM8wAQDoEvf9c0MCAEBX5Oy+f27MEQBAJ6RRDIcW/7gxEwCAbnju6Z8mBACA6qWR+/5pSgAAqN04vgpoyA4AQNXyWfrjxWVAQyYAADVT+2NJAgBArbLFP5YnAABUKY3S6cVxwJIEAIA6Gf2zEgEAoDYpLtX+WJUAAFCbnaHaHysTAACqks8s/tEG9wAAVCONYjB09k8rTAAAapHz957+aYsAAFAFtT/aJQAA1MHon1YJAADle632R9sEAIDSDYZPA1omAAAUTe2P9VADBCiW2h/rYwIAUC5v+2NtBACAIqWRxT/WSQAAKFGeWPxjrQQAgOLks3T69nXAGgkAAKUZ3LL4x9oJAAAlyRb/2Aw1QIBipFEMB2cBG2ACAFAOT/9sjAAAUAS1PzZLAAAowTi+CtggOwAAW5fP0h8vLgM2yAQAYNvU/tgCAaCR/7wKgDap/bElKWgkP779Y+S0FwArmy/+/TZgC0wAmsrpbwHQDqN/tkYAaO48AFaV4lLtj20SAJoaDL2gA1jdzlDtj60SABp6t6xzHgBLy2cW/9g2AWAZ2bkdsKw0UvujBALAEtLpxXmYAgDLmOQXnv4pgQCwLFMAoLE0St9enAQUQABY0nwKkPOLALg5Dw4Uw0VAK8pfH7yZ/nYYAJ+Uz9LLtw8DCmECsKrB9VeR0igAPsXiH4URAFaUTi6vYmdwd3apRwB8kNof5XEE0KL86PbJdBrwJAB+Nqv9De4KAJTGBKBF6fTt0fTXh44EgPd42x9FMgFYk/zo4Hj6tzubBuwG0FPe9ke5TADWJJ1eHMdg+EXk/H0A/ZQnTwMKZQKwAfno93sxGb+ZhoG9AHpC7Y+yCQAblL++82D6N/5MEIAeGAx/6+yfkjkC2KD5u793fvrCNcLQcdniH+UzAdiS+bHA9U/HkdL9ADpkVvv7zRfp5PwqoGACwJblRweHsZO+cywAXZEezqd9UDgBoBD2A6AL1P6ohx2AQiz2AwZ3vWEQKjaY/huGSpgAFMh+ANRI7Y+6CAAFcywA1biaXfxl85+aCAAVyP//4CgG6YkgAIWa1f5mt39CRQSASjgWgFJZ/KNOlgArMRstptO3D2a3i01j22UApXCxF1UyAaiU/QAownl6eWHznyoJAJV799rhZwFsnvv+qZgjgMq9e+3wb712GDYtn/nyp2YmAB2S/+XOfgzjlWMBWLfZff+DuwIANRMAOsh+AKzZJJ6mby9OAiomAHTUojZ4/cB+ALRN7Y9usAPQUYvaoP0AWAO1PzrBBKAn8qPb92Jn5xvHArAK9/3THQJAz9gPgBWo/dEhjgB65r3XDjsWgCZyfuHLny4xAeix+aLg+Hq2yfz/AvgEtT+6RwDAsQB8Vno4n55BhwgA/Gx+rfBOui8IwPvU/ugmOwD8bF4btB8Av5SzrX86yQSAD5rvB0yuX0WO/YDeUvujuwQAPsl+AL2m9keHCQDciNcO0zs5ns+PxaCj7ABwI64Vpl/SKIb/5GU/dJoJAI157TDdp/ZH9wkALM1+AN2k9kc/OAJgae9dK/wioCsG059p6AETAFoxrw1e/3QcKd0PqJbaH/0hANAqxwJU7CoGwy/U/ugLAYC1EASojtofPSMAsDaOBaiHxT/6xxIgazMbpabTtw/m9wdE/CmgXM8DesYEgI1xLEChztPLC5v/9I4AwMa9u1b4yfSPuwHbluPu9Oz/PKBnBAC2wn4AhfD0T2/ZAWArfrEfkNIoYCuSd1vQWyYAFMF+AJtn859+MwGgCItrhX/6YtbFDtiIyXlAj5kAUBz7AWzEIH2RTv56GdBTAgDFcizA+hj/gyMAivXz2wZTeEqjZcb/IABQtHlb4A8XdgNoV3YzJQgAVGH+khYhgLYMb5kq0Xt2AKjKfC8g8ncBy7tKLy/+T0DPmQBQlfleQKSHAcvz9A8hAFAhIYCVpPy3AAQA6jQPAXYCWEq6CkAAoF7zxcCI1wFNZO+egBkBgLoNrh96mRCN5IkJAIQAQOXSyeVVTLJ9ABpwBAAzAgDVmx4FnEfOLwKAGxMA6Ibh+Hj6qyc7biDvBiAA0A3zo4BITwM+J+0IABACAB0yrwZaCAS4EQGAbnE3AJ+TvF4aZgQAOmVxS6BdAD4hp38OQACgg1JoBPBxKe8HIADQQTvXJwEfk2MvAAGA7lk0AuI84MN289Hv9wJ6TgCgq/4U8DHj63sBPScA0E2D67OAj0q/C+g5AYBOmh8DpLgM+KBsAkDvCQB0WP5zwIft5kcHhwE9JgDQXTmbAPBxKd0P6DEBgO4a/K/zgI/K9/LRvvcC0FsCAB32n24E5FN2YzI8CugpAYDOWiwC5lHAx2THAPSXAEDHJVMAPiHv5a/vPAjoIQGAbsvxbwGf9swuAH0kANBtOZsA8Bl5zy4AfSQAAOR44v0A9I0AADBrBIyvvwvoEQEAYOEwf33gKIDeEADotpT+OeDmnuV/ubMf0AMCAMD/2I1BvNIKoA8EALrO0xwNzVsBb4QAuk4AoLPefYD7EKe5PA2O48E3AR0mANBhQ0//rCA9yF/f1gygswQAumuc9gJWMgsBB3YC6CQBgO7Kk8OA1d2L8a0fXBRE1wgAdNfOzpcBrch7MR6/yY8ODgM6QgCgk+ZPa3n6oQ2tmf48pXiTHx88C+gAAYBuGo8PA9Yhx3H++s6PjgSonQBAR+X7AWszOxK4/nHWEhAEqFUK6Jj5B/L0wzlgM66mn6Qn6Q8XzwMqYgJA91z/dBywObs/Hwt8fedBQCVMAOiU+dP/ZPzGAiBbdB6D4cN08pdRQMFMAOiW2fKfL3+269B+ADUwAaAzPP1TnjSa/mS+SC8vTgIKYwJAd0yu7/vypyzzn8dv7AdQIhMAOsHmP3XIZzG49dx+ACUwAaAbbP5ThfRgvh/w5OAb+wFsmwkA1ctHB4cxjjcBVZntB8Tz9PKvZwFbIABQvfz4zo/O/qnXNAgM8sN0cnEesEECAFVbLFbl7wKqZz+AzRIAqJbaH52U4ti1wmyCJUDqla+f+PKnc1wrzIaYAFAltT/6YbYfMLjrWIB1MAGgTmp/9ILXDrM+JgBUx+IfPeW1w7RKAKA6an/0m/sDaIcAQFWmX/6zxT8vVoGI1zEYPrUfwLIEAKqh9gcf4v4AlmMJkHrMFv98+cM/mL1fYPxGbZCmTACogtof3EQaRZ48TadvXwd8hgkAdRhf2/qHz5pOyFJ6pTbITZgAUDy1P1hSiuPYGX5vP4APMQGgfCmeBdBcngYA+wF8hAkARcuPD57NP8SAFc2uFY6v0slfLwNCAKBg7xb/fpj+cTeAlqgNsuAIgHIt7vv35Q+tmtUGr3+cT9foNRMAiqT2B5vgWuE+EwAokvv+YYNSXMbO8CvHAv0iAFActT/YFvsBfSIAUJR8dLgbk//4wdM/bMv0WCDlM68d7j5LgJRl8vcnvvxhm6b//nIcTydxP7o/oNtMACiGxT8oktcOd5QJAOVY1P6Astyb1wa9X6BzTAAoQj66Pf2QSa8CKJjaYJcIABRB7Q9q4rXDXSAAsHVqf1ArtcGaCQBs1fxMcTJ+4+kfKua1w1WyBMh2zRb/fPlD3bx2uEomAGyN2h900ey1w4O7pgHlMwFge9T+oIPyntpgHUwA2AqLf9ATKY5dK1wmAYCtUPuDPnF/QIkEADYuPz54Nl8aAvrFa4eLIgCwUWp/gPsDymAJkM1S+wMiPVjUBg+Ogq0xAWBj1P6AX7MfsC0mAGzO5NrLfoB/MJsI5u/UBjfPBICNUPsDbmQnTiINX9gPWD8TADYjxbMA+JxJHLlWeDNMAFg7tT9gObNrhfPDdHJxHrROAGCtLP4Bq1MbXAdHAKyX+/6Blc1qg9c/qA22ywSAtclHd/ZjnH8IgLZ4t0BrTABYn0mo/QHtynE8qwwGKxMAWIv5Bq8b/4C1SA/yk4NvgpU4AqB17vsHNuRpenlxEizFBID2Ta7v+/IHNuCZ2wOXJwDQqvk/Rp1/YDN2Y3xtH2BJAgDtUvsDNuswPzo4DBoTAGhNPrp9L1K6HwCb5KrxpQgAtGeyYysX2IbDfLS/GzQiANAKtT9gq8a37gWNCACsbL74ZwQHbNeXQSMCAKubLf55+ge26zBoRABgJYunf4t/wLZ5CGlKAGA142uLf0ARXArUjADA0uaLfxEWbwAqJACwPIt/ANUSAFhKfnzwzOIfQL0EABpbnLOlBwFAtQQAmlP7A6ieAEAjan8A3SAA0Mzk+lUAUD0BgBtb3Pcf+wFA9QQAbk7tD6AzBABuRO0PoFsEAD5rvviX4zgA6AwBgM+b1f4A6BQBgE/KR3f21f4AukcA4NMmofYH0EECAB+1qP1Z/APoIgGAD1rc+Kf2B9BVw4APyddPIsdeANBJJgD8yvzpfxJHAUBnCQD8mtofQOc5AuAX5ot/kdX+ADrOBIBfsvgH0AsCAD/Lj+88UfsD6AcBgLn54l9Y/APoCwGAhdnin6d/gN4QAHh36Y/7/gH6RAAgYnz9XQDQKwJAzy1qf3EYAPSKANB3an8AvSQA9Fh+fPDM4h9APwkAPTVf/MtqfwB9JQD01eK+/90AoJcEgB5S+wNAAOijyfhNANBrAkDPzGt/Fv8Aek8A6JF8dLir9gfAzDDoj8nfn0SOvQCg90wAeuJd7e84ACAEgP5Y1P4AYE4A6IF8dHCo9gfA+wSAPpgkb/sD4BcEgI5T+wPgQwSADlvc+Kf2B8CvqQF2Wb5W+wPgg0wAOmr+9D/xtj8APkwA6Cq1PwA+wRFAB80X/yKr/QHwUSYAXWTxD4DPEAA6Jj++80TtD4DPEQA6ZL74Fxb/APg8AaBLZot/nv4BuAEBoCMWl/647x+AmxEAumJ87b5/AG5MAOiARe0vDgMAbkgA6AK1PwAaEgAqlx8fPLP4B0BTAkDF5ot/OY4DABoSAGrmvn8AliQAVErtD4BVCAC1mozfBAAsSQCo0Lz2Z/EPgBUIAJXJR4e7an8ArGoY1GXy9yeRYy8AYAUmABVR+wOgLQJATdT+AGiJAFCJfHT7ntofAG0RAGox2fkmAKAlAkAF1P4AaJsAULjFjX9qfwC0SwAo3Wzxz9M/AC0TAArmvn8A1kUAKNn42uIfAGshABRqvvgXcS8AYA0EgFJZ/ANgjQSAAuXHB88s/gGwTgJAYeaLf5EeBACskQBQGrU/ADZAACiI2h8AmyIAlGRy/SoAYAMEgEIs7vuP/QCADRAASqH2B8AGCQAFUPsDYNMEgC2bL/7lOA4A2CABYNtmtT8A2DABYIvy0Z19tT8AtkEA2KZJqP0BsBUCwJYsan8W/wDYDgFgCxY3/qn9AbA9w2DzJtf3I8deAMCWmABsmNofACUQADZN7Q+AAggAG5SPbt9T+wOgBALAJk12vgkAKIAAsCFqfwCURADYALU/AEojAGzCbPHP0z8ABREA1mzx9G/xD4CyCADrNr62+AdAcQSANZov/kXcCwAojACwThb/ACiUALAm+fHBM4t/AJRKAFiDd/f9HwUAFEoAWIfFff+7AQCFEgBapvYHQA0EgLZNxm8CAAonALTIff8A1EIAaJPaHwCVEABaovYHQE0EgBa8q/0dBwBUQgBow6L2BwDVEABWlI/u7Kv9AVAbAWBVk3gVAFAZAWAFan8A1EoAWNLixj+1PwDqNAyWk6+fRI69AIAKmQAsYf70P/G2PwDqJQAsQ+0PgMoJAMvY2fkyAKBiAkBD+dHtezb/AaidANDcvQCAygkATe2k3wUAVE4AaCrHfgBA5QSABvLR/m4AQAcIAI38bwEAgE4QAACghwQAAOghAQAAekgAAIAeEgAAoIcEAADoIQEAAHpIAACAHhIAAKCHBAAA6CEBAAB6SAAAgB4SAACghwQAAOghAQAAekgAAIAeEgAAoIcEAADoIQEAAHpIAACAHhIAAKCHBAAA6KEUNJK/PsgBQHHSywvfaQ2YADSV8igAKEuKy6ARAaCpSfw5AChLzgJAQwJAUymfBwCF2fFw1pAA0NRg8nr661UAUI7BT6+DRgSAhtLJ5dV0CvB9AFCIfDb/bKYRAWAZkyRpApRicOt50JgAsIR0enEe2RQAYPtmT/9/GQWNCQDLGo6Pwi4AwBalkaf/5QkAS5qfN+X4KgDYjpyeevpfngCwgsVRQEifAJs2/exNp/9qH2sFrk1sQX50cDz9m3wWAKzf/Mv/4jhYiQDQEiEAYAN8+bdGAGjRNAQcxk76LnLeCwBalEbTz9aH86NXWmEHoEXzH8ydwd3pD+mLAKANV/Ndq8FvvvDl3y4TgDXJR7/fi+ufjmNn50sTAYDGZl/8L2L4Tyfp5Fzleg0EgA1YHA3E4fSH+cvp3/ju9Pf9AOC/za5Yn37hp8vp5+Pfpv997ml//f4L3vH+OAZ8xYAAAAAASUVORK5CYII\\u003d\"\n  },\n  \"description\": \"Use this tag for sending data to the Server Container.\",\n  \"containerContexts\": [\n    \"WEB\"\n  ]\n}\n\n\n___TEMPLATE_PARAMETERS___\n\n[\n  {\n    \"type\": \"GROUP\",\n    \"name\": \"configGroup\",\n    \"subParams\": [\n      {\n        \"type\": \"RADIO\",\n        \"name\": \"event_type\",\n        \"displayName\": \"Event Name\",\n        \"radioItems\": [\n          {\n            \"value\": \"standard\",\n            \"displayValue\": \"Standard\",\n            \"subParams\": [\n              {\n                \"type\": \"SELECT\",\n                \"name\": \"event_name_standard\",\n                \"selectItems\": [\n                  {\n                    \"value\": \"page_view\",\n                    \"displayValue\": \"Page View\"\n                  },\n                  {\n                    \"value\": \"add_payment_info\",\n                    \"displayValue\": \"Add Payment Info\"\n                  },\n                  {\n                    \"value\": \"add_to_cart\",\n                    \"displayValue\": \"Add To Cart\"\n                  },\n                  {\n                    \"value\": \"add_to_wishlist\",\n                    \"displayValue\": \"Add To Wishlist\"\n                  },\n                  {\n                    \"value\": \"begin_checkout\",\n                    \"displayValue\": \"Begin Checkout\"\n                  },\n                  {\n                    \"value\": \"contact\",\n                    \"displayValue\": \"Contact\"\n                  },\n                  {\n                    \"value\": \"customize_product\",\n                    \"displayValue\": \"Customize Product\"\n                  },\n                  {\n                    \"value\": \"donate\",\n                    \"displayValue\": \"Donate\"\n                  },\n                  {\n                    \"value\": \"exception\",\n                    \"displayValue\": \"Exception\"\n                  },\n                  {\n                    \"value\": \"find_location\",\n                    \"displayValue\": \"Find Location\"\n                  },\n                  {\n                    \"value\": \"generate_lead\",\n                    \"displayValue\": \"Generate Lead\"\n                  },\n                  {\n                    \"value\": \"join_group\",\n                    \"displayValue\": \"Join Group\"\n                  },\n                  {\n                    \"value\": \"login\",\n                    \"displayValue\": \"Login\"\n                  },\n                  {\n                    \"value\": \"purchase\",\n                    \"displayValue\": \"Purchase\"\n                  },\n                  {\n                    \"value\": \"refund\",\n                    \"displayValue\": \"Refund\"\n                  },\n                  {\n                    \"value\": \"schedule\",\n                    \"displayValue\": \"Schedule\"\n                  },\n                  {\n                    \"value\": \"search\",\n                    \"displayValue\": \"Search\"\n                  },\n                  {\n                    \"value\": \"select_content\",\n                    \"displayValue\": \"Select Content\"\n                  },\n                  {\n                    \"value\": \"share\",\n                    \"displayValue\": \"Share\"\n                  },\n                  {\n                    \"value\": \"sign_up\",\n                    \"displayValue\": \"Sign Up\"\n                  },\n                  {\n                    \"value\": \"start_trial\",\n                    \"displayValue\": \"Start Trial\"\n                  },\n                  {\n                    \"value\": \"submit_application\",\n                    \"displayValue\": \"Submit Application\"\n                  },\n                  {\n                    \"value\": \"subscribe\",\n                    \"displayValue\": \"Subscribe\"\n                  },\n                  {\n                    \"value\": \"view_item\",\n                    \"displayValue\": \"View Item\"\n                  },\n                  {\n                    \"value\": \"view_item_list\",\n                    \"displayValue\": \"View Item List\"\n                  },\n                  {\n                    \"value\": \"view_search_results\",\n                    \"displayValue\": \"View Search Results\"\n                  }\n                ],\n                \"simpleValueType\": true,\n                \"defaultValue\": \"page_view\",\n                \"alwaysInSummary\": true\n              }\n            ]\n          },\n          {\n            \"value\": \"custom\",\n            \"displayValue\": \"Custom\",\n            \"subParams\": [\n              {\n                \"type\": \"TEXT\",\n                \"name\": \"event_name_custom\",\n                \"simpleValueType\": true\n              }\n            ]\n          }\n        ],\n        \"simpleValueType\": true\n      },\n      {\n        \"type\": \"TEXT\",\n        \"name\": \"gtm_server_domain\",\n        \"displayName\": \"GTM Server Side URL\",\n        \"simpleValueType\": true,\n        \"help\": \"Domain to where the tag will send requests.\\u003cbr\\u003eFor example: \\u003ci\\u003ehttps://gtm.example.com\\u003c/i\\u003e\",\n        \"valueValidators\": [\n          {\n            \"type\": \"NON_EMPTY\"\n          }\n        ],\n        \"alwaysInSummary\": true\n      },\n      {\n        \"type\": \"CHECKBOX\",\n        \"name\": \"add_data_layer\",\n        \"checkboxText\": \"Send all from Data Layer\",\n        \"simpleValueType\": true,\n        \"help\": \"Adds all Data Layer values to the request.\\n\\u003cbr/\\u003e\\u003cbr/\\u003e \\nNote that the values added to the request are from GTM\\u0027s internal Data Model (as seen in the GTM Preview Mode variable tab), not the actual Data Layer event as seen in the DevTools Console tab.\\n\\u003cbr/\\u003e\\u003cbr/\\u003e\\nIf you want only the values from the Data Layer event that triggered the tag:\\n\\u003cul\\u003e\\n\\u003cli\\u003e\\u003cb\\u003edisable\\u003c/b\\u003e the \\u003ci\\u003eUse own Data Model\\u003c/i\\u003e option\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003cb\\u003eenable\\u003c/b\\u003e the \\u003ci\\u003eSend the current Data Layer event object data only\\u003c/i\\u003e option\\u003c/li\\u003e\\n\\u003c/ul\\u003e\\n\\u003cbr/\\u003e\\nLearn more about: the \\u003ca href\\u003d\\\"https://www.simoahava.com/analytics/google-tag-manager-data-model/\\\"\\u003eGTM\\u0027s Data Model\\u003c/a\\u003e and the \\u003ca href\\u003d\\\"https://www.simoahava.com/analytics/two-simple-data-model-tricks/#trick-2-get-the-object-representation-of-the-current-state-of-the-data-model\\\"\\u003emethod\\u003c/a\\u003e used to get the values.\",\n        \"subParams\": [\n          {\n            \"type\": \"GROUP\",\n            \"name\": \"add_data_layer_group\",\n            \"subParams\": [\n              {\n                \"type\": \"CHECKBOX\",\n                \"name\": \"add_data_layer_use_own_data_model\",\n                \"checkboxText\": \"Use own Data Model\",\n                \"simpleValueType\": true,\n                \"help\": \"Enable this option if your event captures Data Layer values that don’t match what was available when the tag fired.\\nFor example, when certain values weren’t yet defined in the Data Layer but still appeared in the event payload.\\n\\u003cbr/\\u003e\\u003cbr/\\u003e\\nThis usually happens when the Data Tag fires before the Data Tag JavaScript script has fully loaded.\\n\\u003cbr/\\u003e\\u003cbr/\\u003e\\nMake sure to use the \\u003cb\\u003ev9\\u003c/b\\u003e version of the \\u003ci\\u003eData Tag Script URL\\u003c/i\\u003e under the \\u003ci\\u003eSettings\\u003c/i\\u003e section.\\n\\u003cbr/\\u003e\\u003cbr/\\u003e\\nLearn more: \\u003ca href\\u003d\\\"https://github.com/stape-io/data-tag/issues/28\\\"\\u003e[1]\\u003c/a\\u003e, \\u003ca href\\u003d\\\"https://github.com/stape-io/data-tag/pull/33\\\"\\u003e[2]\\u003c/a\\u003e and \\u003ca href\\u003d\\\"https://github.com/stape-io/data-tag/pull/41\\\"\\u003e[3]\\u003c/a\\u003e.\",\n                \"defaultValue\": true,\n                \"alwaysInSummary\": true\n              },\n              {\n                \"type\": \"CHECKBOX\",\n                \"name\": \"add_data_layer_use_only_current_push\",\n                \"checkboxText\": \"Send the current Data Layer event object data only\",\n                \"simpleValueType\": true,\n                \"enablingConditions\": [\n                  {\n                    \"paramName\": \"add_data_layer_use_own_data_model\",\n                    \"paramValue\": true,\n                    \"type\": \"NOT_EQUALS\"\n                  }\n                ],\n                \"help\": \"Enable this option to only capture data from the Data Layer event that triggered the tag, not from the whole GTM\\u0027s internal Data Model.\\n\\u003cbr/\\u003e\\u003cbr/\\u003e\\nMake sure to use the \\u003cb\\u003ev9\\u003c/b\\u003e version of the \\u003ci\\u003eData Tag Script URL\\u003c/i\\u003e under the \\u003ci\\u003eSettings\\u003c/i\\u003e section.\",\n                \"alwaysInSummary\": true\n              }\n            ],\n            \"enablingConditions\": [\n              {\n                \"paramName\": \"add_data_layer\",\n                \"paramValue\": true,\n                \"type\": \"EQUALS\"\n              }\n            ]\n          }\n        ],\n        \"enablingConditions\": [\n          {\n            \"paramName\": \"request_type\",\n            \"paramValue\": \"get\",\n            \"type\": \"NOT_EQUALS\"\n          }\n        ],\n        \"alwaysInSummary\": true\n      },\n      {\n        \"type\": \"CHECKBOX\",\n        \"name\": \"add_common\",\n        \"checkboxText\": \"Send common data\",\n        \"simpleValueType\": true,\n        \"help\": \"Adds the following Common Event Data parameters to the request:\\n\\u003cul\\u003e\\n\\u003cli\\u003epage_location\\u003c/li\\u003e\\n\\u003cli\\u003epage_path\\u003c/li\\u003e\\n\\u003cli\\u003epage_hostname\\u003c/li\\u003e\\n\\u003cli\\u003epage_referrer\\u003c/li\\u003e\\n\\u003cli\\u003epage_title\\u003c/li\\u003e\\n\\u003cli\\u003epage_encoding\\u003c/li\\u003e\\n\\u003cli\\u003escreen_resolution\\u003c/li\\u003e\\n\\u003cli\\u003eviewport_size\\u003c/li\\u003e\\n\\u003c/ul\\u003e\",\n        \"defaultValue\": true,\n        \"alwaysInSummary\": true\n      },\n      {\n        \"type\": \"CHECKBOX\",\n        \"name\": \"add_consent_state\",\n        \"checkboxText\": \"Add consent state\",\n        \"simpleValueType\": true,\n        \"help\": \"Adds the \\u003ci\\u003econsent_state\\u003c/i\\u003e object including the following properties to the request:\\n\\u003cul\\u003e \\n\\u003cli\\u003ead_storage\\u003c/li\\u003e\\n\\u003cli\\u003ead_user_data\\u003c/li\\u003e\\n\\u003cli\\u003ead_personalization\\u003c/li\\u003e\\n\\u003cli\\u003eanalytics_storage\\u003c/li\\u003e\\n\\u003cli\\u003efunctionality_storage\\u003c/li\\u003e\\n\\u003cli\\u003epersonalization_storage\\u003c/li\\u003e\\n\\u003cli\\u003esecurity_storage\\u003c/li\\u003e\\n\\u003cul\\u003e\",\n        \"alwaysInSummary\": true\n      },\n      {\n        \"type\": \"CHECKBOX\",\n        \"name\": \"add_common_cookie\",\n        \"checkboxText\": \"Add Common Cookie\",\n        \"simpleValueType\": true,\n        \"help\": \"The tag will send common cookies in \\u003cI\\u003eeventData\\u003c/i\\u003e to avoid some e-commerce platform limitations.\\n\\u003cbr/\\u003e\\nSupported Stape\\u0027s tags:\\n\\u003cbr/\\u003e\\n\\u003ca href\\u003d\\\"https://tagmanager.google.com/gallery/#/owners/stape-io/templates/facebook-tag\\\" target\\u003d\\\"_blank\\\"\\u003eFacebook Conversion API\\u003c/a\\u003e\\u003cbr /\\u003e\\n\\u003ca href\\u003d\\\"https://tagmanager.google.com/gallery/#/owners/stape-io/templates/tiktok-tag\\\" target\\u003d\\\"_blank\\\"\\u003eTikTok Events API\\u003c/a\\u003e\\u003cbr /\\u003e\\n\\u003ca href\\u003d\\\"https://tagmanager.google.com/gallery/#/owners/stape-io/templates/pinterest-capi-tag\\\" target\\u003d\\\"_blank\\\"\\u003ePinterest Conversion API\\u003c/a\\u003e\\u003cbr /\\u003e\\n\\u003ca href\\u003d\\\"https://tagmanager.google.com/gallery/#/owners/stape-io/templates/snapchat-tag\\\" target\\u003d\\\"_blank\\\"\\u003eSnapchat Conversion API\\u003c/a\\u003e\\u003cbr /\\u003e\\n\\u003ca href\\u003d\\\"https://tagmanager.google.com/gallery/#/owners/stape-io/templates/taboola-tag\\\" target\\u003d\\\"_blank\\\"\\u003eTaboola\\u003c/a\\u003e\\u003c/br\\u003e\\n\\u003ca href\\u003d\\\"https://tagmanager.google.com/gallery/#/owners/stape-io/templates/awin-tag\\\" target\\u003d\\\"_blank\\\"\\u003eAwin\\u003c/a\\u003e\\u003c/br\\u003e\\n\\u003ca href\\u003d\\\"https://tagmanager.google.com/gallery/#/owners/stape-io/templates/rakuten-tag\\\" target\\u003d\\\"_blank\\\"\\u003eRakuten\\u003c/a\\u003e\\u003c/br\\u003e\\n\\u003ca href\\u003d\\\"https://tagmanager.google.com/gallery/#/owners/stape-io/templates/klaviyo-tag\\\" target\\u003d\\\"_blank\\\"\\u003eKlaviyo\\u003c/a\\u003e\\u003c/br\\u003e\\n\\u003ca href\\u003d\\\"https://tagmanager.google.com/gallery/#/owners/stape-io/templates/outbrain-tag\\\" target\\u003d\\\"_blank\\\"\\u003eOutbrain\\u003c/a\\u003e\\u003c/br\\u003e\\n\\u003ca href\\u003d\\\"https://tagmanager.google.com/gallery/#/owners/stape-io/templates/webgains-tag\\\" target\\u003d\\\"_blank\\\"\\u003eWebgains\\u003c/a\\u003e\\u003c/br\\u003e\\n\\u003ca href\\u003d\\\"https://tagmanager.google.com/gallery/#/owners/stape-io/templates/postscript-tag\\\" target\\u003d\\\"_blank\\\"\\u003ePostscript\\u003c/a\\u003e\\u003c/br\\u003e\\n\\u003ca href\\u003d\\\"https://tagmanager.google.com/gallery/#/owners/stape-io/templates/microsoft-capi-tag\\\" target\\u003d\\\"_blank\\\"\\u003eMicrosoft UET Conversion API\\u003c/a\\u003e\\u003c/br\\u003e\\n\\u003ca href\\u003d\\\"https://tagmanager.google.com/gallery/#/owners/stape-io/templates/google-conversion-events-tag\\\" target\\u003d\\\"_blank\\\"\\u003eGoogle Conversion Events (Data Manager)\\u003c/a\\u003e\\u003c/br\\u003e\\n\\u003ca href\\u003d\\\"https://tagmanager.google.com/gallery/#/owners/stape-io/templates/linkedin-tag\\\"\\u003e LinkedIn Conversions API \\u003c/a\\u003e\\n\\u003c/br\\u003e\",\n        \"alwaysInSummary\": true\n      }\n    ]\n  },\n  {\n    \"type\": \"GROUP\",\n    \"name\": \"eventDataGroup\",\n    \"displayName\": \"Event Data\",\n    \"groupStyle\": \"ZIPPY_CLOSED\",\n    \"subParams\": [\n      {\n        \"type\": \"SIMPLE_TABLE\",\n        \"name\": \"custom_data\",\n        \"displayName\": \"\",\n        \"simpleTableColumns\": [\n          {\n            \"defaultValue\": \"\",\n            \"displayName\": \"Name\",\n            \"name\": \"name\",\n            \"type\": \"TEXT\",\n            \"valueValidators\": [\n              {\n                \"type\": \"NON_EMPTY\"\n              }\n            ]\n          },\n          {\n            \"defaultValue\": \"\",\n            \"displayName\": \"Value\",\n            \"name\": \"value\",\n            \"type\": \"TEXT\"\n          },\n          {\n            \"defaultValue\": \"none\",\n            \"displayName\": \"Transformation\",\n            \"name\": \"transformation\",\n            \"type\": \"SELECT\",\n            \"selectItems\": [\n              {\n                \"value\": \"none\",\n                \"displayValue\": \"None\"\n              },\n              {\n                \"value\": \"trim\",\n                \"displayValue\": \"Trim\"\n              },\n              {\n                \"value\": \"to_lower_case\",\n                \"displayValue\": \"To lower case\"\n              },\n              {\n                \"value\": \"md5\",\n                \"displayValue\": \"MD5 hash\"\n              },\n              {\n                \"value\": \"base64\",\n                \"displayValue\": \"Base64\"\n              },\n              {\n                \"value\": \"sha256base64\",\n                \"displayValue\": \"SHA-256 digest (Base64 encoded)\"\n              },\n              {\n                \"value\": \"sha256hex\",\n                \"displayValue\": \"SHA-256 digest (HEX encoded)\"\n              }\n            ],\n            \"valueValidators\": [\n              {\n                \"type\": \"NON_EMPTY\"\n              }\n            ]\n          },\n          {\n            \"defaultValue\": \"none\",\n            \"displayName\": \"Store\",\n            \"name\": \"store\",\n            \"type\": \"SELECT\",\n            \"selectItems\": [\n              {\n                \"value\": \"none\",\n                \"displayValue\": \"None\"\n              },\n              {\n                \"value\": \"all\",\n                \"displayValue\": \"Everywhere\"\n              },\n              {\n                \"value\": \"localStorage\",\n                \"displayValue\": \"Local Storage\"\n              },\n              {\n                \"value\": \"cookies\",\n                \"displayValue\": \"Cookies\"\n              }\n            ],\n            \"valueValidators\": [\n              {\n                \"type\": \"NON_EMPTY\"\n              }\n            ]\n          }\n        ]\n      }\n    ]\n  },\n  {\n    \"type\": \"GROUP\",\n    \"name\": \"userDataGroup\",\n    \"displayName\": \"User Data\",\n    \"groupStyle\": \"ZIPPY_CLOSED\",\n    \"subParams\": [\n      {\n        \"type\": \"SIMPLE_TABLE\",\n        \"name\": \"user_data\",\n        \"displayName\": \"\",\n        \"simpleTableColumns\": [\n          {\n            \"defaultValue\": \"email_address\",\n            \"displayName\": \"Name\",\n            \"name\": \"name\",\n            \"type\": \"SELECT\",\n            \"valueValidators\": [\n              {\n                \"type\": \"NON_EMPTY\"\n              }\n            ],\n            \"isUnique\": true,\n            \"selectItems\": [\n              {\n                \"value\": \"email_address\",\n                \"displayValue\": \"Email Address\"\n              },\n              {\n                \"value\": \"phone_number\",\n                \"displayValue\": \"Phone Number\"\n              },\n              {\n                \"value\": \"first_name\",\n                \"displayValue\": \"First Name\"\n              },\n              {\n                \"value\": \"last_name\",\n                \"displayValue\": \"Last Name\"\n              },\n              {\n                \"value\": \"gender\",\n                \"displayValue\": \"Gender\"\n              },\n              {\n                \"value\": \"db\",\n                \"displayValue\": \"Date of Birth\"\n              },\n              {\n                \"value\": \"street\",\n                \"displayValue\": \"Street\"\n              },\n              {\n                \"value\": \"city\",\n                \"displayValue\": \"City\"\n              },\n              {\n                \"value\": \"region\",\n                \"displayValue\": \"Region\"\n              },\n              {\n                \"value\": \"postal_code\",\n                \"displayValue\": \"Postal Code\"\n              },\n              {\n                \"value\": \"country\",\n                \"displayValue\": \"Country\"\n              },\n              {\n                \"value\": \"user_id\",\n                \"displayValue\": \"User ID\"\n              }\n            ]\n          },\n          {\n            \"defaultValue\": \"\",\n            \"displayName\": \"Value\",\n            \"name\": \"value\",\n            \"type\": \"TEXT\"\n          },\n          {\n            \"defaultValue\": \"none\",\n            \"displayName\": \"Transformation\",\n            \"name\": \"transformation\",\n            \"type\": \"SELECT\",\n            \"selectItems\": [\n              {\n                \"value\": \"none\",\n                \"displayValue\": \"None\"\n              },\n              {\n                \"value\": \"trim\",\n                \"displayValue\": \"Trim\"\n              },\n              {\n                \"value\": \"to_lower_case\",\n                \"displayValue\": \"To lower case\"\n              },\n              {\n                \"value\": \"md5\",\n                \"displayValue\": \"MD5 hash\"\n              },\n              {\n                \"value\": \"base64\",\n                \"displayValue\": \"Base64\"\n              },\n              {\n                \"value\": \"sha256base64\",\n                \"displayValue\": \"SHA-256 digest (Base64 encoded)\"\n              },\n              {\n                \"value\": \"sha256hex\",\n                \"displayValue\": \"SHA-256 digest (HEX encoded)\"\n              }\n            ],\n            \"valueValidators\": [\n              {\n                \"type\": \"NON_EMPTY\"\n              }\n            ]\n          },\n          {\n            \"defaultValue\": \"none\",\n            \"displayName\": \"Store\",\n            \"name\": \"store\",\n            \"type\": \"SELECT\",\n            \"selectItems\": [\n              {\n                \"value\": \"none\",\n                \"displayValue\": \"None\"\n              },\n              {\n                \"value\": \"all\",\n                \"displayValue\": \"Everywhere\"\n              },\n              {\n                \"value\": \"localStorage\",\n                \"displayValue\": \"Local Storage\"\n              },\n              {\n                \"value\": \"cookies\",\n                \"displayValue\": \"Cookies\"\n              }\n            ],\n            \"valueValidators\": [\n              {\n                \"type\": \"NON_EMPTY\"\n              }\n            ]\n          }\n        ]\n      }\n    ]\n  },\n  {\n    \"type\": \"GROUP\",\n    \"name\": \"settingsGroup\",\n    \"displayName\": \"Settings\",\n    \"groupStyle\": \"ZIPPY_CLOSED\",\n    \"subParams\": [\n      {\n        \"type\": \"SELECT\",\n        \"name\": \"request_type\",\n        \"displayName\": \"Request Type\",\n        \"macrosInSelect\": false,\n        \"selectItems\": [\n          {\n            \"value\": \"auto\",\n            \"displayValue\": \"Auto\"\n          },\n          {\n            \"value\": \"post\",\n            \"displayValue\": \"POST\"\n          },\n          {\n            \"value\": \"get\",\n            \"displayValue\": \"GET\"\n          }\n        ],\n        \"simpleValueType\": true,\n        \"defaultValue\": \"auto\",\n        \"valueValidators\": [\n          {\n            \"type\": \"NON_EMPTY\"\n          }\n        ],\n        \"help\": \"We highly recommend using \\u003cb\\u003eAuto\\u003c/b\\u003e. Change this only if you know what you are doing.\\n\\u003cbr/\\u003e\\u003cbr/\\u003e\\nSome features will become unavailable if you choose \\u003ci\\u003eGET\\u003c/i\\u003e.\"\n      },\n      {\n        \"type\": \"TEXT\",\n        \"name\": \"request_path\",\n        \"displayName\": \"Path\",\n        \"simpleValueType\": true,\n        \"defaultValue\": \"/data\",\n        \"help\": \"The path used for sending requests to the GTM Server Side container. If you use the Data client on GTM Server Side, the Path should be \\u003cb\\u003e/data\\u003c/b\\u003e.\",\n        \"valueValidators\": [\n          {\n            \"type\": \"NON_EMPTY\"\n          },\n          {\n            \"type\": \"REGEX\",\n            \"args\": [\n              \"^/.*\"\n            ],\n            \"errorMessage\": \"The path must start with /.\"\n          }\n        ]\n      },\n      {\n        \"type\": \"TEXT\",\n        \"name\": \"protocol_version\",\n        \"displayName\": \"Protocol version\",\n        \"simpleValueType\": true,\n        \"defaultValue\": 2,\n        \"help\": \"Protocol version that used for sending a request to Data client on GTM Server Side.\",\n        \"valueValidators\": [\n          {\n            \"type\": \"NON_EMPTY\"\n          }\n        ]\n      },\n      {\n        \"type\": \"TEXT\",\n        \"name\": \"data_tag_load_script_url\",\n        \"displayName\": \"Data Tag Script URL\",\n        \"simpleValueType\": true,\n        \"help\": \"URL where to load Data tag script from, by default it will be loaded from \\u003cI\\u003ehttps://stapecdn.com/dtag/${data-script-version}.js\\u003c/i\\u003e. \\n\\u003cbr/\\u003e\\nThis can be parameterized with \\u003ci\\u003e${data-script-version}\\u003c/i\\u003e in order to load the correct version for this tag.\\n\\u003cbr/\\u003e\\u003cbr/\\u003e\\nLatest version: \\u003cb\\u003ev9\\u003c/b\\u003e.\",\n        \"valueValidators\": [\n          {\n            \"type\": \"REGEX\",\n            \"args\": [\n              \"^(https://).*(\\\\.js)$\"\n            ]\n          }\n        ],\n        \"alwaysInSummary\": false,\n        \"defaultValue\": \"https://stapecdn.com/dtag/v9.js\",\n        \"enablingConditions\": [\n          {\n            \"paramName\": \"request_type\",\n            \"paramValue\": \"get\",\n            \"type\": \"NOT_EQUALS\"\n          }\n        ]\n      },\n      {\n        \"type\": \"CHECKBOX\",\n        \"name\": \"addGaParameters\",\n        \"checkboxText\": \"Add GA4 specific parameters\",\n        \"simpleValueType\": true,\n        \"help\": \"Adds specific parameters for the server GA4 tag.\\n\\u003cbr/\\u003e\\nSuch as:\\n\\u003cul\\u003e\\n\\u003cli\\u003ex-ga-measurement_id\\u0027 \\u003d {GA4 Measurement ID}\\u003c/li\\u003e\\n\\u003cli\\u003ex-ga-page_id \\u003d copyFromDataLayer(\\u0027gtm.start\\u0027)\\u003c/li\\u003e\\n\\u003cli\\u003ex-ga-mp2-richsstsse \\u003d \\u0027\\u0027\\u003c/li\\u003e\\n\\u003cli\\u003ex-ga-mp2-seg \\u003d 1\\u003c/li\\u003e\\n\\u003cli\\u003ex-ga-request_count \\u003d 1\\u003c/li\\u003e\\n\\u003cli\\u003ex-ga-protocol_version \\u003d 2\\u003c/li\\u003e\\n\\u003c/ul\\u003e\",\n        \"defaultValue\": false,\n        \"enablingConditions\": [\n          {\n            \"paramName\": \"request_type\",\n            \"paramValue\": \"get\",\n            \"type\": \"NOT_EQUALS\"\n          }\n        ],\n        \"subParams\": [\n          {\n            \"type\": \"TEXT\",\n            \"name\": \"gaId\",\n            \"displayName\": \"Measurement ID\",\n            \"simpleValueType\": true,\n            \"enablingConditions\": [\n              {\n                \"paramName\": \"addGaParameters\",\n                \"paramValue\": true,\n                \"type\": \"EQUALS\"\n              }\n            ],\n            \"valueHint\": \"G-ABCD123456\",\n            \"valueValidators\": [\n              {\n                \"type\": \"NON_EMPTY\"\n              }\n            ],\n            \"help\": \"Enter the Measurement ID of your GA4 property.\"\n          }\n        ]\n      },\n      {\n        \"type\": \"CHECKBOX\",\n        \"name\": \"dataLayerEventPush\",\n        \"checkboxText\": \"Push event to DataLayer after tag receives a response\",\n        \"simpleValueType\": true,\n        \"help\": \"Helpful in obtaining data from the server.\",\n        \"defaultValue\": false,\n        \"enablingConditions\": [\n          {\n            \"paramName\": \"request_type\",\n            \"paramValue\": \"get\",\n            \"type\": \"NOT_EQUALS\"\n          }\n        ],\n        \"subParams\": [\n          {\n            \"type\": \"TEXT\",\n            \"name\": \"dataLayerEventName\",\n            \"displayName\": \"DataLayer Event Name\",\n            \"simpleValueType\": true,\n            \"enablingConditions\": [\n              {\n                \"paramName\": \"dataLayerEventPush\",\n                \"paramValue\": true,\n                \"type\": \"EQUALS\"\n              }\n            ],\n            \"valueValidators\": [\n              {\n                \"type\": \"NON_EMPTY\"\n              }\n            ],\n            \"valueHint\": \"page_view_response\"\n          },\n          {\n            \"type\": \"TEXT\",\n            \"name\": \"dataLayerVariableName\",\n            \"displayName\": \"DataLayer Object Name\",\n            \"simpleValueType\": true,\n            \"enablingConditions\": [\n              {\n                \"paramName\": \"dataLayerEventPush\",\n                \"paramValue\": true,\n                \"type\": \"EQUALS\"\n              }\n            ],\n            \"valueValidators\": [\n              {\n                \"type\": \"NON_EMPTY\"\n              }\n            ],\n            \"defaultValue\": \"dataLayer\",\n            \"help\": \"Use \\u003ci\\u003edataLayer\\u003c/i\\u003e by default. Modify only if you renamed dataLayer object name.\"\n          }\n        ]\n      },\n      {\n        \"type\": \"CHECKBOX\",\n        \"name\": \"richsstsse\",\n        \"checkboxText\": \"Support rich command protocol\",\n        \"simpleValueType\": true,\n        \"enablingConditions\": [\n          {\n            \"paramName\": \"request_type\",\n            \"paramValue\": \"get\",\n            \"type\": \"NOT_EQUALS\"\n          }\n        ],\n        \"help\": \"Useful if you have server-side tags, that (partially) depend on the \\u003cI\\u003esendPixelFromBrowser()\\u003c/i\\u003e API for 3rd party cookies (e.g. Google Ads Conversion, Google Ads Remarketing).\",\n        \"defaultValue\": false,\n        \"subParams\": [\n          {\n            \"type\": \"CHECKBOX\",\n            \"name\": \"waitForCookies\",\n            \"checkboxText\": \"Wait for cookies before event is pushed\",\n            \"simpleValueType\": true,\n            \"defaultValue\": false,\n            \"enablingConditions\": [\n              {\n                \"paramName\": \"richsstsse\",\n                \"paramValue\": true,\n                \"type\": \"EQUALS\"\n              }\n            ],\n            \"help\": \"Wait for all cookies to be set before event is pushed to DataLayer. Helpful if a server-side tag sets cookies that a web tag relies on.\"\n          }\n        ]\n      },\n      {\n        \"type\": \"CHECKBOX\",\n        \"name\": \"useFetchInsteadOfXHR\",\n        \"checkboxText\": \"Use fetch instead of XMLHttpRequest (for POST requests only)\",\n        \"simpleValueType\": true,\n        \"help\": \"Using \\u003ci\\u003efetch\\u003c/i\\u003e with \\u003ci\\u003ekeepalive\\u003c/i\\u003e option which allow the request to outlive the page. \\u003ca href\\u003d\\\"https://developer.mozilla.org/en-US/docs/Web/API/fetch#keepalive\\\"\\u003eRead more\\u003c/a\\u003e.\",\n        \"defaultValue\": true,\n        \"enablingConditions\": [\n          {\n            \"paramName\": \"request_type\",\n            \"paramValue\": \"get\",\n            \"type\": \"NOT_EQUALS\"\n          }\n        ]\n      }\n    ]\n  }\n]\n\n\n___SANDBOXED_JS_FOR_WEB_TEMPLATE___\n\nconst callInWindow = require('callInWindow');\nconst copyFromDataLayer = require('copyFromDataLayer');\nconst copyFromWindow = require('copyFromWindow');\nconst encodeUriComponent = require('encodeUriComponent');\nconst generateRandom = require('generateRandom');\nconst getContainerVersion = require('getContainerVersion');\nconst getCookieValues = require('getCookieValues');\nconst getReferrerUrl = require('getReferrerUrl');\nconst getTimestampMillis = require('getTimestampMillis');\nconst getType = require('getType');\nconst getUrl = require('getUrl');\nconst injectScript = require('injectScript');\nconst isConsentGranted = require('isConsentGranted');\nconst JSON = require('JSON');\nconst localStorage = require('localStorage');\nconst makeNumber = require('makeNumber');\nconst makeString = require('makeString');\nconst readCharacterSet = require('readCharacterSet');\nconst readTitle = require('readTitle');\nconst sendPixel = require('sendPixel');\nconst setCookie = require('setCookie');\nconst setInWindow = require('setInWindow');\nconst toBase64 = require('toBase64');\n\n/*==============================================================================\n==============================================================================*/\n\nconst pageLocation = getUrl();\nif (pageLocation && pageLocation.lastIndexOf('https://gtm-msr.appspot.com/', 0) === 0) {\n  return data.gtmOnSuccess();\n}\n\nconst userAndCustomData = getUserAndCustomDataArray();\nconst requestType = determinateRequestType();\nconst normalizedServerUrl = normalizeServerUrl();\nconst eventId = copyFromDataLayer('gtm.uniqueEventId');\n\nif (requestType === 'post') {\n  const dataScriptVersion = 'v9';\n  const dataTagScriptUrl =\n    getType(data.data_tag_load_script_url) !== 'undefined'\n      ? data.data_tag_load_script_url.replace('${data-script-version}', dataScriptVersion)\n      : 'https://stapecdn.com/dtag/' + dataScriptVersion + '.js';\n\n  const dataTagScriptLoadedCacheKey = 'gtm_dataTagScriptLoadedCache';\n  const dataTagScriptLoadedCache = copyFromWindow(dataTagScriptLoadedCacheKey) || {};\n\n  if (!dataTagScriptLoadedCache[dataTagScriptUrl]) {\n    injectScript(\n      dataTagScriptUrl,\n      () => {\n        dataTagScriptLoadedCache[dataTagScriptUrl] = true;\n        setInWindow(dataTagScriptLoadedCacheKey, dataTagScriptLoadedCache);\n        sendPostRequest();\n      },\n      data.gtmOnFailure,\n      dataTagScriptUrl\n    );\n  } else {\n    sendPostRequest();\n  }\n} else {\n  sendGetRequest();\n}\n\n/*==============================================================================\n  Vendor related functions\n==============================================================================*/\n\nfunction sendPostRequest() {\n  let eventData = {};\n\n  eventData = addCommonDataForPostRequest(data, eventData);\n  eventData = addRequiredDataForPostRequest(data, eventData);\n  eventData = addGaRequiredData(data, eventData);\n\n  callInWindow(\n    'dataTagSendData',\n    eventData,\n    normalizedServerUrl.gtmServerDomain,\n    normalizedServerUrl.requestPath +\n      '?v=' +\n      eventData.v +\n      '&event=' +\n      encodeUriComponent(eventData.event_name) +\n      (data.richsstsse ? '&richsstsse' : ''),\n    data.dataLayerEventName,\n    data.dataLayerVariableName,\n    data.waitForCookies,\n    data.useFetchInsteadOfXHR\n  );\n\n  data.gtmOnSuccess();\n}\n\nfunction sendGetRequest() {\n  sendPixel(addDataForGetRequest(data, buildEndpoint()), data.gtmOnSuccess, data.gtmOnFailure);\n}\n\nfunction normalizeServerUrl() {\n  let gtmServerDomain = data.gtm_server_domain;\n  let requestPath = data.request_path;\n\n  // Add 'https://' if gtmServerDomain doesn't start with it\n  if (gtmServerDomain.indexOf('http://') !== 0 && gtmServerDomain.indexOf('https://') !== 0) {\n    gtmServerDomain = 'https://' + gtmServerDomain;\n  }\n\n  // Removes trailing slash from gtmServerDomain if it ends with it\n  if (gtmServerDomain.charAt(gtmServerDomain.length - 1) === '/') {\n    gtmServerDomain = gtmServerDomain.slice(0, -1);\n  }\n\n  // Adds slash to first position of requestPath if doesn't start with it\n  if (requestPath.charAt(0) !== '/') {\n    requestPath = '/' + requestPath;\n  }\n\n  return {\n    gtmServerDomain: gtmServerDomain,\n    requestPath: requestPath\n  };\n}\n\nfunction buildEndpoint() {\n  return normalizedServerUrl.gtmServerDomain + normalizedServerUrl.requestPath;\n}\n\nfunction addRequiredDataForPostRequest(data, eventData) {\n  eventData.event_name = getEventName(data);\n  eventData.v = makeNumber(data.protocol_version);\n\n  let customData = getCustomData(data, true);\n\n  for (let key in customData) {\n    eventData[customData[key].name] = customData[key].value;\n  }\n\n  eventData = addTempClientId(eventData);\n\n  return eventData;\n}\n\nfunction addGaRequiredData(data, eventData) {\n  if (data.addGaParameters && data.gaId) {\n    eventData['x-ga-measurement_id'] = data.gaId;\n    eventData['x-ga-page_id'] = copyFromDataLayer('gtm.start');\n    eventData['x-ga-mp2-richsstsse'] = '';\n    eventData['x-ga-mp2-seg'] = 1;\n    eventData['x-ga-request_count'] = 1;\n    eventData['x-ga-protocol_version'] = 2;\n    eventData.v = 2;\n  }\n\n  return eventData;\n}\n\nfunction addDataForGetRequest(data, url) {\n  let eventData = {};\n  url += '?v=' + data.protocol_version + '&event=' + encodeUriComponent(getEventName(data));\n\n  if (data.add_common) {\n    eventData = addCommonData(eventData);\n  }\n\n  if (data.add_consent_state && data.request_type === 'auto') {\n    eventData = addConsentStateData(eventData);\n  }\n\n  if (data.add_common_cookie && data.request_type === 'auto') {\n    eventData = addCommonCookie(eventData);\n  }\n\n  const customData = getCustomData(data, false);\n\n  if (customData.length) {\n    for (let customDataKey in customData) {\n      eventData[customData[customDataKey].name] = customData[customDataKey].value;\n    }\n  }\n\n  eventData = addTempClientId(eventData);\n\n  if (data.request_type === 'auto') {\n    return url + '&dtdc=' + encodeUriComponent(toBase64(JSON.stringify(eventData)));\n  }\n\n  for (let eventDataKey in eventData) {\n    const value = eventData[eventDataKey];\n    url += '&' + eventDataKey + '=' + (value ? encodeUriComponent(value) : '');\n  }\n\n  return url;\n}\n\nfunction addCommonDataForPostRequest(data, eventData) {\n  if (data.add_common || data.add_data_layer) {\n    const dataTagData = callInWindow(\n      'dataTagGetData',\n      getContainerVersion()['containerId'],\n      eventId,\n      data.add_data_layer_use_own_data_model,\n      data.add_data_layer_use_only_current_push\n    );\n\n    if (data.add_data_layer && dataTagData.dataModel) {\n      for (let dataKey in dataTagData.dataModel) {\n        eventData[dataKey] = dataTagData.dataModel[dataKey];\n      }\n    }\n\n    if (data.add_common) {\n      eventData = addCommonData(eventData);\n      eventData.screen_resolution = dataTagData.screen.width + 'x' + dataTagData.screen.height;\n      eventData.viewport_size = dataTagData.innerWidth + 'x' + dataTagData.innerHeight;\n    }\n  }\n\n  if (data.add_consent_state) {\n    eventData = addConsentStateData(eventData);\n  }\n\n  if (data.add_common_cookie) {\n    eventData = addCommonCookie(eventData);\n  }\n\n  return eventData;\n}\n\nfunction addCommonData(eventData) {\n  eventData.page_location = getUrl();\n  eventData.page_hostname = getUrl('host');\n  eventData.page_referrer = getReferrerUrl();\n  eventData.page_title = readTitle();\n  eventData.page_encoding = readCharacterSet();\n\n  return eventData;\n}\n\nfunction addConsentStateData(eventData) {\n  eventData.consent_state = {\n    ad_storage: isConsentGranted('ad_storage'),\n    ad_user_data: isConsentGranted('ad_user_data'),\n    ad_personalization: isConsentGranted('ad_personalization'),\n    analytics_storage: isConsentGranted('analytics_storage'),\n    functionality_storage: isConsentGranted('functionality_storage'),\n    personalization_storage: isConsentGranted('personalization_storage'),\n    security_storage: isConsentGranted('security_storage')\n  };\n  return eventData;\n}\n\nfunction addTempClientId(eventData) {\n  const tempClientIdStorageKey = 'gtm_dataTagTempClientId';\n  const tempClientId =\n    copyFromWindow(tempClientIdStorageKey) ||\n    'dcid.1.' + getTimestampMillis() + '.' + generateRandom(100000000, 999999999);\n\n  eventData._dcid_temp = tempClientId;\n  setInWindow(tempClientIdStorageKey, eventData._dcid_temp);\n\n  return eventData;\n}\n\nfunction getEventName(data) {\n  const eventName = 'page_view';\n\n  if (data.event_type === 'standard') {\n    return data.event_name_standard ? data.event_name_standard : eventName;\n  }\n\n  if (data.event_type === 'custom') {\n    return data.event_name_custom ? data.event_name_custom : eventName;\n  }\n\n  return eventName;\n}\n\nfunction getCustomData(data, dtagLoaded) {\n  let dataToStore = [];\n  let customData = userAndCustomData;\n\n  for (let dataKey in customData) {\n    let dataValue = customData[dataKey].value;\n    let dataTransformation = customData[dataKey].transformation;\n\n    if (dataValue) {\n      if (dataTransformation === 'trim') {\n        dataValue = makeString(dataValue);\n        dataValue = dataValue.trim();\n      }\n\n      if (dataTransformation === 'to_lower_case') {\n        dataValue = makeString(dataValue);\n        dataValue = dataValue.trim().toLowerCase();\n      }\n\n      if (dataTransformation === 'base64') {\n        dataValue = makeString(dataValue);\n        dataValue = toBase64(dataValue);\n      }\n\n      if (dtagLoaded && dataTransformation === 'md5') {\n        dataValue = makeString(dataValue);\n        dataValue = callInWindow('dataTagMD5', dataValue.trim().toLowerCase());\n      }\n\n      if (dtagLoaded && dataTransformation === 'sha256base64') {\n        dataValue = makeString(dataValue);\n        dataValue = callInWindow('dataTag256', dataValue.trim().toLowerCase(), 'B64');\n      }\n\n      if (dtagLoaded && dataTransformation === 'sha256hex') {\n        dataValue = makeString(dataValue);\n        dataValue = callInWindow('dataTag256', dataValue.trim().toLowerCase(), 'HEX');\n      }\n\n      if (customData[dataKey].store && customData[dataKey].store !== 'none') {\n        dataToStore.push({\n          store: customData[dataKey].store,\n          name: customData[dataKey].name,\n          value: dataValue\n        });\n      }\n\n      customData[dataKey].value = dataValue;\n    }\n  }\n\n  if (dataToStore.length !== 0) {\n    storeData(dataToStore);\n  }\n\n  return customData;\n}\n\nfunction storeData(dataToStore) {\n  let dataToStoreCookieResult = {};\n  let dataToStoreLocalStorageResult = {};\n  let dataToStoreCookie = getCookieValues('stape')[0];\n\n  if (dataToStoreCookie) {\n    dataToStoreCookie = JSON.parse(dataToStoreCookie);\n\n    if (dataToStoreCookie) {\n      for (let attrName in dataToStoreCookie) {\n        if (dataToStoreCookie[attrName])\n          dataToStoreCookieResult[attrName] = dataToStoreCookie[attrName];\n      }\n    }\n  }\n\n  if (localStorage) {\n    let dataToStoreLocalStorage = localStorage.getItem('stape');\n\n    if (dataToStoreLocalStorage) {\n      dataToStoreLocalStorage = JSON.parse(dataToStoreLocalStorage);\n\n      if (dataToStoreLocalStorage) {\n        for (let attrName in dataToStoreLocalStorage) {\n          if (dataToStoreLocalStorage[attrName])\n            dataToStoreLocalStorageResult[attrName] = dataToStoreLocalStorage[attrName];\n        }\n      }\n    }\n  }\n\n  for (let attrName in dataToStore) {\n    if (dataToStore[attrName].value) {\n      if (dataToStore[attrName].store === 'all' || dataToStore[attrName].store === 'localStorage') {\n        dataToStoreLocalStorageResult[dataToStore[attrName].name] = dataToStore[attrName].value;\n      }\n\n      if (dataToStore[attrName].store === 'all' || dataToStore[attrName].store === 'cookies') {\n        dataToStoreCookieResult[dataToStore[attrName].name] = dataToStore[attrName].value;\n      }\n    }\n  }\n\n  if (localStorage && getObjectLength(dataToStoreLocalStorageResult) !== 0) {\n    localStorage.setItem('stape', JSON.stringify(dataToStoreLocalStorageResult));\n  }\n\n  if (getObjectLength(dataToStoreCookieResult) !== 0) {\n    setCookie('stape', JSON.stringify(dataToStoreCookieResult), {\n      secure: true,\n      domain: 'auto',\n      path: '/'\n    });\n  }\n}\n\nfunction getObjectLength(object) {\n  let length = 0;\n\n  for (let key in object) {\n    if (object.hasOwnProperty(key)) {\n      ++length;\n    }\n  }\n  return length;\n}\n\nfunction determinateRequestType() {\n  if (data.request_type !== 'auto') {\n    return data.request_type;\n  }\n\n  if (data.add_data_layer || data.addGaParameters || data.dataLayerEventPush || data.richsstsse) {\n    return 'post';\n  }\n\n  const isHashingEnabled = userAndCustomData.some(\n    (item) =>\n      item.transformation === 'md5' ||\n      item.transformation === 'sha256base64' ||\n      item.transformation === 'sha256hex'\n  );\n  if (isHashingEnabled) return 'post';\n\n  const userAndCustomDataLength = makeNumber(JSON.stringify(userAndCustomData).length);\n  return userAndCustomDataLength > 1500 ? 'post' : 'get';\n}\n\nfunction getUserAndCustomDataArray() {\n  let userAndCustomDataArray = [];\n\n  if (data.custom_data && data.custom_data.length) {\n    userAndCustomDataArray = data.custom_data;\n  }\n\n  if (data.user_data && data.user_data.length) {\n    for (let userDataKey in data.user_data) {\n      userAndCustomDataArray.push(data.user_data[userDataKey]);\n    }\n  }\n  return userAndCustomDataArray;\n}\n\nfunction addCommonCookie(eventData) {\n  const cookieNames = [\n    // FB cookies\n    '_fbc',\n    '_fbp',\n    '_gtmeec',\n    // TikTok cookies\n    'ttclid',\n    '_ttp',\n    // Pinterest cookies\n    '_epik',\n    // Snapchat cookies\n    '_scid',\n    '_scclid',\n    // Taboola cookies\n    'taboola_cid',\n    // Awin cookies\n    'awin_awc',\n    'awin_sn_awc',\n    'awin_source',\n    // Rakuten cookies\n    'rakuten_site_id',\n    'rakuten_time_entered',\n    'rakuten_ran_mid',\n    'rakuten_ran_eaid',\n    'rakuten_ran_site_id',\n    // Klaviyo cookies\n    'stape_klaviyo_email',\n    'stape_klaviyo_kx',\n    'stape_klaviyo_viewed_items',\n    // Outbrain cookies\n    'outbrain_cid',\n    // Webgains cookies\n    'wg_cid',\n    // Postscript cookies\n    'ps_id',\n    // Microsoft UET CAPI cookies\n    'uet_msclkid',\n    '_uetmsclkid',\n    'uet_vid',\n    '_uetvid',\n    // Google cookies\n    '_dm_session_attributes',\n    'FPGCLAW',\n    '_gcl_aw',\n    'FPGCLAG',\n    '_gcl_ag',\n    'FPGCLGB',\n    '_gcl_gb',\n    'FPGCLDC',\n    '_gcl_dc',\n    // Linkedin cookie\n    'li_fat_id',\n    // OpenAI cookie\n    '__oppref'\n  ];\n\n  let commonCookie = null;\n\n  for (var i = 0; i < cookieNames.length; i++) {\n    const name = cookieNames[i];\n    var cookie = getCookieValues(name)[0];\n    if (cookie) {\n      commonCookie = commonCookie || {};\n      commonCookie[name] = cookie;\n    }\n  }\n  if (commonCookie) {\n    eventData.common_cookie = commonCookie;\n  }\n  return eventData;\n}\n\n\n___WEB_PERMISSIONS___\n\n[\n  {\n    \"instance\": {\n      \"key\": {\n        \"publicId\": \"access_globals\",\n        \"versionId\": \"1\"\n      },\n      \"param\": [\n        {\n          \"key\": \"keys\",\n          \"value\": {\n            \"type\": 2,\n            \"listItem\": [\n              {\n                \"type\": 3,\n                \"mapKey\": [\n                  {\n                    \"type\": 1,\n                    \"string\": \"key\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"read\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"write\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"execute\"\n                  }\n                ],\n                \"mapValue\": [\n                  {\n                    \"type\": 1,\n                    \"string\": \"dataLayer\"\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": true\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": false\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": false\n                  }\n                ]\n              },\n              {\n                \"type\": 3,\n                \"mapKey\": [\n                  {\n                    \"type\": 1,\n                    \"string\": \"key\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"read\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"write\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"execute\"\n                  }\n                ],\n                \"mapValue\": [\n                  {\n                    \"type\": 1,\n                    \"string\": \"dataTagSendData\"\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": true\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": true\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": true\n                  }\n                ]\n              },\n              {\n                \"type\": 3,\n                \"mapKey\": [\n                  {\n                    \"type\": 1,\n                    \"string\": \"key\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"read\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"write\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"execute\"\n                  }\n                ],\n                \"mapValue\": [\n                  {\n                    \"type\": 1,\n                    \"string\": \"dataTagGetData\"\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": true\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": true\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": true\n                  }\n                ]\n              },\n              {\n                \"type\": 3,\n                \"mapKey\": [\n                  {\n                    \"type\": 1,\n                    \"string\": \"key\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"read\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"write\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"execute\"\n                  }\n                ],\n                \"mapValue\": [\n                  {\n                    \"type\": 1,\n                    \"string\": \"dataTagData\"\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": true\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": true\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": false\n                  }\n                ]\n              },\n              {\n                \"type\": 3,\n                \"mapKey\": [\n                  {\n                    \"type\": 1,\n                    \"string\": \"key\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"read\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"write\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"execute\"\n                  }\n                ],\n                \"mapValue\": [\n                  {\n                    \"type\": 1,\n                    \"string\": \"dataTagMD5\"\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": true\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": true\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": true\n                  }\n                ]\n              },\n              {\n                \"type\": 3,\n                \"mapKey\": [\n                  {\n                    \"type\": 1,\n                    \"string\": \"key\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"read\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"write\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"execute\"\n                  }\n                ],\n                \"mapValue\": [\n                  {\n                    \"type\": 1,\n                    \"string\": \"dataTag256\"\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": true\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": true\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": true\n                  }\n                ]\n              },\n              {\n                \"type\": 3,\n                \"mapKey\": [\n                  {\n                    \"type\": 1,\n                    \"string\": \"key\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"read\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"write\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"execute\"\n                  }\n                ],\n                \"mapValue\": [\n                  {\n                    \"type\": 1,\n                    \"string\": \"gtm_dataTagTempClientId\"\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": true\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": true\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": false\n                  }\n                ]\n              },\n              {\n                \"type\": 3,\n                \"mapKey\": [\n                  {\n                    \"type\": 1,\n                    \"string\": \"key\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"read\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"write\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"execute\"\n                  }\n                ],\n                \"mapValue\": [\n                  {\n                    \"type\": 1,\n                    \"string\": \"gtm_dataTagScriptLoadedCache\"\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": true\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": true\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": false\n                  }\n                ]\n              }\n            ]\n          }\n        }\n      ]\n    },\n    \"clientAnnotations\": {\n      \"isEditedByUser\": true\n    },\n    \"isRequired\": true\n  },\n  {\n    \"instance\": {\n      \"key\": {\n        \"publicId\": \"get_referrer\",\n        \"versionId\": \"1\"\n      },\n      \"param\": [\n        {\n          \"key\": \"urlParts\",\n          \"value\": {\n            \"type\": 1,\n            \"string\": \"any\"\n          }\n        },\n        {\n          \"key\": \"queriesAllowed\",\n          \"value\": {\n            \"type\": 1,\n            \"string\": \"any\"\n          }\n        }\n      ]\n    },\n    \"clientAnnotations\": {\n      \"isEditedByUser\": true\n    },\n    \"isRequired\": true\n  },\n  {\n    \"instance\": {\n      \"key\": {\n        \"publicId\": \"read_data_layer\",\n        \"versionId\": \"1\"\n      },\n      \"param\": [\n        {\n          \"key\": \"allowedKeys\",\n          \"value\": {\n            \"type\": 1,\n            \"string\": \"specific\"\n          }\n        },\n        {\n          \"key\": \"keyPatterns\",\n          \"value\": {\n            \"type\": 2,\n            \"listItem\": [\n              {\n                \"type\": 1,\n                \"string\": \"gtm.uniqueEventId\"\n              },\n              {\n                \"type\": 1,\n                \"string\": \"gtm.start\"\n              }\n            ]\n          }\n        }\n      ]\n    },\n    \"clientAnnotations\": {\n      \"isEditedByUser\": true\n    },\n    \"isRequired\": true\n  },\n  {\n    \"instance\": {\n      \"key\": {\n        \"publicId\": \"read_title\",\n        \"versionId\": \"1\"\n      },\n      \"param\": []\n    },\n    \"isRequired\": true\n  },\n  {\n    \"instance\": {\n      \"key\": {\n        \"publicId\": \"get_url\",\n        \"versionId\": \"1\"\n      },\n      \"param\": [\n        {\n          \"key\": \"urlParts\",\n          \"value\": {\n            \"type\": 1,\n            \"string\": \"any\"\n          }\n        },\n        {\n          \"key\": \"queriesAllowed\",\n          \"value\": {\n            \"type\": 1,\n            \"string\": \"any\"\n          }\n        }\n      ]\n    },\n    \"clientAnnotations\": {\n      \"isEditedByUser\": true\n    },\n    \"isRequired\": true\n  },\n  {\n    \"instance\": {\n      \"key\": {\n        \"publicId\": \"inject_script\",\n        \"versionId\": \"1\"\n      },\n      \"param\": [\n        {\n          \"key\": \"urls\",\n          \"value\": {\n            \"type\": 2,\n            \"listItem\": [\n              {\n                \"type\": 1,\n                \"string\": \"https://stapecdn.com/dtag/*\"\n              }\n            ]\n          }\n        }\n      ]\n    },\n    \"clientAnnotations\": {\n      \"isEditedByUser\": true\n    },\n    \"isRequired\": true\n  },\n  {\n    \"instance\": {\n      \"key\": {\n        \"publicId\": \"access_local_storage\",\n        \"versionId\": \"1\"\n      },\n      \"param\": [\n        {\n          \"key\": \"keys\",\n          \"value\": {\n            \"type\": 2,\n            \"listItem\": [\n              {\n                \"type\": 3,\n                \"mapKey\": [\n                  {\n                    \"type\": 1,\n                    \"string\": \"key\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"read\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"write\"\n                  }\n                ],\n                \"mapValue\": [\n                  {\n                    \"type\": 1,\n                    \"string\": \"stape\"\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": true\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": true\n                  }\n                ]\n              }\n            ]\n          }\n        }\n      ]\n    },\n    \"clientAnnotations\": {\n      \"isEditedByUser\": true\n    },\n    \"isRequired\": true\n  },\n  {\n    \"instance\": {\n      \"key\": {\n        \"publicId\": \"read_character_set\",\n        \"versionId\": \"1\"\n      },\n      \"param\": []\n    },\n    \"isRequired\": true\n  },\n  {\n    \"instance\": {\n      \"key\": {\n        \"publicId\": \"send_pixel\",\n        \"versionId\": \"1\"\n      },\n      \"param\": [\n        {\n          \"key\": \"allowedUrls\",\n          \"value\": {\n            \"type\": 1,\n            \"string\": \"any\"\n          }\n        }\n      ]\n    },\n    \"clientAnnotations\": {\n      \"isEditedByUser\": true\n    },\n    \"isRequired\": true\n  },\n  {\n    \"instance\": {\n      \"key\": {\n        \"publicId\": \"get_cookies\",\n        \"versionId\": \"1\"\n      },\n      \"param\": [\n        {\n          \"key\": \"cookieAccess\",\n          \"value\": {\n            \"type\": 1,\n            \"string\": \"specific\"\n          }\n        },\n        {\n          \"key\": \"cookieNames\",\n          \"value\": {\n            \"type\": 2,\n            \"listItem\": [\n              {\n                \"type\": 1,\n                \"string\": \"stape\"\n              },\n              {\n                \"type\": 1,\n                \"string\": \"_fbc\"\n              },\n              {\n                \"type\": 1,\n                \"string\": \"_fbp\"\n              },\n              {\n                \"type\": 1,\n                \"string\": \"_gtmeec\"\n              },\n              {\n                \"type\": 1,\n                \"string\": \"ttclid\"\n              },\n              {\n                \"type\": 1,\n                \"string\": \"_ttp\"\n              },\n              {\n                \"type\": 1,\n                \"string\": \"_epik\"\n              },\n              {\n                \"type\": 1,\n                \"string\": \"_scid\"\n              },\n              {\n                \"type\": 1,\n                \"string\": \"_scclid\"\n              },\n              {\n                \"type\": 1,\n                \"string\": \"taboola_cid\"\n              },\n              {\n                \"type\": 1,\n                \"string\": \"awin_awc\"\n              },\n              {\n                \"type\": 1,\n                \"string\": \"awin_sn_awc\"\n              },\n              {\n                \"type\": 1,\n                \"string\": \"awin_source\"\n              },\n              {\n                \"type\": 1,\n                \"string\": \"rakuten_site_id\"\n              },\n              {\n                \"type\": 1,\n                \"string\": \"rakuten_time_entered\"\n              },\n              {\n                \"type\": 1,\n                \"string\": \"rakuten_ran_mid\"\n              },\n              {\n                \"type\": 1,\n                \"string\": \"rakuten_ran_eaid\"\n              },\n              {\n                \"type\": 1,\n                \"string\": \"rakuten_ran_site_id\"\n              },\n              {\n                \"type\": 1,\n                \"string\": \"stape_klaviyo_email\"\n              },\n              {\n                \"type\": 1,\n                \"string\": \"stape_klaviyo_kx\"\n              },\n              {\n                \"type\": 1,\n                \"string\": \"stape_klaviyo_viewed_items\"\n              },\n              {\n                \"type\": 1,\n                \"string\": \"outbrain_cid\"\n              },\n              {\n                \"type\": 1,\n                \"string\": \"wg_cid\"\n              },\n              {\n                \"type\": 1,\n                \"string\": \"ps_id\"\n              },\n              {\n                \"type\": 1,\n                \"string\": \"uet_msclkid\"\n              },\n              {\n                \"type\": 1,\n                \"string\": \"_uetmsclkid\"\n              },\n              {\n                \"type\": 1,\n                \"string\": \"uet_vid\"\n              },\n              {\n                \"type\": 1,\n                \"string\": \"_uetvid\"\n              },\n              {\n                \"type\": 1,\n                \"string\": \"_dm_session_attributes\"\n              },\n              {\n                \"type\": 1,\n                \"string\": \"FPGCLAW\"\n              },\n              {\n                \"type\": 1,\n                \"string\": \"_gcl_aw\"\n              },\n              {\n                \"type\": 1,\n                \"string\": \"FPGCLAG\"\n              },\n              {\n                \"type\": 1,\n                \"string\": \"_gcl_ag\"\n              },\n              {\n                \"type\": 1,\n                \"string\": \"FPGCLGB\"\n              },\n              {\n                \"type\": 1,\n                \"string\": \"_gcl_gb\"\n              },\n              {\n                \"type\": 1,\n                \"string\": \"FPGCLDC\"\n              },\n              {\n                \"type\": 1,\n                \"string\": \"_gcl_dc\"\n              },\n              {\n                \"type\": 1,\n                \"string\": \"li_fat_id\"\n              },\n              {\n                \"type\": 1,\n                \"string\": \"__oppref\"\n              }\n            ]\n          }\n        }\n      ]\n    },\n    \"clientAnnotations\": {\n      \"isEditedByUser\": true\n    },\n    \"isRequired\": true\n  },\n  {\n    \"instance\": {\n      \"key\": {\n        \"publicId\": \"set_cookies\",\n        \"versionId\": \"1\"\n      },\n      \"param\": [\n        {\n          \"key\": \"allowedCookies\",\n          \"value\": {\n            \"type\": 2,\n            \"listItem\": [\n              {\n                \"type\": 3,\n                \"mapKey\": [\n                  {\n                    \"type\": 1,\n                    \"string\": \"name\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"domain\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"path\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"secure\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"session\"\n                  }\n                ],\n                \"mapValue\": [\n                  {\n                    \"type\": 1,\n                    \"string\": \"stape\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"*\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"*\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"any\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"any\"\n                  }\n                ]\n              }\n            ]\n          }\n        }\n      ]\n    },\n    \"clientAnnotations\": {\n      \"isEditedByUser\": true\n    },\n    \"isRequired\": true\n  },\n  {\n    \"instance\": {\n      \"key\": {\n        \"publicId\": \"read_container_data\",\n        \"versionId\": \"1\"\n      },\n      \"param\": []\n    },\n    \"isRequired\": true\n  },\n  {\n    \"instance\": {\n      \"key\": {\n        \"publicId\": \"access_consent\",\n        \"versionId\": \"1\"\n      },\n      \"param\": [\n        {\n          \"key\": \"consentTypes\",\n          \"value\": {\n            \"type\": 2,\n            \"listItem\": [\n              {\n                \"type\": 3,\n                \"mapKey\": [\n                  {\n                    \"type\": 1,\n                    \"string\": \"consentType\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"read\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"write\"\n                  }\n                ],\n                \"mapValue\": [\n                  {\n                    \"type\": 1,\n                    \"string\": \"ad_storage\"\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": true\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": false\n                  }\n                ]\n              },\n              {\n                \"type\": 3,\n                \"mapKey\": [\n                  {\n                    \"type\": 1,\n                    \"string\": \"consentType\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"read\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"write\"\n                  }\n                ],\n                \"mapValue\": [\n                  {\n                    \"type\": 1,\n                    \"string\": \"ad_user_data\"\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": true\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": false\n                  }\n                ]\n              },\n              {\n                \"type\": 3,\n                \"mapKey\": [\n                  {\n                    \"type\": 1,\n                    \"string\": \"consentType\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"read\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"write\"\n                  }\n                ],\n                \"mapValue\": [\n                  {\n                    \"type\": 1,\n                    \"string\": \"ad_personalization\"\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": true\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": false\n                  }\n                ]\n              },\n              {\n                \"type\": 3,\n                \"mapKey\": [\n                  {\n                    \"type\": 1,\n                    \"string\": \"consentType\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"read\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"write\"\n                  }\n                ],\n                \"mapValue\": [\n                  {\n                    \"type\": 1,\n                    \"string\": \"analytics_storage\"\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": true\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": false\n                  }\n                ]\n              },\n              {\n                \"type\": 3,\n                \"mapKey\": [\n                  {\n                    \"type\": 1,\n                    \"string\": \"consentType\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"read\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"write\"\n                  }\n                ],\n                \"mapValue\": [\n                  {\n                    \"type\": 1,\n                    \"string\": \"functionality_storage\"\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": true\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": false\n                  }\n                ]\n              },\n              {\n                \"type\": 3,\n                \"mapKey\": [\n                  {\n                    \"type\": 1,\n                    \"string\": \"consentType\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"read\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"write\"\n                  }\n                ],\n                \"mapValue\": [\n                  {\n                    \"type\": 1,\n                    \"string\": \"personalization_storage\"\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": true\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": false\n                  }\n                ]\n              },\n              {\n                \"type\": 3,\n                \"mapKey\": [\n                  {\n                    \"type\": 1,\n                    \"string\": \"consentType\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"read\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"write\"\n                  }\n                ],\n                \"mapValue\": [\n                  {\n                    \"type\": 1,\n                    \"string\": \"security_storage\"\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": true\n                  },\n                  {\n                    \"type\": 8,\n                    \"boolean\": false\n                  }\n                ]\n              }\n            ]\n          }\n        }\n      ]\n    },\n    \"clientAnnotations\": {\n      \"isEditedByUser\": true\n    },\n    \"isRequired\": true\n  }\n]\n\n\n___TESTS___\n\nscenarios:\n- name: GTM Server Side URL and Request Path for GET requests are normalized\n  code: \"mockData.request_type = 'get';\\nmockData.event_type = 'standard';\\nmockData.event_name_standard\\\n    \\ = 'page_view';\\n\\n[\\n  { gtm_server_domain: 'example.com', request_path: '/foo',\\\n    \\ expectedServerUrl: 'https://example.com/foo' },\\n  { gtm_server_domain: 'example.com/',\\\n    \\ request_path: '/foo', expectedServerUrl: 'https://example.com/foo' },\\n  { gtm_server_domain:\\\n    \\ 'https://example.com', request_path: '/foo', expectedServerUrl: 'https://example.com/foo'\\\n    \\ },\\n  { gtm_server_domain: 'https://example.com/', request_path: '/foo', expectedServerUrl:\\\n    \\ 'https://example.com/foo' },\\n  { gtm_server_domain: 'example.com', request_path:\\\n    \\ 'foo/', expectedServerUrl: 'https://example.com/foo' },\\n  { gtm_server_domain:\\\n    \\ 'example.com/', request_path: 'foo/', expectedServerUrl: 'https://example.com/foo'\\\n    \\ },\\n  { gtm_server_domain: 'https://example.com', request_path: 'foo/', expectedServerUrl:\\\n    \\ 'https://example.com/foo' },\\n  { gtm_server_domain: 'https://example.com/',\\\n    \\ request_path: 'foo/', expectedServerUrl: 'https://example.com/foo' },\\n  { gtm_server_domain:\\\n    \\ 'http://example.com', request_path: '/foo', expectedServerUrl: 'http://example.com/foo'\\\n    \\ },\\n  { gtm_server_domain: 'http://example.com/', request_path: '/foo', expectedServerUrl:\\\n    \\ 'http://example.com/foo' },\\n  { gtm_server_domain: 'http://example.com', request_path:\\\n    \\ 'foo/', expectedServerUrl: 'http://example.com/foo' },\\n  { gtm_server_domain:\\\n    \\ 'http://example.com/', request_path: 'foo/', expectedServerUrl: 'http://example.com/foo'\\\n    \\ },\\n].forEach((testCase, testNumber) => {\\n  mockData.gtm_server_domain = testCase.gtm_server_domain;\\n\\\n    \\  mockData.request_path = testCase.request_path;\\n  \\n  mock('sendPixel', function(url,\\\n    \\ onSuccess, onFailure) {\\n    // logToConsole('#' + testNumber + ' - sendPixel\\\n    \\ called with URL:', url);\\n    assertThat(url).contains(testCase.expectedServerUrl);\\n\\\n    \\  });\\n\\n  runCode(mockData);\\n});\"\n- name: GTM Server Side URL and Request Path for POST requests are normalized\n  code: \"mockData.request_type = 'post';\\nmockData.event_type = 'standard';\\nmockData.event_name_standard\\\n    \\ = 'cc';\\n\\nmock('injectScript', function(url, onSuccess, onFailure, cacheToken)\\\n    \\ {\\n  onSuccess();\\n});\\n\\nconst expectedRequestPathParams = '?v=' + mockData.protocol_version;\\n\\\n    \\n[\\n  { gtm_server_domain: 'example.com', request_path: '/foo', expectedGtmServerDomain:\\\n    \\ 'https://example.com', expectedRequestPath: '/foo' + expectedRequestPathParams\\\n    \\ },\\n  { gtm_server_domain: 'example.com/', request_path: '/foo', expectedGtmServerDomain:\\\n    \\ 'https://example.com', expectedRequestPath: '/foo' + expectedRequestPathParams\\\n    \\ },\\n  { gtm_server_domain: 'https://example.com', request_path: '/foo', expectedGtmServerDomain:\\\n    \\ 'https://example.com', expectedRequestPath: '/foo' + expectedRequestPathParams\\\n    \\ },\\n  { gtm_server_domain: 'https://example.com/', request_path: '/foo', expectedGtmServerDomain:\\\n    \\ 'https://example.com', expectedRequestPath: '/foo' + expectedRequestPathParams\\\n    \\ },\\n  { gtm_server_domain: 'example.com', request_path: 'foo/', expectedGtmServerDomain:\\\n    \\ 'https://example.com', expectedRequestPath: '/foo/' + expectedRequestPathParams\\\n    \\ },\\n  { gtm_server_domain: 'example.com/', request_path: 'foo/', expectedGtmServerDomain:\\\n    \\ 'https://example.com', expectedRequestPath: '/foo/' + expectedRequestPathParams\\\n    \\ },\\n  { gtm_server_domain: 'https://example.com', request_path: 'foo/', expectedGtmServerDomain:\\\n    \\ 'https://example.com', expectedRequestPath: '/foo/' + expectedRequestPathParams\\\n    \\ },\\n  { gtm_server_domain: 'https://example.com/', request_path: 'foo/', expectedGtmServerDomain:\\\n    \\ 'https://example.com', expectedRequestPath: '/foo/' + expectedRequestPathParams\\\n    \\ },\\n  { gtm_server_domain: 'http://example.com', request_path: '/foo', expectedGtmServerDomain:\\\n    \\ 'http://example.com', expectedRequestPath: '/foo' + expectedRequestPathParams\\\n    \\ },\\n  { gtm_server_domain: 'http://example.com/', request_path: '/foo', expectedGtmServerDomain:\\\n    \\ 'http://example.com', expectedRequestPath: '/foo' + expectedRequestPathParams\\\n    \\ },\\n  { gtm_server_domain: 'http://example.com', request_path: 'foo/', expectedGtmServerDomain:\\\n    \\ 'http://example.com', expectedRequestPath: '/foo/' + expectedRequestPathParams\\\n    \\ },\\n  { gtm_server_domain: 'http://example.com/', request_path: 'foo/', expectedGtmServerDomain:\\\n    \\ 'http://example.com', expectedRequestPath: '/foo/' + expectedRequestPathParams\\\n    \\ },\\n].forEach((testCase, testNumber) => {\\n  mockData.gtm_server_domain = testCase.gtm_server_domain;\\n\\\n    \\  mockData.request_path = testCase.request_path;\\n  \\n  mock('callInWindow',\\\n    \\ function(functionName, eventData, gtmServerDomain, requestPath, dataLayerEventName,\\\n    \\ dataLayerVariableName, waitForCookies, useFetchInsteadOfXHR) {\\n    /*\\n   \\\n    \\ logToConsole('#' + testNumber + ' - callInWindow called with:', {\\n      functionName:\\\n    \\ functionName,\\n      gtmServerDomain: gtmServerDomain,\\n      requestPath: requestPath,\\n\\\n    \\    });\\n    */\\n    \\n    assertThat(gtmServerDomain).isEqualTo(testCase.expectedGtmServerDomain);\\n\\\n    \\    const requestPathStartsWith = requestPath.indexOf(testCase.expectedRequestPath)\\\n    \\ === 0;\\n    assertThat(requestPathStartsWith).isTrue();\\n  });\\n\\n  runCode(mockData);\\n\\\n    });\"\nsetup: |-\n  const mockData = {\n    protocol_version: '2'\n  };\n\n\n___NOTES___\n\n2026-06-05 - Change Notes:\n  - Add FPGCLDC and _gcl_dc (Display & Video 360 click ID cookies) to the common cookie object and read permissions, extending conversion tracking support for CM360 campaigns\n\nCreated on 21/03/2021, 11:26:46\n\n\n",
                "galleryReference": {
                    "host": "github.com",
                    "owner": "stape-io",
                    "repository": "data-tag",
                    "version": "f19903150c4ead1cf2a868f74381d89dceb35977",
                    "signature": "9bb127e34975a96e50ff5eb9eed7f1d4a8227928bb92b854f8c2ea1b9798559c",
                    "galleryTemplateId": "MBTSV"
                }
            }
        ]
    }
}