{
    "exportFormatVersion": 2,
    "exportTime": "2026-10-03 10:13:49",
    "containerVersion": {
        "path": "accounts/6374306328/containers/262778781/versions/0",
        "accountId": "6374306328",
        "containerId": "262778781",
        "containerVersionId": "0",
        "container": {
            "path": "accounts/6374306328/containers/262778781",
            "accountId": "6374306328",
            "containerId": "262778781",
            "name": "PixelFly JSON | Server || GTM",
            "publicId": "GTM-WBMQ4SW9",
            "usageContext": [
                "SERVER"
            ],
            "fingerprint": "1788193085885",
            "tagManagerUrl": "https://tagmanager.google.com/#/container/accounts/6374306328/containers/262778781/workspaces?apiLink=container",
            "features": {
                "supportUserPermissions": true,
                "supportEnvironments": true,
                "supportWorkspaces": true,
                "supportGtagConfigs": false,
                "supportBuiltInVariables": true,
                "supportClients": true,
                "supportFolders": true,
                "supportTags": true,
                "supportTemplates": true,
                "supportTriggers": true,
                "supportVariables": true,
                "supportVersions": true,
                "supportZones": true,
                "supportTransformations": true
            },
            "tagIds": [
                "GTM-WBMQ4SW9"
            ]
        },
        "tag": [
            {
                "accountId": "6374306328",
                "containerId": "262778781",
                "tagId": "6",
                "name": "TikTok Events API",
                "type": "cvt_K8M24",
                "parameter": [
                    {
                        "type": "TEMPLATE",
                        "key": "adStorageConsent",
                        "value": "optional"
                    },
                    {
                        "type": "TEMPLATE",
                        "key": "pixelId",
                        "value": "00000"
                    },
                    {
                        "type": "BOOLEAN",
                        "key": "generateTtp",
                        "value": "true"
                    },
                    {
                        "type": "BOOLEAN",
                        "key": "overrideCookiesSettings",
                        "value": "false"
                    },
                    {
                        "type": "BOOLEAN",
                        "key": "useOptimisticScenario",
                        "value": "false"
                    },
                    {
                        "type": "TEMPLATE",
                        "key": "testEventCode",
                        "value": "TEST66766"
                    },
                    {
                        "type": "TEMPLATE",
                        "key": "eventSource",
                        "value": "web"
                    },
                    {
                        "type": "BOOLEAN",
                        "key": "limitedDataUse",
                        "value": "false"
                    },
                    {
                        "type": "TEMPLATE",
                        "key": "eventType",
                        "value": "inherit"
                    },
                    {
                        "type": "TEMPLATE",
                        "key": "accessToken",
                        "value": "0000000"
                    },
                    {
                        "type": "BOOLEAN",
                        "key": "enableEventEnhancement",
                        "value": "true"
                    }
                ],
                "fingerprint": "1791000829716",
                "firingTriggerId": [
                    "5",
                    "15"
                ],
                "tagFiringOption": "ONCE_PER_EVENT",
                "paused": true,
                "monitoringMetadata": {
                    "type": "MAP"
                },
                "consentSettings": {
                    "consentStatus": "NOT_SET"
                },
                "blockingTriggerId": [
                    "14"
                ]
            },
            {
                "accountId": "6374306328",
                "containerId": "262778781",
                "tagId": "12",
                "name": "GA4-Server Side",
                "type": "sgtmgaaw",
                "parameter": [
                    {
                        "type": "BOOLEAN",
                        "key": "redactVisitorIp",
                        "value": "false"
                    },
                    {
                        "type": "TEMPLATE",
                        "key": "epToIncludeDropdown",
                        "value": "all"
                    },
                    {
                        "type": "LIST",
                        "key": "epToExclude",
                        "list": [
                            {
                                "type": "MAP",
                                "map": [
                                    {
                                        "type": "TEMPLATE",
                                        "key": "fieldName",
                                        "value": "event_id"
                                    }
                                ]
                            },
                            {
                                "type": "MAP",
                                "map": [
                                    {
                                        "type": "TEMPLATE",
                                        "key": "fieldName",
                                        "value": "event_name"
                                    }
                                ]
                            },
                            {
                                "type": "MAP",
                                "map": [
                                    {
                                        "type": "TEMPLATE",
                                        "key": "fieldName",
                                        "value": "event_time"
                                    }
                                ]
                            },
                            {
                                "type": "MAP",
                                "map": [
                                    {
                                        "type": "TEMPLATE",
                                        "key": "fieldName",
                                        "value": "x-fb-ck-fbc"
                                    }
                                ]
                            },
                            {
                                "type": "MAP",
                                "map": [
                                    {
                                        "type": "TEMPLATE",
                                        "key": "fieldName",
                                        "value": "x-fb-ck-fbp"
                                    }
                                ]
                            },
                            {
                                "type": "MAP",
                                "map": [
                                    {
                                        "type": "TEMPLATE",
                                        "key": "fieldName",
                                        "value": "first_party_collection"
                                    }
                                ]
                            },
                            {
                                "type": "MAP",
                                "map": [
                                    {
                                        "type": "TEMPLATE",
                                        "key": "fieldName",
                                        "value": "x-fb-ud-external_id"
                                    }
                                ]
                            },
                            {
                                "type": "MAP",
                                "map": [
                                    {
                                        "type": "TEMPLATE",
                                        "key": "fieldName",
                                        "value": "x-fb-cd-content_type"
                                    }
                                ]
                            },
                            {
                                "type": "MAP",
                                "map": [
                                    {
                                        "type": "TEMPLATE",
                                        "key": "fieldName",
                                        "value": "x-fb-cd-content_category"
                                    }
                                ]
                            },
                            {
                                "type": "MAP",
                                "map": [
                                    {
                                        "type": "TEMPLATE",
                                        "key": "fieldName",
                                        "value": "x-fb-cd-num_items"
                                    }
                                ]
                            },
                            {
                                "type": "MAP",
                                "map": [
                                    {
                                        "type": "TEMPLATE",
                                        "key": "fieldName",
                                        "value": "client_ip_address"
                                    }
                                ]
                            },
                            {
                                "type": "MAP",
                                "map": [
                                    {
                                        "type": "TEMPLATE",
                                        "key": "fieldName",
                                        "value": "x-fb-cd-content_name"
                                    }
                                ]
                            },
                            {
                                "type": "MAP",
                                "map": [
                                    {
                                        "type": "TEMPLATE",
                                        "key": "fieldName",
                                        "value": "x-fb-cd-content_ids"
                                    }
                                ]
                            },
                            {
                                "type": "MAP",
                                "map": [
                                    {
                                        "type": "TEMPLATE",
                                        "key": "fieldName",
                                        "value": "cod_hold"
                                    }
                                ]
                            },
                            {
                                "type": "MAP",
                                "map": [
                                    {
                                        "type": "TEMPLATE",
                                        "key": "fieldName",
                                        "value": "is_delayed"
                                    }
                                ]
                            },
                            {
                                "type": "MAP",
                                "map": [
                                    {
                                        "type": "TEMPLATE",
                                        "key": "fieldName",
                                        "value": "delayed_reason"
                                    }
                                ]
                            },
                            {
                                "type": "MAP",
                                "map": [
                                    {
                                        "type": "TEMPLATE",
                                        "key": "fieldName",
                                        "value": "data_source"
                                    }
                                ]
                            },
                            {
                                "type": "MAP",
                                "map": [
                                    {
                                        "type": "TEMPLATE",
                                        "key": "fieldName",
                                        "value": "gclid"
                                    }
                                ]
                            },
                            {
                                "type": "MAP",
                                "map": [
                                    {
                                        "type": "TEMPLATE",
                                        "key": "fieldName",
                                        "value": "gbraid"
                                    }
                                ]
                            }
                        ]
                    },
                    {
                        "type": "TEMPLATE",
                        "key": "upToIncludeDropdown",
                        "value": "all"
                    },
                    {
                        "type": "TEMPLATE",
                        "key": "measurementId",
                        "value": "G-00000000000000000"
                    }
                ],
                "fingerprint": "1791000829716",
                "firingTriggerId": [
                    "10",
                    "15"
                ],
                "tagFiringOption": "ONCE_PER_EVENT",
                "monitoringMetadata": {
                    "type": "MAP"
                },
                "consentSettings": {
                    "consentStatus": "NOT_SET"
                },
                "blockingTriggerId": [
                    "14"
                ]
            },
            {
                "accountId": "6374306328",
                "containerId": "262778781",
                "tagId": "15",
                "name": "Facebook CAPI",
                "type": "cvt_NCN6S",
                "parameter": [
                    {
                        "type": "TEMPLATE",
                        "key": "pixelId",
                        "value": "00000000000000000"
                    },
                    {
                        "type": "TEMPLATE",
                        "key": "apiAccessToken",
                        "value": "00000000000000000"
                    },
                    {
                        "type": "TEMPLATE",
                        "key": "testEventCode",
                        "value": ""
                    },
                    {
                        "type": "BOOLEAN",
                        "key": "enableEventEnhancement",
                        "value": "true"
                    },
                    {
                        "type": "BOOLEAN",
                        "key": "extendCookies",
                        "value": "true"
                    },
                    {
                        "type": "TEMPLATE",
                        "key": "actionSource",
                        "value": "website"
                    }
                ],
                "fingerprint": "1791000829716",
                "firingTriggerId": [
                    "13",
                    "15"
                ],
                "tagFiringOption": "ONCE_PER_EVENT",
                "monitoringMetadata": {
                    "type": "MAP"
                },
                "consentSettings": {
                    "consentStatus": "NOT_SET"
                },
                "blockingTriggerId": [
                    "14"
                ]
            },
            {
                "accountId": "6374306328",
                "containerId": "262778781",
                "tagId": "16",
                "name": "PixelFly COD Protection (hold)",
                "type": "cvt_262778781_18",
                "parameter": [
                    {
                        "type": "TEMPLATE",
                        "key": "serverHost",
                        "value": "{{PixelFly - COD Host}}"
                    },
                    {
                        "type": "TEMPLATE",
                        "key": "apiKey",
                        "value": "{{PixelFly - COD API Key}}"
                    },
                    {
                        "type": "TEMPLATE",
                        "key": "dataMode",
                        "value": "auto"
                    },
                    {
                        "type": "BOOLEAN",
                        "key": "skipIfNotCod",
                        "value": "true"
                    },
                    {
                        "type": "BOOLEAN",
                        "key": "includeEventSnapshot",
                        "value": "false"
                    },
                    {
                        "type": "BOOLEAN",
                        "key": "logToConsole",
                        "value": "false"
                    }
                ],
                "fingerprint": "1791000829716",
                "firingTriggerId": [
                    "14"
                ],
                "tagFiringOption": "ONCE_PER_EVENT",
                "monitoringMetadata": {
                    "type": "MAP"
                },
                "consentSettings": {
                    "consentStatus": "NOT_SET"
                }
            },
            {
                "accountId": "6374306328",
                "containerId": "262778781",
                "tagId": "17",
                "name": "Google Ads Conversion (COD confirmed)",
                "type": "sgtmadsct",
                "paused": true,
                "parameter": [
                    {
                        "type": "BOOLEAN",
                        "key": "enableNewCustomerReporting",
                        "value": "false"
                    },
                    {
                        "type": "BOOLEAN",
                        "key": "enableConversionLinker",
                        "value": "true"
                    },
                    {
                        "type": "BOOLEAN",
                        "key": "enableProductReporting",
                        "value": "false"
                    },
                    {
                        "type": "TEMPLATE",
                        "key": "conversionValue",
                        "value": "{{ED - value}}"
                    },
                    {
                        "type": "TEMPLATE",
                        "key": "conversionId",
                        "value": "{{PixelFly - Google Ads Conversion ID}}"
                    },
                    {
                        "type": "TEMPLATE",
                        "key": "currencyCode",
                        "value": "{{ED - currency}}"
                    },
                    {
                        "type": "TEMPLATE",
                        "key": "conversionLabel",
                        "value": "{{PixelFly - Google Ads Conversion Label}}"
                    },
                    {
                        "type": "BOOLEAN",
                        "key": "rdp",
                        "value": "false"
                    }
                ],
                "fingerprint": "1791000829716",
                "firingTriggerId": [
                    "15"
                ],
                "tagFiringOption": "ONCE_PER_EVENT",
                "monitoringMetadata": {
                    "type": "MAP"
                },
                "consentSettings": {
                    "consentStatus": "NOT_SET"
                }
            }
        ],
        "trigger": [
            {
                "accountId": "6374306328",
                "containerId": "262778781",
                "triggerId": "5",
                "name": "Titkok Events API",
                "type": "ALWAYS",
                "filter": [
                    {
                        "type": "MATCH_REGEX",
                        "parameter": [
                            {
                                "type": "TEMPLATE",
                                "key": "arg0",
                                "value": "{{Event Name}}"
                            },
                            {
                                "type": "TEMPLATE",
                                "key": "arg1",
                                "value": "page_view|view_item|add_to_cart|begin_checkout|purchase"
                            }
                        ]
                    }
                ],
                "fingerprint": "1788192494720"
            },
            {
                "accountId": "6374306328",
                "containerId": "262778781",
                "triggerId": "10",
                "name": "GA4-Client Name",
                "type": "ALWAYS",
                "filter": [
                    {
                        "type": "EQUALS",
                        "parameter": [
                            {
                                "type": "TEMPLATE",
                                "key": "arg0",
                                "value": "{{Client Name}}"
                            },
                            {
                                "type": "TEMPLATE",
                                "key": "arg1",
                                "value": "GA4"
                            }
                        ]
                    }
                ],
                "fingerprint": "1788192494721"
            },
            {
                "accountId": "6374306328",
                "containerId": "262778781",
                "triggerId": "13",
                "name": "GA4-Events Name",
                "type": "ALWAYS",
                "filter": [
                    {
                        "type": "MATCH_REGEX",
                        "parameter": [
                            {
                                "type": "TEMPLATE",
                                "key": "arg0",
                                "value": "{{Event Name}}"
                            },
                            {
                                "type": "TEMPLATE",
                                "key": "arg1",
                                "value": "remove_from_cart|page_view|view_item|add_to_cart|begin_checkout|purchase|view_cart|phone_click|scroll_25|scroll_50|scroll_75|scroll_100"
                            }
                        ]
                    }
                ],
                "fingerprint": "1788192494721"
            },
            {
                "accountId": "6374306328",
                "containerId": "262778781",
                "triggerId": "14",
                "name": "purchase - COD hold (PixelFly)",
                "type": "ALWAYS",
                "filter": [
                    {
                        "type": "EQUALS",
                        "parameter": [
                            {
                                "type": "TEMPLATE",
                                "key": "arg0",
                                "value": "{{Client Name}}"
                            },
                            {
                                "type": "TEMPLATE",
                                "key": "arg1",
                                "value": "GA4"
                            }
                        ]
                    },
                    {
                        "type": "EQUALS",
                        "parameter": [
                            {
                                "type": "TEMPLATE",
                                "key": "arg0",
                                "value": "{{Event Name}}"
                            },
                            {
                                "type": "TEMPLATE",
                                "key": "arg1",
                                "value": "purchase"
                            }
                        ]
                    },
                    {
                        "type": "EQUALS",
                        "parameter": [
                            {
                                "type": "TEMPLATE",
                                "key": "arg0",
                                "value": "{{ED - cod_hold}}"
                            },
                            {
                                "type": "TEMPLATE",
                                "key": "arg1",
                                "value": "true"
                            }
                        ]
                    },
                    {
                        "type": "STARTS_WITH",
                        "parameter": [
                            {
                                "type": "TEMPLATE",
                                "key": "arg0",
                                "value": "{{PixelFly - COD API Key}}"
                            },
                            {
                                "type": "TEMPLATE",
                                "key": "arg1",
                                "value": "pf_live_"
                            }
                        ]
                    },
                    {
                        "type": "EQUALS",
                        "parameter": [
                            {
                                "type": "TEMPLATE",
                                "key": "arg0",
                                "value": "{{PixelFly - COD API Key}}"
                            },
                            {
                                "type": "TEMPLATE",
                                "key": "arg1",
                                "value": "pf_live_REPLACE_ME"
                            },
                            {
                                "type": "BOOLEAN",
                                "key": "negate",
                                "value": "true"
                            }
                        ]
                    },
                    {
                        "type": "EQUALS",
                        "parameter": [
                            {
                                "type": "TEMPLATE",
                                "key": "arg0",
                                "value": "{{PixelFly - COD Host}}"
                            },
                            {
                                "type": "TEMPLATE",
                                "key": "arg1",
                                "value": "https://YOUR-SGTM-DOMAIN"
                            },
                            {
                                "type": "BOOLEAN",
                                "key": "negate",
                                "value": "true"
                            }
                        ]
                    }
                ],
                "fingerprint": "1791000829716"
            },
            {
                "accountId": "6374306328",
                "containerId": "262778781",
                "triggerId": "15",
                "name": "purchase - COD confirmed (PixelFly Data Client)",
                "type": "ALWAYS",
                "filter": [
                    {
                        "type": "EQUALS",
                        "parameter": [
                            {
                                "type": "TEMPLATE",
                                "key": "arg0",
                                "value": "{{Client Name}}"
                            },
                            {
                                "type": "TEMPLATE",
                                "key": "arg1",
                                "value": "Data Client"
                            }
                        ]
                    },
                    {
                        "type": "EQUALS",
                        "parameter": [
                            {
                                "type": "TEMPLATE",
                                "key": "arg0",
                                "value": "{{Event Name}}"
                            },
                            {
                                "type": "TEMPLATE",
                                "key": "arg1",
                                "value": "purchase"
                            }
                        ]
                    },
                    {
                        "type": "EQUALS",
                        "parameter": [
                            {
                                "type": "TEMPLATE",
                                "key": "arg0",
                                "value": "{{ED - is_delayed}}"
                            },
                            {
                                "type": "TEMPLATE",
                                "key": "arg1",
                                "value": "true"
                            }
                        ]
                    }
                ],
                "fingerprint": "1791000829716"
            }
        ],
        "variable": [
            {
                "accountId": "6374306328",
                "containerId": "262778781",
                "variableId": "8",
                "name": "Client IP Cloudflare",
                "type": "rh",
                "parameter": [
                    {
                        "type": "TEMPLATE",
                        "key": "headerName",
                        "value": "Cf-Connecting-Ip"
                    }
                ],
                "fingerprint": "1788192494720",
                "formatValue": {}
            },
            {
                "accountId": "6374306328",
                "containerId": "262778781",
                "variableId": "9",
                "name": "ED - cod_hold",
                "type": "ed",
                "parameter": [
                    {
                        "type": "BOOLEAN",
                        "key": "setDefaultValue",
                        "value": "false"
                    },
                    {
                        "type": "TEMPLATE",
                        "key": "keyPath",
                        "value": "cod_hold"
                    }
                ],
                "fingerprint": "1791000829716",
                "formatValue": {}
            },
            {
                "accountId": "6374306328",
                "containerId": "262778781",
                "variableId": "10",
                "name": "ED - is_delayed",
                "type": "ed",
                "parameter": [
                    {
                        "type": "BOOLEAN",
                        "key": "setDefaultValue",
                        "value": "false"
                    },
                    {
                        "type": "TEMPLATE",
                        "key": "keyPath",
                        "value": "is_delayed"
                    }
                ],
                "fingerprint": "1791000829716",
                "formatValue": {}
            },
            {
                "accountId": "6374306328",
                "containerId": "262778781",
                "variableId": "11",
                "name": "PixelFly - COD Host",
                "type": "c",
                "parameter": [
                    {
                        "type": "TEMPLATE",
                        "key": "value",
                        "value": "https://YOUR-SGTM-DOMAIN"
                    }
                ],
                "fingerprint": "1791000829716",
                "formatValue": {},
                "notes": "The Hold URL on your container's PixelFly COD Power-up, without /cod/hold (e.g. https://sgtm.yourstore.com)."
            },
            {
                "accountId": "6374306328",
                "containerId": "262778781",
                "variableId": "12",
                "name": "PixelFly - COD API Key",
                "type": "c",
                "parameter": [
                    {
                        "type": "TEMPLATE",
                        "key": "value",
                        "value": "pf_live_REPLACE_ME"
                    }
                ],
                "fingerprint": "1791000829716",
                "formatValue": {},
                "notes": "Your container's API Key (pf_live_...), shown on the container page in PixelFly. Nothing is held until this and the host are filled in."
            },
            {
                "accountId": "6374306328",
                "containerId": "262778781",
                "variableId": "13",
                "name": "ED - value",
                "type": "ed",
                "parameter": [
                    {
                        "type": "BOOLEAN",
                        "key": "setDefaultValue",
                        "value": "false"
                    },
                    {
                        "type": "TEMPLATE",
                        "key": "keyPath",
                        "value": "value"
                    }
                ],
                "fingerprint": "1791000829716",
                "formatValue": {}
            },
            {
                "accountId": "6374306328",
                "containerId": "262778781",
                "variableId": "14",
                "name": "ED - currency",
                "type": "ed",
                "parameter": [
                    {
                        "type": "BOOLEAN",
                        "key": "setDefaultValue",
                        "value": "false"
                    },
                    {
                        "type": "TEMPLATE",
                        "key": "keyPath",
                        "value": "currency"
                    }
                ],
                "fingerprint": "1791000829716",
                "formatValue": {}
            },
            {
                "accountId": "6374306328",
                "containerId": "262778781",
                "variableId": "15",
                "name": "PixelFly - Google Ads Conversion ID",
                "type": "c",
                "parameter": [
                    {
                        "type": "TEMPLATE",
                        "key": "value",
                        "value": "AW-REPLACE_ME"
                    }
                ],
                "fingerprint": "1791000829716",
                "formatValue": {},
                "notes": "Google Ads conversion ID for confirmed COD orders, numbers only (from AW-123456789 use 123456789). Then un-pause \"Google Ads Conversion (COD confirmed)\"."
            },
            {
                "accountId": "6374306328",
                "containerId": "262778781",
                "variableId": "16",
                "name": "PixelFly - Google Ads Conversion Label",
                "type": "c",
                "parameter": [
                    {
                        "type": "TEMPLATE",
                        "key": "value",
                        "value": "REPLACE_ME"
                    }
                ],
                "fingerprint": "1791000829716",
                "formatValue": {},
                "notes": "The conversion label of your Google Ads Purchase conversion action."
            }
        ],
        "builtInVariable": [
            {
                "accountId": "6374306328",
                "containerId": "262778781",
                "type": "EVENT_NAME",
                "name": "Event Name"
            },
            {
                "accountId": "6374306328",
                "containerId": "262778781",
                "type": "CLIENT_NAME",
                "name": "Client Name"
            }
        ],
        "fingerprint": "1790836663566",
        "tagManagerUrl": "https://tagmanager.google.com/#/versions/accounts/6374306328/containers/262778781/versions/0?apiLink=version",
        "customTemplate": [
            {
                "accountId": "6374306328",
                "containerId": "262778781",
                "templateId": "4",
                "name": "TikTok Events API",
                "fingerprint": "1789878700973",
                "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_K8M24\",\n  \"version\": 1,\n  \"displayName\": \"TikTok Events API\",\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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HABASjIOACAlGQcAkJKMAwBIScYBAKQk4wAAUpJxAAApyTgAgJRkHABASjIOACAlGQcAkJKMAwBIScYBAKQk4wAAUpJxAAApyTgAgJRkHABASjIOACAlGQcAkJKMAwBIScYBAKQk4wAAUpJxAAApyTgAgJRkHABASjIOACAlGQcAkJKMAwBIScYBAKQk4wAAUpJxAAApyTgAgJRkHABASjIOACAlGQcAkJKMAwBIScYBAKQk4wAAUpJxAAApyTgAgJRkHABASjIOACAlGQcAkJKMAwBIScYBAKQk4wAAUpJxAAApyTgAgJRkHABASjIOACAlGQcAkJKMAwBIScYBAKQk4wAAUpJxAAApyTgAgJRkHABASjIOACAlGQcAkJKMAwBIScYBAKQk4wAAUpJxAAApyTgAgJRkHABASjIOACAlGQcAkJKMAwBIScYBAKQk4wAAUpJxAAApyTgAgJRkHABASjIOACAlGQcAkJKMAwBIScYBAKQk4wAAUpJxAAApyTgAgJRkHABASjIOACAlGQcAkJKMAwBIScYBAKQk4wAAUpJxAAApyTgAgJRkHABASjIOACAlGQcAkJKMAwBIScYBAKQk4wAAUpJxAAApyTgAgJRkHABASjIOACClV86fP181AwDA7lIUxf8A/d26PBdp9woAAAAASUVORK5CYII\\u003d\"\n  },\n  \"description\": \"Tag that send the event data from the GA4 Client or Data Client to TikTok Events API.\",\n  \"containerContexts\": [\n    \"SERVER\"\n  ]\n}\n\n\n___TEMPLATE_PARAMETERS___\n\n[\n  {\n    \"type\": \"GROUP\",\n    \"name\": \"baseConfigGroup\",\n    \"subParams\": [\n      {\n        \"type\": \"RADIO\",\n        \"name\": \"eventType\",\n        \"displayName\": \"Event Name Setup Method\",\n        \"radioItems\": [\n          {\n            \"value\": \"standard\",\n            \"displayValue\": \"Standard\",\n            \"subParams\": [\n              {\n                \"type\": \"SELECT\",\n                \"name\": \"eventName\",\n                \"macrosInSelect\": false,\n                \"selectItems\": [\n                  {\n                    \"value\": \"AddPaymentInfo\",\n                    \"displayValue\": \"Add Payment Info\"\n                  },\n                  {\n                    \"value\": \"AddToCart\",\n                    \"displayValue\": \"Add to Cart\"\n                  },\n                  {\n                    \"value\": \"AddToWishlist\",\n                    \"displayValue\": \"Add to Wishlist\"\n                  },\n                  {\n                    \"value\": \"ApplicationApproval\",\n                    \"displayValue\": \"Application Approval\"\n                  },\n                  {\n                    \"value\": \"CompleteRegistration\",\n                    \"displayValue\": \"Complete Registration\"\n                  },\n                  {\n                    \"value\": \"Contact\",\n                    \"displayValue\": \"Contact\"\n                  },\n                  {\n                    \"value\": \"CustomizeProduct\",\n                    \"displayValue\": \"Customize Product\"\n                  },\n                  {\n                    \"value\": \"Download\",\n                    \"displayValue\": \"Download\"\n                  },\n                  {\n                    \"value\": \"FindLocation\",\n                    \"displayValue\": \"Find Location\"\n                  },\n                  {\n                    \"value\": \"InitiateCheckout\",\n                    \"displayValue\": \"Initiate Checkout\"\n                  },\n                  {\n                    \"value\": \"Lead\",\n                    \"displayValue\": \"Lead\"\n                  },\n                  {\n                    \"value\": \"Pageview\",\n                    \"displayValue\": \"Page View\"\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\": \"Start Trial\"\n                  },\n                  {\n                    \"value\": \"SubmitApplication\",\n                    \"displayValue\": \"Submit Application\"\n                  },\n                  {\n                    \"value\": \"Subscribe\",\n                    \"displayValue\": \"Subscribe\"\n                  },\n                  {\n                    \"value\": \"ViewContent\",\n                    \"displayValue\": \"View Content\"\n                  },\n                  {\n                    \"value\": \"CompletePayment\",\n                    \"displayValue\": \"Complete Payment (legacy - Use Purchase instead)\"\n                  },\n                  {\n                    \"value\": \"SubmitForm\",\n                    \"displayValue\": \"Submit Form (legacy - Use Lead instead)\"\n                  },\n                  {\n                    \"value\": \"ClickButton\",\n                    \"displayValue\": \"Click Button (deprecated)\"\n                  },\n                  {\n                    \"value\": \"PlaceAnOrder\",\n                    \"displayValue\": \"Place an Order (deprecated)\"\n                  }\n                ],\n                \"simpleValueType\": true,\n                \"alwaysInSummary\": true,\n                \"valueValidators\": [\n                  {\n                    \"type\": \"NON_EMPTY\"\n                  }\n                ],\n                \"displayName\": \"Event Name\",\n                \"defaultValue\": \"Pageview\"\n              }\n            ]\n          },\n          {\n            \"value\": \"inherit\",\n            \"subParams\": [],\n            \"displayValue\": \"Inherit from client\"\n          },\n          {\n            \"value\": \"custom\",\n            \"subParams\": [\n              {\n                \"type\": \"TEXT\",\n                \"name\": \"eventNameCustom\",\n                \"displayName\": \"\",\n                \"simpleValueType\": true\n              }\n            ],\n            \"displayValue\": \"Custom\"\n          }\n        ],\n        \"simpleValueType\": true,\n        \"defaultValue\": \"standard\"\n      },\n      {\n        \"type\": \"SELECT\",\n        \"name\": \"eventSource\",\n        \"displayName\": \"Event Source\",\n        \"selectItems\": [\n          {\n            \"value\": \"web\",\n            \"displayValue\": \"Web\"\n          },\n          {\n            \"value\": \"app\",\n            \"displayValue\": \"App\"\n          },\n          {\n            \"value\": \"offline\",\n            \"displayValue\": \"Offline\"\n          },\n          {\n            \"value\": \"crm\",\n            \"displayValue\": \"CRM\"\n          }\n        ],\n        \"simpleValueType\": true,\n        \"defaultValue\": \"web\"\n      },\n      {\n        \"type\": \"TEXT\",\n        \"name\": \"accessToken\",\n        \"displayName\": \"Access Token\",\n        \"simpleValueType\": true,\n        \"help\": \"Set to your TikTok API Access Token. More info on how to get it can be found \\u003ca href\\u003d\\\"https://ads.tiktok.com/marketing_api/docs?rid\\u003d959icq5stjr\\u0026id\\u003d1701890979375106\\\" target\\u003d\\\"_blank\\\"\\u003ehere\\u003c/a\\u003e.\",\n        \"valueValidators\": [\n          {\n            \"type\": \"NON_EMPTY\"\n          }\n        ]\n      },\n      {\n        \"type\": \"TEXT\",\n        \"name\": \"pixelId\",\n        \"displayName\": \"TikTok Pixel ID / Offline Event Set ID / TikTok App ID / CRM Event Set ID\",\n        \"simpleValueType\": true,\n        \"valueValidators\": [\n          {\n            \"type\": \"NON_EMPTY\"\n          }\n        ],\n        \"help\": \"For \\u003cb\\u003eWeb events\\u003c/b\\u003e, enter a valid \\u003cb\\u003eTikTok Pixel ID\\u003c/b\\u003e. Only one TikTok Pixel ID can be used per tag.\\n\\u003cbr\\u003e\\nFor \\u003cb\\u003eOffline events\\u003c/b\\u003e, provide the \\u003cb\\u003eOffline Event Set ID\\u003c/b\\u003e. Only one Offline Event Set ID can be used per tag.\\n\\u003cbr\\u003e\\nFor \\u003cb\\u003eApp events\\u003c/b\\u003e, enter the \\u003cb\\u003eTikTok App ID\\u003c/b\\u003e. Only one TikTok App ID can be used per tag.\\n\\u003cbr\\u003e\\nFor \\u003cb\\u003eCRM events\\u003c/b\\u003e, enter the \\u003cb\\u003eCRM Event Set ID\\u003c/b\\u003e. Only one CRM Event Set ID can be used per tag.\"\n      },\n      {\n        \"type\": \"TEXT\",\n        \"name\": \"appId\",\n        \"displayName\": \"Mobile App ID\",\n        \"simpleValueType\": true,\n        \"enablingConditions\": [\n          {\n            \"paramName\": \"eventSource\",\n            \"paramValue\": \"app\",\n            \"type\": \"EQUALS\"\n          }\n        ],\n        \"valueValidators\": [\n          {\n            \"type\": \"NON_EMPTY\"\n          }\n        ],\n        \"help\": \"\\u003ca href\\u003d\\\"https://business-api.tiktok.com/portal/docs?id\\u003d1771101151059969#item-link-app%20parameters\\\"\\u003eLearn more\\u003c/a\\u003e.\"\n      },\n      {\n        \"type\": \"TEXT\",\n        \"name\": \"leadId\",\n        \"displayName\": \"Lead ID\",\n        \"simpleValueType\": true,\n        \"help\": \"\\u003ca href\\u003d\\\"https://business-api.tiktok.com/portal/docs?id\\u003d1835052338764993#item-link-lead%20parameters\\\"\\u003eLearn more\\u003c/a\\u003e.\",\n        \"enablingConditions\": [\n          {\n            \"paramName\": \"eventSource\",\n            \"paramValue\": \"crm\",\n            \"type\": \"EQUALS\"\n          }\n        ],\n        \"valueValidators\": [\n          {\n            \"type\": \"NON_EMPTY\"\n          }\n        ]\n      },\n      {\n        \"type\": \"TEXT\",\n        \"name\": \"testEventCode\",\n        \"displayName\": \"Test Event Code\",\n        \"simpleValueType\": true,\n        \"help\": \"If you want to test event tracking, you can use this field to specify a test code. If the event is received on TikTok side, this test code will display in the Test Events tab of the Pixel in TikTok Ads Manager.\"\n      },\n      {\n        \"type\": \"CHECKBOX\",\n        \"name\": \"generateTtp\",\n        \"checkboxText\": \"Generate Browser ID (_ttp) cookie if not exist\",\n        \"simpleValueType\": true\n      },\n      {\n        \"type\": \"CHECKBOX\",\n        \"name\": \"enableEventEnhancement\",\n        \"checkboxText\": \"Enable Event Enhancement\",\n        \"simpleValueType\": true,\n        \"help\": \"Enable Use of HTTP Only Secure Cookie (\\u003ci\\u003egtmeec-tt\\u003c/i\\u003e) to Enhance Event Data.\",\n        \"defaultValue\": true\n      },\n      {\n        \"type\": \"CHECKBOX\",\n        \"name\": \"overrideCookiesSettings\",\n        \"checkboxText\": \"Override Cookies Settings\",\n        \"simpleValueType\": true,\n        \"help\": \"If enabled, it will override the listed settings for the \\u003ci\\u003e_gtmeec-tt\\u003c/i\\u003e, \\u003ci\\u003ettclid\\u003c/i\\u003e and \\u003ci\\u003e_ttp\\u003c/i\\u003e cookies.\",\n        \"subParams\": [\n          {\n            \"type\": \"GROUP\",\n            \"name\": \"cookieSettingsGroup\",\n            \"displayName\": \"Cookies Settings\",\n            \"groupStyle\": \"ZIPPY_OPEN_ON_PARAM\",\n            \"subParams\": [\n              {\n                \"type\": \"TEXT\",\n                \"name\": \"cookieDomain\",\n                \"displayName\": \"Cookie Domain\",\n                \"simpleValueType\": true,\n                \"help\": \"Use this option to override the cookie domain. \\u003cbr\\u003e Enter your website\\u0027s top-level domain as a fixed value (e.g., example.com). \\u003cbr\\u003e If left empty or using the \\\"auto\\\" value, the domain will be automatically determined using the following priority: \\u003cul\\u003e \\u003cli\\u003eDomain of the \\u003ci\\u003epage_location\\u003c/i\\u003e Event Data parameter (if present).\\u003c/li\\u003e \\u003cli\\u003eDomain of the \\u003ci\\u003eReferer\\u003c/i\\u003e header (if present).\\u003c/li\\u003e \\u003cli\\u003eDomain of the \\u003ci\\u003eForwarded\\u003c/i\\u003e header (if present).\\u003c/li\\u003e \\u003cli\\u003eDomain of the \\u003ci\\u003eX-Forwarded-Host\\u003c/i\\u003e header (if present).\\u003c/li\\u003e \\u003cli\\u003eDomain of the \\u003ci\\u003eHost\\u003c/i\\u003e header.\\u003c/li\\u003e \\u003c/ul\\u003e\",\n                \"valueHint\": \"example.com\",\n                \"defaultValue\": \"auto\"\n              },\n              {\n                \"type\": \"SELECT\",\n                \"name\": \"cookieSameSite\",\n                \"displayName\": \"Cookie SameSite\",\n                \"macrosInSelect\": true,\n                \"selectItems\": [\n                  {\n                    \"value\": \"none\",\n                    \"displayValue\": \"None\"\n                  },\n                  {\n                    \"value\": \"lax\",\n                    \"displayValue\": \"Lax\"\n                  },\n                  {\n                    \"value\": \"strict\",\n                    \"displayValue\": \"Strict\"\n                  }\n                ],\n                \"simpleValueType\": true,\n                \"defaultValue\": \"none\",\n                \"help\": \"\\u003ca href\\u003d\\\"https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Set-Cookie#samesitesamesite-value\\\"\\u003eLearn more\\u003c/a\\u003e.\"\n              }\n            ],\n            \"enablingConditions\": [\n              {\n                \"paramName\": \"overrideCookiesSettings\",\n                \"paramValue\": true,\n                \"type\": \"EQUALS\"\n              }\n            ]\n          }\n        ]\n      },\n      {\n        \"type\": \"CHECKBOX\",\n        \"name\": \"useOptimisticScenario\",\n        \"checkboxText\": \"Use Optimistic Scenario\",\n        \"simpleValueType\": true,\n        \"help\": \"The tag will call gtmOnSuccess() without waiting for a response from the API\"\n      }\n    ]\n  },\n  {\n    \"displayName\": \"Common Event Data Override\",\n    \"name\": \"commonEventDataListGroup\",\n    \"groupStyle\": \"ZIPPY_CLOSED\",\n    \"type\": \"GROUP\",\n    \"subParams\": [\n      {\n        \"type\": \"CHECKBOX\",\n        \"name\": \"autoMapCommonEventData\",\n        \"checkboxText\": \"Automap Common Event Data\",\n        \"simpleValueType\": true,\n        \"help\": \"If enabled, the tag will attempt to automatically map parameters from your event data.\\n\\u003cbr/\\u003e\\u003cbr/\\u003e\\nAny value you manually enter in a field below will always override the auto-mapped value.\\n\\u003cbr/\\u003e\\u003cbr/\\u003e\\nDefault mappings:\\n\\u003cul\\u003e\\n\\u003cli\\u003e\\u003cb\\u003eEvent Time:\\u003c/b\\u003e \\u003ci\\u003eeventData.event_time\\u003c/i\\u003e, current timestamp\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003cb\\u003eEvent ID:\\u003c/b\\u003e \\u003ci\\u003eeventData.event_id\\u003c/i\\u003e, \\u003ci\\u003eeventData.transaction_id\\u003c/i\\u003e\\u003c/li\\u003e\\n\\u003c/ul\\u003e\",\n        \"defaultValue\": true\n      },\n      {\n        \"type\": \"TEXT\",\n        \"name\": \"eventId\",\n        \"displayName\": \"Event ID\",\n        \"simpleValueType\": true,\n        \"help\": \"\\u003ca href\\u003d\\\"https://business-api.tiktok.com/portal/docs?id\\u003d1771101151059969#item-link-Top-level%20Parameters\\\"\\u003eLearn more\\u003c/a\\u003e.\"\n      },\n      {\n        \"type\": \"TEXT\",\n        \"name\": \"eventTime\",\n        \"displayName\": \"Event Time\",\n        \"simpleValueType\": true,\n        \"help\": \"The time when the event occurred, indicated as a Unix timestamp measured in seconds, and in UTC+0 time zone.\"\n      },\n      {\n        \"type\": \"CHECKBOX\",\n        \"name\": \"limitedDataUse\",\n        \"checkboxText\": \"Limited Data Use\",\n        \"simpleValueType\": true,\n        \"help\": \"To learn more about the Limited Data Use feature, refer to \\u003ca href\\u003d\\\"https://ads.tiktok.com/marketing_api/docs?id\\u003d1771101204435970\\\" target\\u003d\\\"_blank\\\"\\u003eEvents API 2.0 - Limited Data Use\\u003c/a\\u003e.\",\n        \"defaultValue\": false\n      }\n    ]\n  },\n  {\n    \"type\": \"GROUP\",\n    \"name\": \"pageDataGroup\",\n    \"displayName\": \"Page Data\",\n    \"groupStyle\": \"ZIPPY_CLOSED\",\n    \"subParams\": [\n      {\n        \"type\": \"CHECKBOX\",\n        \"name\": \"autoMapPageData\",\n        \"checkboxText\": \"Automap Page Data\",\n        \"simpleValueType\": true,\n        \"help\": \"If enabled, the tag will attempt to automatically map parameters from your event data.\\n\\u003cbr/\\u003e\\u003cbr/\\u003e\\nAny value you manually enter in a field below will always override the auto-mapped value.\\n\\u003cbr/\\u003e\\u003cbr/\\u003e\\nDefault mappings:\\n\\u003cul\\u003e\\n\\u003cli\\u003e\\u003cb\\u003ePage Location:\\u003c/b\\u003e \\u003ci\\u003eeventData.page_location\\u003c/i\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003cb\\u003ePage Referrer:\\u003c/b\\u003e \\u003ci\\u003eeventData.page_referrer\\u003c/i\\u003e, \\u003ci\\u003eeventData.referrer\\u003c/i\\u003e\\u003c/li\\u003e\\n\\u003c/ul\\u003e\",\n        \"defaultValue\": true\n      },\n      {\n        \"type\": \"TEXT\",\n        \"name\": \"pageLocation\",\n        \"displayName\": \"Page Location\",\n        \"simpleValueType\": true\n      },\n      {\n        \"type\": \"TEXT\",\n        \"name\": \"pageReferrer\",\n        \"displayName\": \"Page Referrer\",\n        \"simpleValueType\": true\n      }\n    ],\n    \"enablingConditions\": [\n      {\n        \"paramName\": \"eventSource\",\n        \"paramValue\": \"web\",\n        \"type\": \"EQUALS\"\n      }\n    ]\n  },\n  {\n    \"type\": \"GROUP\",\n    \"name\": \"appDataGroup\",\n    \"displayName\": \"App Data\",\n    \"groupStyle\": \"ZIPPY_CLOSED\",\n    \"subParams\": [\n      {\n        \"type\": \"CHECKBOX\",\n        \"name\": \"autoMapAppData\",\n        \"checkboxText\": \"Automap App Data\",\n        \"simpleValueType\": true,\n        \"help\": \"If enabled, the tag will attempt to automatically map parameters from your event data.\\n\\u003cbr/\\u003e\\u003cbr/\\u003e\\nAny value you manually enter in a field below will always override the auto-mapped value.\\n\\u003cbr/\\u003e\\u003cbr/\\u003e\\nDefault mappings:\\n\\u003cul\\u003e\\n\\u003cli\\u003e\\u003cb\\u003eApplication Name:\\u003c/b\\u003e \\u003ci\\u003eeventData.app_name\\u003c/i\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003cb\\u003eApp Version Number:\\u003c/b\\u003e \\u003ci\\u003eeventData.app_version\\u003c/i\\u003e\\u003c/li\\u003e\\n\\u003c/ul\\u003e\",\n        \"defaultValue\": true\n      },\n      {\n        \"type\": \"TEXT\",\n        \"name\": \"appName\",\n        \"displayName\": \"Application name\",\n        \"simpleValueType\": true,\n        \"help\": \"\\u003ca href\\u003d\\\"https://business-api.tiktok.com/portal/docs?id\\u003d1771101151059969#item-link-app%20parameters\\\"\\u003eLearn more\\u003c/a\\u003e.\"\n      },\n      {\n        \"type\": \"TEXT\",\n        \"name\": \"appVersion\",\n        \"displayName\": \"App version number\",\n        \"simpleValueType\": true,\n        \"help\": \"\\u003ca href\\u003d\\\"https://business-api.tiktok.com/portal/docs?id\\u003d1771101151059969#item-link-app%20parameters\\\"\\u003eLearn more\\u003c/a\\u003e.\"\n      }\n    ],\n    \"enablingConditions\": [\n      {\n        \"paramName\": \"eventSource\",\n        \"paramValue\": \"app\",\n        \"type\": \"EQUALS\"\n      }\n    ]\n  },\n  {\n    \"displayName\": \"Ad Data\",\n    \"name\": \"adDataGroup\",\n    \"groupStyle\": \"ZIPPY_CLOSED\",\n    \"type\": \"GROUP\",\n    \"subParams\": [\n      {\n        \"type\": \"LABEL\",\n        \"name\": \"adDataGroupLabel\",\n        \"displayName\": \"See \\u003ca href\\u003d\\\"https://business-api.tiktok.com/portal/docs?id\\u003d1771101151059969\\\"\\u003ethis documentation\\u003c/a\\u003e for more details on Ad Data properties.\\u003cbr/\\u003e\\u003cbr/\\u003e\"\n      },\n      {\n        \"type\": \"CHECKBOX\",\n        \"name\": \"autoMapAdData\",\n        \"checkboxText\": \"Automap Ad Data\",\n        \"simpleValueType\": true,\n        \"help\": \"If enabled, the tag will attempt to automatically map parameters from your event data.\\n\\u003cbr/\\u003e\\u003cbr/\\u003e\\nAny value you manually enter in the table below will always override the auto-mapped value.\\n\\u003cbr/\\u003e\\u003cbr/\\u003e\\nDefault mappings:\\n\\u003cul\\u003e\\n\\u003cli\\u003e\\u003cb\\u003eCallback:\\u003c/b\\u003e \\u003ci\\u003eeventData.ad.callback\\u003c/i\\u003e, \\u003ci\\u003eeventData.callback\\u003c/i\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003cb\\u003eCampaign ID:\\u003c/b\\u003e \\u003ci\\u003eeventData.ad.campaign_id\\u003c/i\\u003e, \\u003ci\\u003eeventData.campaign_id\\u003c/i\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003cb\\u003eAd ID:\\u003c/b\\u003e \\u003ci\\u003eeventData.ad.ad_id\\u003c/i\\u003e, \\u003ci\\u003eeventData.ad_id\\u003c/i\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003cb\\u003eCreative ID:\\u003c/b\\u003e \\u003ci\\u003eeventData.ad.creative_id\\u003c/i\\u003e, \\u003ci\\u003eeventData.creative_id\\u003c/i\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003cb\\u003eIs Retargeting:\\u003c/b\\u003e \\u003ci\\u003eeventData.ad.is_retargeting\\u003c/i\\u003e, \\u003ci\\u003eeventData.is_retargeting\\u003c/i\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003cb\\u003eAttributed:\\u003c/b\\u003e \\u003ci\\u003eeventData.ad.attributed\\u003c/i\\u003e, \\u003ci\\u003eeventData.attributed\\u003c/i\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003cb\\u003eAttribution Type:\\u003c/b\\u003e \\u003ci\\u003eeventData.ad.attribution_type\\u003c/i\\u003e, \\u003ci\\u003eeventData.attribution_type\\u003c/i\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003cb\\u003eAttribution Provider:\\u003c/b\\u003e \\u003ci\\u003eeventData.ad.attribution_provider\\u003c/i\\u003e, \\u003ci\\u003eeventData.attribution_provider\\u003c/i\\u003e\\u003c/li\\u003e\\n\\u003c/ul\\u003e\",\n        \"defaultValue\": true\n      },\n      {\n        \"name\": \"adDataList\",\n        \"simpleTableColumns\": [\n          {\n            \"valueValidators\": [\n              {\n                \"type\": \"NON_EMPTY\"\n              }\n            ],\n            \"defaultValue\": \"ad_id\",\n            \"displayName\": \"Property Name\",\n            \"name\": \"name\",\n            \"isUnique\": true,\n            \"type\": \"SELECT\",\n            \"selectItems\": [\n              {\n                \"value\": \"callback\",\n                \"displayValue\": \"Callback\"\n              },\n              {\n                \"value\": \"campaign_id\",\n                \"displayValue\": \"Campaign ID\"\n              },\n              {\n                \"value\": \"ad_id\",\n                \"displayValue\": \"Ad ID\"\n              },\n              {\n                \"value\": \"creative_id\",\n                \"displayValue\": \"Creative ID\"\n              },\n              {\n                \"value\": \"is_retargeting\",\n                \"displayValue\": \"Is Retargeting\"\n              },\n              {\n                \"value\": \"attributed\",\n                \"displayValue\": \"Attributed\"\n              },\n              {\n                \"value\": \"attribution_type\",\n                \"displayValue\": \"Attribution Type\"\n              },\n              {\n                \"value\": \"attribution_provider\",\n                \"displayValue\": \"Attribution Provider\"\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\": \"eventSource\",\n        \"paramValue\": \"app\",\n        \"type\": \"EQUALS\"\n      }\n    ]\n  },\n  {\n    \"type\": \"GROUP\",\n    \"name\": \"leadDataGroup\",\n    \"displayName\": \"Lead Data\",\n    \"groupStyle\": \"ZIPPY_CLOSED\",\n    \"subParams\": [\n      {\n        \"type\": \"TEXT\",\n        \"name\": \"leadEventSource\",\n        \"displayName\": \"Lead Event Source\",\n        \"simpleValueType\": true,\n        \"help\": \"\\u003ca href\\u003d\\\"https://business-api.tiktok.com/portal/docs?id\\u003d1835052338764993#item-link-lead%20parameters\\\"\\u003eLearn more\\u003c/a\\u003e.\"\n      }\n    ],\n    \"enablingConditions\": [\n      {\n        \"paramName\": \"eventSource\",\n        \"paramValue\": \"crm\",\n        \"type\": \"EQUALS\"\n      }\n    ]\n  },\n  {\n    \"displayName\": \"User Data\",\n    \"name\": \"userDataGroup\",\n    \"groupStyle\": \"ZIPPY_CLOSED\",\n    \"type\": \"GROUP\",\n    \"subParams\": [\n      {\n        \"type\": \"LABEL\",\n        \"name\": \"userDataGroupLabel\",\n        \"displayName\": \"See \\u003ca href\\u003d\\\"https://business-api.tiktok.com/portal/docs?id\\u003d1771101151059969\\\"\\u003ethis documentation\\u003c/a\\u003e for more details on User Data properties. If the documentation requires the parameter to be hashed, you \\u003cb\\u003emust\\u003c/b\\u003e hash it with SHA256, or the tag will do this automatically before sending the event to TikTok.\\u003cbr/\\u003e\\u003cbr/\\u003e\"\n      },\n      {\n        \"type\": \"CHECKBOX\",\n        \"name\": \"autoMapUserData\",\n        \"checkboxText\": \"Automap User Data\",\n        \"simpleValueType\": true,\n        \"help\": \"If enabled, the tag will attempt to automatically map parameters from your event data.\\n\\u003cbr/\\u003e\\u003cbr/\\u003e\\nAny value you manually enter in the table below will always override the auto-mapped value.\\n\\u003cbr/\\u003e\\u003cbr/\\u003e\\nDefault mappings:\\n\\u003cul\\u003e\\n\\u003cli\\u003e\\u003cb\\u003eEmail:\\u003c/b\\u003e \\u003ci\\u003eeventData.email\\u003c/i\\u003e, \\u003ci\\u003eeventData.email_address\\u003c/i\\u003e, \\u003ci\\u003eeventData.user_data.email\\u003c/i\\u003e, \\u003ci\\u003eeventData.user_data.email_address\\u003c/i\\u003e, \\u003ci\\u003eeventData.user_data.sha256_email_address\\u003c/i\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003cb\\u003ePhone:\\u003c/b\\u003e \\u003ci\\u003eeventData.phone\\u003c/i\\u003e, \\u003ci\\u003eeventData.phone_number\\u003c/i\\u003e, \\u003ci\\u003eeventData.user_data.phone\\u003c/i\\u003e, \\u003ci\\u003eeventData.user_data.phone_number\\u003c/i\\u003e, \\u003ci\\u003eeventData.user_data.sha256_phone_number\\u003c/i\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003cb\\u003eFirst Name:\\u003c/b\\u003e \\u003ci\\u003eeventData.first_name\\u003c/i\\u003e, \\u003ci\\u003eeventData.firstName\\u003c/i\\u003e, \\u003ci\\u003eeventData.nameFirst\\u003c/i\\u003e, \\u003ci\\u003eeventData.user_data.first_name\\u003c/i\\u003e, \\u003ci\\u003eeventData.user_data.address[].first_name\\u003c/i\\u003e, \\u003ci\\u003eeventData.user_data.address[].sha256_first_name\\u003c/i\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003cb\\u003eLast Name:\\u003c/b\\u003e \\u003ci\\u003eeventData.last_name\\u003c/i\\u003e, \\u003ci\\u003eeventData.lastName\\u003c/i\\u003e, \\u003ci\\u003eeventData.nameLast\\u003c/i\\u003e, \\u003ci\\u003eeventData.user_data.last_name\\u003c/i\\u003e, \\u003ci\\u003eeventData.user_data.address[].last_name\\u003c/i\\u003e, \\u003ci\\u003eeventData.user_data.address[].sha256_last_name\\u003c/i\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003cb\\u003eCity:\\u003c/b\\u003e \\u003ci\\u003eeventData.city\\u003c/i\\u003e, \\u003ci\\u003eeventData.user_data.address[].city\\u003c/i\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003cb\\u003eState:\\u003c/b\\u003e \\u003ci\\u003eeventData.state\\u003c/i\\u003e, \\u003ci\\u003eeventData.region\\u003c/i\\u003e, \\u003ci\\u003eeventData.user_data.region\\u003c/i\\u003e, \\u003ci\\u003eeventData.user_data.address[].region\\u003c/i\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003cb\\u003eZip Code:\\u003c/b\\u003e \\u003ci\\u003eeventData.zip\\u003c/i\\u003e, \\u003ci\\u003eeventData.postal_code\\u003c/i\\u003e, \\u003ci\\u003eeventData.user_data.postal_code\\u003c/i\\u003e, \\u003ci\\u003eeventData.user_data.address[].postal_code\\u003c/i\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003cb\\u003eCountry:\\u003c/b\\u003e \\u003ci\\u003eeventData.countryCode\\u003c/i\\u003e, \\u003ci\\u003eeventData.country\\u003c/i\\u003e, \\u003ci\\u003eeventData.user_data.country\\u003c/i\\u003e, \\u003ci\\u003eeventData.user_data.address[].country\\u003c/i\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003cb\\u003eClick ID (ttclid):\\u003c/b\\u003e \\u003ci\\u003ettclid URL parameter\\u003c/i\\u003e, \\u003ci\\u003ettclid cookie\\u003c/i\\u003e, \\u003ci\\u003eeventData.common_cookie.ttclid\\u003c/i\\u003e, \\u003ci\\u003eeventData.ttclid\\u003c/i\\u003e, \\u003ci\\u003eeventData.user_data.ttclid\\u003c/i\\u003e (web only)\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003cb\\u003eBrowser ID (ttp):\\u003c/b\\u003e \\u003ci\\u003e_ttp cookie\\u003c/i\\u003e, \\u003ci\\u003eeventData.common_cookie._ttp\\u003c/i\\u003e, \\u003ci\\u003eeventData._ttp\\u003c/i\\u003e, \\u003ci\\u003eeventData.ttp\\u003c/i\\u003e, \\u003ci\\u003eeventData.user_data.ttp\\u003c/i\\u003e, or generated if \\\"Generate _ttp\\\" is enabled (web only)\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003cb\\u003eExternal ID:\\u003c/b\\u003e \\u003ci\\u003eeventData.external_id\\u003c/i\\u003e, \\u003ci\\u003eeventData.user_id\\u003c/i\\u003e, \\u003ci\\u003eeventData.userId\\u003c/i\\u003e, \\u003ci\\u003eeventData.user_data.external_id\\u003c/i\\u003e (web and crm)\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003cb\\u003eIP Address:\\u003c/b\\u003e \\u003ci\\u003eeventData.ip_override\\u003c/i\\u003e, \\u003ci\\u003eeventData.ip_address\\u003c/i\\u003e, \\u003ci\\u003eeventData.ip\\u003c/i\\u003e (web and app)\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003cb\\u003eUser Agent:\\u003c/b\\u003e \\u003ci\\u003eeventData.user_agent\\u003c/i\\u003e (web and app)\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003cb\\u003eLocale:\\u003c/b\\u003e \\u003ci\\u003eeventData.locale\\u003c/i\\u003e, \\u003ci\\u003eeventData.user_data.locale\\u003c/i\\u003e (web and app)\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003cb\\u003eIDFA:\\u003c/b\\u003e \\u003ci\\u003eeventData.idfa\\u003c/i\\u003e, \\u003ci\\u003eeventData[\\u0027x-ga-resettable_device_id\\u0027]\\u003c/i\\u003e (iOS), \\u003ci\\u003eeventData.user_data.idfa\\u003c/i\\u003e — null UUIDs are ignored (app only)\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003cb\\u003eIDFV:\\u003c/b\\u003e \\u003ci\\u003eeventData.idfv\\u003c/i\\u003e, \\u003ci\\u003eeventData[\\u0027x-ga-vendor_device_id\\u0027]\\u003c/i\\u003e (iOS), \\u003ci\\u003eeventData.user_data.idfv\\u003c/i\\u003e — null UUIDs are ignored (app only)\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003cb\\u003eGAID:\\u003c/b\\u003e \\u003ci\\u003eeventData.gaid\\u003c/i\\u003e, \\u003ci\\u003eeventData[\\u0027x-ga-resettable_device_id\\u0027]\\u003c/i\\u003e (Android), \\u003ci\\u003eeventData.user_data.gaid\\u003c/i\\u003e — null UUIDs are ignored (app only)\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003cb\\u003eATT Status:\\u003c/b\\u003e \\u003ci\\u003eeventData.att_status\\u003c/i\\u003e, \\u003ci\\u003eeventData.user_data.att_status\\u003c/i\\u003e (app only)\\u003c/li\\u003e\\n\\u003c/ul\\u003e\",\n        \"defaultValue\": true\n      },\n      {\n        \"name\": \"userDataList\",\n        \"simpleTableColumns\": [\n          {\n            \"valueValidators\": [\n              {\n                \"type\": \"NON_EMPTY\"\n              }\n            ],\n            \"defaultValue\": \"email\",\n            \"displayName\": \"Property Name\",\n            \"name\": \"name\",\n            \"isUnique\": true,\n            \"type\": \"SELECT\",\n            \"selectItems\": [\n              {\n                \"value\": \"email\",\n                \"displayValue\": \"Email\"\n              },\n              {\n                \"value\": \"phone\",\n                \"displayValue\": \"Phone\"\n              },\n              {\n                \"value\": \"external_id\",\n                \"displayValue\": \"External ID\"\n              },\n              {\n                \"value\": \"ip\",\n                \"displayValue\": \"Client IP Address\"\n              },\n              {\n                \"value\": \"user_agent\",\n                \"displayValue\": \"Client User Agent\"\n              },\n              {\n                \"value\": \"ttclid\",\n                \"displayValue\": \"Click ID (ttclid)\"\n              },\n              {\n                \"value\": \"ttp\",\n                \"displayValue\": \"Browser ID (ttp)\"\n              },\n              {\n                \"value\": \"locale\",\n                \"displayValue\": \"Locale\"\n              },\n              {\n                \"value\": \"idfa\",\n                \"displayValue\": \"iOS IDFA\"\n              },\n              {\n                \"value\": \"idfv\",\n                \"displayValue\": \"iOS IDFV\"\n              },\n              {\n                \"value\": \"gaid\",\n                \"displayValue\": \"GAID (Google Advertising ID)\"\n              },\n              {\n                \"value\": \"att_status\",\n                \"displayValue\": \"ATT Status\"\n              },\n              {\n                \"value\": \"first_name\",\n                \"displayValue\": \"First Name\"\n              },\n              {\n                \"value\": \"last_name\",\n                \"displayValue\": \"Last Name\"\n              },\n              {\n                \"value\": \"city\",\n                \"displayValue\": \"City\"\n              },\n              {\n                \"value\": \"state\",\n                \"displayValue\": \"State\"\n              },\n              {\n                \"value\": \"country\",\n                \"displayValue\": \"Country\"\n              },\n              {\n                \"value\": \"zip_code\",\n                \"displayValue\": \"Zip\"\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  },\n  {\n    \"displayName\": \"Event Properties\",\n    \"name\": \"eventPropertiesGroup\",\n    \"groupStyle\": \"ZIPPY_CLOSED\",\n    \"type\": \"GROUP\",\n    \"subParams\": [\n      {\n        \"type\": \"LABEL\",\n        \"name\": \"eventPropertiesGroupLabel\",\n        \"displayName\": \"See \\u003ca href\\u003d\\\"https://business-api.tiktok.com/portal/docs?id\\u003d1771101151059969\\\"\\u003ethis documentation\\u003c/a\\u003e for more details on Event Properties.\\u003cbr/\\u003e\\u003cbr/\\u003e\"\n      },\n      {\n        \"type\": \"CHECKBOX\",\n        \"name\": \"autoMapCustomData\",\n        \"checkboxText\": \"Automap Custom Data\",\n        \"simpleValueType\": true,\n        \"help\": \"If enabled, the tag will attempt to automatically map parameters from your event data.\\n\\u003cbr/\\u003e\\u003cbr/\\u003e\\nAny value you manually enter in the table below will always override the auto-mapped value.\\n\\u003cbr/\\u003e\\u003cbr/\\u003e\\nDefault mappings:\\n\\u003cul\\u003e\\n\\u003cli\\u003e\\u003cb\\u003eValue:\\u003c/b\\u003e\\n\\u003cul\\u003e\\n\\u003cli\\u003e\\u003ci\\u003eeventData.value\\u003c/i\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003ci\\u003eeventData[\\u0027x-ga-mp1-ev\\u0027]\\u003c/i\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003ci\\u003eeventData[\\u0027x-ga-mp1-tr\\u0027]\\u003c/i\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003ci\\u003eSum of Price * Quantity from eventData.items[] or eventData.ecommerce.items[]\\u003c/i\\u003e\\u003c/li\\u003e\\n\\u003c/ul\\u003e\\n\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003cb\\u003eCurrency:\\u003c/b\\u003e\\n\\u003cul\\u003e\\n\\u003cli\\u003e\\u003ci\\u003eeventData.currency\\u003c/i\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003ci\\u003eCurrency from eventData.items[] or eventData.ecommerce.items[]\\u003c/i\\u003e\\u003c/li\\u003e\\n\\u003c/ul\\u003e\\n\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003cb\\u003eContents:\\u003c/b\\u003e\\n\\u003cul\\u003e\\n\\u003cli\\u003e\\u003ci\\u003eeventData.contents\\u003c/i\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003ci\\u003eMapped from eventData.items[] or eventData.ecommerce.items[]\\u003c/i\\u003e (each item maps: \\u003ci\\u003eitem_id / id → content_id\\u003c/i\\u003e, \\u003ci\\u003econtent_name / item_name → content_name\\u003c/i\\u003e, \\u003ci\\u003econtent_category / item_category → content_category\\u003c/i\\u003e, \\u003ci\\u003ebrand / item_brand → brand\\u003c/i\\u003e, \\u003ci\\u003equantity\\u003c/i\\u003e, \\u003ci\\u003eprice\\u003c/i\\u003e)\\u003c/li\\u003e\\n\\u003c/ul\\u003e\\n\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003cb\\u003eContent Type:\\u003c/b\\u003e \\u003ci\\u003eeventData.content_type\\u003c/i\\u003e, or \\u003ci\\u003eproduct\\u003c/i\\u003e when items are present\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003cb\\u003eQuery:\\u003c/b\\u003e \\u003ci\\u003eeventData.query\\u003c/i\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003cb\\u003eSearch String:\\u003c/b\\u003e \\u003ci\\u003eeventData.search_term\\u003c/i\\u003e, \\u003ci\\u003eeventData.search_string\\u003c/i\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003cb\\u003eDescription:\\u003c/b\\u003e \\u003ci\\u003eeventData.description\\u003c/i\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003cb\\u003eOrder ID:\\u003c/b\\u003e \\u003ci\\u003eeventData.order_id\\u003c/i\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003cb\\u003eShop ID:\\u003c/b\\u003e \\u003ci\\u003eeventData.shop_id\\u003c/i\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003cb\\u003eCustomer Type:\\u003c/b\\u003e \\u003ci\\u003eeventData.customer_type\\u003c/i\\u003e (supported values: \\u003ci\\u003enew\\u003c/i\\u003e, \\u003ci\\u003ereturning\\u003c/i\\u003e)\\u003c/li\\u003e\\n\\u003c/ul\\u003e\",\n        \"defaultValue\": true\n      },\n      {\n        \"name\": \"customDataList\",\n        \"simpleTableColumns\": [\n          {\n            \"valueValidators\": [\n              {\n                \"type\": \"NON_EMPTY\"\n              }\n            ],\n            \"defaultValue\": \"currency\",\n            \"displayName\": \"Property Name\",\n            \"name\": \"name\",\n            \"isUnique\": true,\n            \"type\": \"SELECT\",\n            \"selectItems\": [\n              {\n                \"value\": \"contents\",\n                \"displayValue\": \"Contents\"\n              },\n              {\n                \"value\": \"content_ids\",\n                \"displayValue\": \"Content IDs\"\n              },\n              {\n                \"value\": \"content_type\",\n                \"displayValue\": \"Content Type\"\n              },\n              {\n                \"value\": \"num_items\",\n                \"displayValue\": \"Number of Items\"\n              },\n              {\n                \"value\": \"currency\",\n                \"displayValue\": \"Currency\"\n              },\n              {\n                \"value\": \"value\",\n                \"displayValue\": \"Value\"\n              },\n              {\n                \"value\": \"description\",\n                \"displayValue\": \"Description\"\n              },\n              {\n                \"value\": \"search_string\",\n                \"displayValue\": \"Search String\"\n              },\n              {\n                \"value\": \"query\",\n                \"displayValue\": \"Query (legacy - use Search String instead)\"\n              },\n              {\n                \"value\": \"order_id\",\n                \"displayValue\": \"Order ID\"\n              },\n              {\n                \"value\": \"shop_id\",\n                \"displayValue\": \"Shop ID\"\n              },\n              {\n                \"value\": \"customer_type\",\n                \"displayValue\": \"Customer Type\"\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  },\n  {\n    \"displayName\": \"Additional Event Properties\",\n    \"name\": \"additionalEventPropertiesGroup\",\n    \"groupStyle\": \"ZIPPY_CLOSED\",\n    \"type\": \"GROUP\",\n    \"subParams\": [\n      {\n        \"type\": \"LABEL\",\n        \"name\": \"additionalEventPropertiesGroupLabel\",\n        \"displayName\": \"Use Additional Event Properties to send any custom property or properties specific to a vertical (Travel, Automotive etc.). \\u003cbr/\\u003e Check these documentations for more details on Additional Event Properties for \\u003ca href\\u003d\\\"https://ads.tiktok.com/help/article/available-events-and-parameters-for-travel-ads?lang\\u003den \\\"\\u003eTravel Ads\\u003c/a\\u003e, \\u003ca href\\u003d\\\"https://ads.tiktok.com/help/article/available-parameters-for-automotive-ads?lang\\u003den\\\"\\u003eAutomotive Ads\\u003c/a\\u003e and \\u003ca href\\u003d\\\"https://business-api.tiktok.com/portal/docs?id\\u003d1771101151059969\\\"\\u003eothers\\u003c/a\\u003e. \\u003cbr/\\u003e\\u003cbr/\\u003e\"\n      },\n      {\n        \"name\": \"additionalEventPropertiesList\",\n        \"simpleTableColumns\": [\n          {\n            \"valueValidators\": [\n              {\n                \"type\": \"NON_EMPTY\"\n              }\n            ],\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\": \"tagExecutionConsentSettingsGroup\",\n    \"displayName\": \"Tag Execution Consent Settings\",\n    \"groupStyle\": \"ZIPPY_CLOSED\",\n    \"subParams\": [\n      {\n        \"type\": \"RADIO\",\n        \"name\": \"adStorageConsent\",\n        \"displayName\": \"\",\n        \"radioItems\": [\n          {\n            \"value\": \"optional\",\n            \"displayValue\": \"Send data always\"\n          },\n          {\n            \"value\": \"required\",\n            \"displayValue\": \"Send data in case marketing consent given\",\n            \"help\": \"Aborts the tag execution if marketing consent (\\u003ci\\u003ead_storage\\u003c/i\\u003e Google Consent Mode or Stape\\u0027s Data Tag parameter) is not given.\"\n          }\n        ],\n        \"simpleValueType\": true,\n        \"defaultValue\": \"optional\"\n      }\n    ]\n  }\n]\n\n\n___SANDBOXED_JS_FOR_SERVER___\n\nconst computeEffectiveTldPlusOne = require('computeEffectiveTldPlusOne');\nconst decodeUriComponent = require('decodeUriComponent');\nconst fromBase64 = require('fromBase64');\nconst generateRandom = require('generateRandom');\nconst getAllEventData = require('getAllEventData');\nconst getCookieValues = require('getCookieValues');\nconst getEventData = require('getEventData');\nconst getRequestHeader = require('getRequestHeader');\nconst getTimestampMillis = require('getTimestampMillis');\nconst getType = require('getType');\nconst JSON = require('JSON');\nconst makeInteger = require('makeInteger');\nconst makeNumber = require('makeNumber');\nconst makeString = require('makeString');\nconst Math = require('Math');\nconst parseUrl = require('parseUrl');\nconst sendHttpRequest = require('sendHttpRequest');\nconst setCookie = require('setCookie');\nconst sha256Sync = require('sha256Sync');\nconst toBase64 = require('toBase64');\n\n/*==============================================================================\n==============================================================================*/\n\nconst API_VERSION = '1.3';\nconst PARTNER_AGENT_STRING = 'stape_2_1_3' + (data.enableEventEnhancement ? '_ee' : '');\n\nconst eventData = getAllEventData();\n\nif (shouldExitEarly(data, eventData)) return;\n\nconst ids = getClickAndBrowserId(data, eventData);\nconst ttclid = ids.ttclid;\nconst ttp = ids.ttp;\nsetIDsCookies(data, ttclid, ttp);\n\nconst mappedData = mapEvent(data, eventData, ttclid, ttp);\nsendRequest(data, mappedData);\n\nif (data.useOptimisticScenario) {\n  return data.gtmOnSuccess();\n}\n\n/*==============================================================================\n  Vendor related functions\n==============================================================================*/\n\nfunction getClickAndBrowserId(data, eventData) {\n  const ids = {\n    ttclid:\n      getCookieValues('ttclid')[0] || (eventData.common_cookie || {}).ttclid || eventData.ttclid,\n    ttp:\n      getCookieValues('_ttp')[0] ||\n      (eventData.common_cookie || {})._ttp ||\n      eventData._ttp ||\n      eventData.ttp\n  };\n\n  const url = getUrl(eventData);\n  if (url) {\n    const urlParsed = parseUrl(url);\n    if (urlParsed && urlParsed.searchParams.ttclid) {\n      ids.ttclid = decodeUriComponent(urlParsed.searchParams.ttclid);\n    }\n  }\n\n  if (!ids.ttp && data.generateTtp) {\n    ids.ttp = generateTtp();\n  }\n\n  return ids;\n}\n\nfunction setIDsCookies(data, ttclid, ttp) {\n  const cookieOptions = {\n    domain: getCookieDomain(data),\n    path: '/',\n    samesite: data.cookieSameSite || 'Lax',\n    secure: true,\n    httpOnly: false\n  };\n\n  if (ttclid) {\n    cookieOptions['max-age'] = 2592000; // 30 days\n    setCookie('ttclid', ttclid, cookieOptions);\n  }\n\n  if (ttp) {\n    cookieOptions['max-age'] = 34190000; // 13 months\n    setCookie('_ttp', ttp, cookieOptions);\n  }\n}\n\nfunction mapEvent(data, eventData, ttclid, ttp) {\n  const eventSource = data.eventSource || 'web';\n  let mappedData = {\n    event: getEventName(data, eventData)\n  };\n\n  const autoMapEnabled = data.hasOwnProperty('autoMapCommonEventData')\n    ? data.autoMapCommonEventData\n    : true; // To avoid a breaking change.\n\n  const eventTime =\n    data.eventTime ||\n    (autoMapEnabled ? eventData.event_time || Math.round(getTimestampMillis() / 1000) : undefined);\n  if (eventTime) mappedData.event_time = makeInteger(eventTime);\n\n  const eventId =\n    data.eventId || (autoMapEnabled ? eventData.event_id || eventData.transaction_id : undefined);\n  if (eventId) mappedData.event_id = eventId;\n\n  if (eventSource === 'web') {\n    addPageData(mappedData, eventData);\n  }\n\n  if (eventSource === 'app') {\n    addAppData(mappedData, eventData);\n  }\n\n  if (eventSource === 'web' || eventSource === 'app') {\n    mappedData.limited_data_use = data.limitedDataUse || false;\n  }\n\n  if (eventSource === 'crm') {\n    addLeadData(mappedData);\n  }\n\n  mappedData = addUserData(eventData, mappedData, eventSource, ttclid, ttp);\n  mappedData = addPropertiesData(eventData, mappedData);\n  mappedData = hashDataIfNeeded(mappedData);\n\n  if (data.enableEventEnhancement) {\n    mappedData.user = enhanceEventData(mappedData.user, eventData);\n    setGtmEecCookie(mappedData.user);\n  }\n\n  const requestData = {\n    event_source: eventSource,\n    event_source_id: data.pixelId,\n    data: [mappedData]\n  };\n  const testEventCode = eventData.test_event_code || data.testEventCode;\n  if (testEventCode) requestData.test_event_code = testEventCode;\n\n  return requestData;\n}\n\nfunction hashData(value) {\n  if (!value) {\n    return value;\n  }\n\n  const type = getType(value);\n\n  if (type === 'undefined' || value === 'undefined') {\n    return undefined;\n  }\n\n  if (type === 'array') {\n    return value.map((val) => {\n      return hashData(val);\n    });\n  }\n\n  if (isHashed(value)) {\n    return value;\n  }\n\n  return sha256Sync(makeString(value).trim().toLowerCase(), {\n    outputEncoding: 'hex'\n  });\n}\n\nfunction hashDataIfNeeded(mappedData) {\n  if (mappedData.user) {\n    const userDataKeysToHash = [\n      'external_id',\n      'phone',\n      'email',\n      'first_name',\n      'last_name',\n      'zip_code'\n    ];\n    for (let key in mappedData.user) {\n      if (userDataKeysToHash.indexOf(key) !== -1) {\n        mappedData.user[key] = hashData(mappedData.user[key]);\n      }\n    }\n  }\n\n  return mappedData;\n}\n\nfunction addPropertiesData(eventData, mappedData) {\n  mappedData.properties = {};\n\n  const autoMapEnabled = data.hasOwnProperty('autoMapCustomData') ? data.autoMapCustomData : true; // To avoid a breaking change.\n  if (autoMapEnabled) {\n    let items;\n    if (getType(eventData.items) === 'array' && eventData.items.length) items = eventData.items;\n    else if (\n      getType(eventData.ecommerce) === 'object' &&\n      getType(eventData.ecommerce.items) === 'array' &&\n      eventData.ecommerce.items.length\n    ) {\n      items = eventData.ecommerce.items;\n    }\n\n    if (eventData.content_type) mappedData.properties.content_type = eventData.content_type;\n    else if (items) mappedData.properties.content_type = 'product';\n\n    if (eventData.query) mappedData.properties.query = eventData.query;\n    if (eventData.search_term || eventData.search_string)\n      mappedData.properties.search_string = eventData.search_term || eventData.search_string;\n    if (eventData.description) mappedData.properties.description = eventData.description;\n    if (eventData.order_id) mappedData.properties.order_id = eventData.order_id;\n    if (eventData.shop_id) mappedData.properties.shop_id = eventData.shop_id;\n    if (eventData.customer_type) mappedData.properties.customer_type = eventData.customer_type;\n\n    let currencyFromItems;\n    let valueFromItems = 0;\n\n    if (eventData.contents) mappedData.properties.contents = eventData.contents;\n    else if (items) {\n      currencyFromItems = items[0].currency;\n      mappedData.properties.contents = [];\n\n      items.forEach((d) => {\n        const item = {};\n\n        if (d.quantity) item.quantity = makeInteger(d.quantity);\n        if (isValidValue(d.price)) {\n          item.price = makeNumber(d.price);\n          valueFromItems += (item.quantity || 1) * item.price;\n        }\n\n        const contentId = d.item_id || d.id;\n        if (contentId) item.content_id = makeString(contentId);\n\n        const contentCategory = d.content_category || d.item_category;\n        if (contentCategory) item.content_category = contentCategory;\n\n        const contentName = d.content_name || d.item_name;\n        if (contentName) item.content_name = contentName;\n\n        const brand = d.brand || d.item_brand;\n        if (brand) item.brand = brand;\n\n        mappedData.properties.contents.push(item);\n      });\n    }\n\n    const currency = eventData.currency || currencyFromItems;\n    if (currency) mappedData.properties.currency = currency;\n\n    const value =\n      makeNumber(eventData.value) ||\n      makeNumber(eventData['x-ga-mp1-ev']) ||\n      makeNumber(eventData['x-ga-mp1-tr']) ||\n      roundValue(valueFromItems);\n    if (value) mappedData.properties.value = value;\n  }\n\n  if (data.customDataList) {\n    data.customDataList.forEach((d) => {\n      if (isValidValue(d.value)) {\n        mappedData.properties[d.name] = d.value;\n      }\n    });\n  }\n\n  if (data.additionalEventPropertiesList) {\n    data.additionalEventPropertiesList.forEach((d) => {\n      if (isValidValue(d.value)) {\n        mappedData.properties[d.name] = d.value;\n      }\n    });\n  }\n\n  mappedData.properties.gtm_version = PARTNER_AGENT_STRING;\n\n  return mappedData;\n}\n\nfunction addUserData(eventData, mappedData, eventSource, ttclid, ttp) {\n  mappedData.user = {};\n\n  const autoMapEnabled = data.hasOwnProperty('autoMapUserData') ? data.autoMapUserData : true; // To avoid a breaking change.\n  if (autoMapEnabled) {\n    let userEventData = {};\n    let address = {};\n    if (getType(eventData.user_data) === 'object') {\n      userEventData = eventData.user_data;\n      const addressType = getType(userEventData.address);\n      if (addressType === 'object' || addressType === 'array') {\n        address = userEventData.address[0] || userEventData.address;\n      }\n    }\n\n    const email =\n      eventData.email ||\n      eventData.email_address ||\n      userEventData.email ||\n      userEventData.email_address ||\n      userEventData.sha256_email_address;\n    if (email) mappedData.user.email = email;\n\n    const phone =\n      eventData.phone ||\n      eventData.phone_number ||\n      userEventData.phone ||\n      userEventData.phone_number ||\n      userEventData.sha256_phone_number;\n    if (phone) mappedData.user.phone = phone;\n\n    const lastName =\n      eventData.lastName ||\n      eventData.LastName ||\n      eventData.nameLast ||\n      eventData.last_name ||\n      userEventData.last_name ||\n      address.last_name ||\n      address.sha256_last_name;\n    if (lastName) mappedData.user.last_name = lastName;\n\n    const firstName =\n      eventData.firstName ||\n      eventData.FirstName ||\n      eventData.nameFirst ||\n      eventData.first_name ||\n      userEventData.first_name ||\n      address.first_name ||\n      address.sha256_first_name;\n    if (firstName) mappedData.user.first_name = firstName;\n\n    const city = eventData.city || address.city;\n    if (city) mappedData.user.city = city;\n\n    const state = eventData.state || eventData.region || userEventData.region || address.region;\n    if (state) mappedData.user.state = state;\n\n    const zipCode =\n      eventData.zip || eventData.postal_code || userEventData.postal_code || address.postal_code;\n    if (zipCode) mappedData.user.zip_code = zipCode;\n\n    const country =\n      eventData.countryCode || eventData.country || userEventData.country || address.country;\n    if (country) mappedData.user.country = country;\n\n    if (eventSource === 'web') {\n      const autoMappedttclid = ttclid || eventData.ttclid || userEventData.ttclid;\n      if (autoMappedttclid) mappedData.user.ttclid = autoMappedttclid;\n\n      const autoMappedttp = ttp || eventData.ttp || userEventData.ttp;\n      if (autoMappedttp) mappedData.user.ttp = autoMappedttp;\n    }\n\n    if (eventSource === 'app') {\n      const platform = eventData['x-ga-platform'];\n\n      const idfa =\n        eventData.idfa ||\n        (platform === 'ios' ? eventData['x-ga-resettable_device_id'] : undefined) ||\n        userEventData.idfa;\n      if (idfa && idfa !== '00000000-0000-0000-0000-000000000000') mappedData.user.idfa = idfa;\n\n      const idfv =\n        eventData.idfv ||\n        (platform === 'ios' ? eventData['x-ga-vendor_device_id'] : undefined) ||\n        userEventData.idfv;\n      if (idfv && idfv !== '00000000-0000-0000-0000-000000000000') mappedData.user.idfv = idfv;\n\n      const gaid =\n        eventData.gaid ||\n        (platform === 'android' ? eventData['x-ga-resettable_device_id'] : undefined) ||\n        userEventData.gaid;\n      if (gaid && gaid !== '00000000-0000-0000-0000-000000000000') mappedData.user.gaid = gaid;\n\n      const attStatus = eventData.att_status || userEventData.att_status;\n      if (attStatus) mappedData.user.att_status = attStatus;\n    }\n\n    if (eventSource === 'web' || eventSource === 'crm') {\n      const externalId =\n        eventData.external_id || eventData.user_id || eventData.userId || userEventData.external_id;\n      if (externalId) mappedData.user.external_id = externalId;\n    }\n\n    if (eventSource === 'web' || eventSource === 'app') {\n      const locale = eventData.locale || userEventData.locale;\n      if (locale) mappedData.user.locale = locale;\n\n      const ip = eventData.ip_override || eventData.ip_address || eventData.ip;\n      if (ip) mappedData.user.ip = ip;\n\n      if (eventData.user_agent) mappedData.user.user_agent = eventData.user_agent;\n    }\n  }\n\n  if (data.userDataList) {\n    data.userDataList.forEach((d) => {\n      if (isValidValue(d.value)) {\n        mappedData.user[d.name] = d.value;\n      }\n    });\n  }\n\n  return mappedData;\n}\n\nfunction getEventName(data, eventData) {\n  if (data.eventType === 'inherit') {\n    const eventName = eventData.event_name;\n\n    const gaToEventName = {\n      page_view: 'Pageview',\n      click: 'ClickButton',\n      download: 'Download',\n      file_download: 'Download',\n      complete_registration: 'CompleteRegistration',\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      find_location: 'Search',\n      submit_application: 'Subscribe',\n      subscribe: 'Subscribe',\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 (!gaToEventName[eventName]) {\n      return eventName;\n    }\n\n    return gaToEventName[eventName];\n  }\n\n  return data.eventType === 'custom' ? data.eventNameCustom : data.eventName;\n}\n\nfunction addPageData(mappedData, eventData) {\n  const autoMapEnabled = data.hasOwnProperty('autoMapPageData') ? data.autoMapPageData : true; // To avoid a breaking change.\n\n  mappedData.page = {\n    url: data.pageLocation || (autoMapEnabled ? eventData.page_location : undefined)\n  };\n\n  const pageReferrer =\n    data.pageReferrer ||\n    (autoMapEnabled ? eventData.page_referrer || eventData.referrer : undefined);\n  if (pageReferrer) mappedData.page.referrer = pageReferrer;\n\n  return mappedData;\n}\n\nfunction addAppData(mappedData, eventData) {\n  const autoMapAppDataEnabled = data.hasOwnProperty('autoMapAppData') ? data.autoMapAppData : true; // To avoid a breaking change.\n  mappedData.app = {\n    app_id: data.appId\n  };\n\n  const appName = data.appName || (autoMapAppDataEnabled ? eventData.app_name : undefined);\n  if (appName) mappedData.app.app_name = appName;\n\n  const appVersion = data.appVersion || (autoMapAppDataEnabled ? eventData.app_version : undefined);\n  if (appVersion) mappedData.app.app_version = appVersion;\n\n  const autoMapAdDataEnabled = data.hasOwnProperty('autoMapAdData') ? data.autoMapAdData : true; // To avoid a breaking change.\n  let adEventData = {};\n  mappedData.ad = {};\n\n  if (autoMapAdDataEnabled) {\n    if (getType(eventData.ad) === 'object') {\n      adEventData = eventData.ad;\n    }\n\n    const callback = adEventData.callback || eventData.callback;\n    if (callback) mappedData.ad.callback = callback;\n\n    const campaignId = adEventData.campaign_id || eventData.campaign_id;\n    if (campaignId) mappedData.ad.campaign_id = campaignId;\n\n    const adId = adEventData.ad_id || eventData.ad_id;\n    if (adId) mappedData.ad.ad_id = adId;\n\n    const creativeId = adEventData.creative_id || eventData.creative_id;\n    if (creativeId) mappedData.ad.creative_id = creativeId;\n\n    const isRetargeting = adEventData.is_retargeting || eventData.is_retargeting;\n    if (isRetargeting) mappedData.ad.is_retargeting = isRetargeting;\n\n    const attributed = adEventData.attributed || eventData.attributed;\n    if (attributed) mappedData.ad.attributed = attributed;\n\n    const attributionType = adEventData.attribution_type || eventData.attribution_type;\n    if (attributionType) mappedData.ad.attribution_type = attributionType;\n\n    const attributionProvider = adEventData.attribution_provider || eventData.attribution_provider;\n    if (attributionProvider) mappedData.ad.attribution_provider = attributionProvider;\n  }\n\n  if (data.adDataList) {\n    data.adDataList.forEach((d) => {\n      if (isValidValue(d.value)) {\n        mappedData.ad[d.name] = d.value;\n      }\n    });\n  }\n\n  return mappedData;\n}\n\nfunction addLeadData(mappedData) {\n  mappedData.lead = {\n    lead_id: makeString(data.leadId)\n  };\n\n  if (data.leadEventSource) mappedData.lead.lead_event_source = data.leadEventSource;\n\n  return mappedData;\n}\n\nfunction generateTtp() {\n  const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';\n  let result = '';\n\n  for (let i = 0; i < 27; i++) {\n    const randomIndex = generateRandom(0, characters.length - 1);\n    result += characters.charAt(randomIndex);\n  }\n\n  return result;\n}\n\nfunction setGtmEecCookie(userData) {\n  const gtmeecCookie = {};\n\n  if (userData.email) gtmeecCookie.email = userData.email;\n  if (userData.phone) gtmeecCookie.phone = userData.phone;\n  if (userData.last_name) gtmeecCookie.last_name = userData.last_name;\n  if (userData.first_name) gtmeecCookie.first_name = userData.first_name;\n  if (userData.city) gtmeecCookie.city = userData.city;\n  if (userData.state) gtmeecCookie.state = userData.state;\n  if (userData.zip_code) gtmeecCookie.zip_code = userData.zip_code;\n  if (userData.country) gtmeecCookie.country = userData.country;\n  if (userData.external_id) gtmeecCookie.external_id = userData.external_id;\n\n  setCookie('_gtmeec-tt', toBase64(JSON.stringify(gtmeecCookie)), {\n    domain: getCookieDomain(data),\n    path: '/',\n    samesite: data.cookieSameSite || 'strict',\n    secure: true,\n    'max-age': 7776000, // 90 days\n    HttpOnly: true\n  });\n}\n\nfunction enhanceEventData(userData, eventData) {\n  const commonCookie = eventData.common_cookie || {};\n  const cookieValue = getCookieValues('_gtmeec-tt')[0] || commonCookie['_gtmeec-tt'];\n  if (!cookieValue) return userData;\n\n  const jsonStr = fromBase64(cookieValue);\n  if (!jsonStr) return userData;\n\n  const gtmeecData = JSON.parse(jsonStr);\n\n  if (getType(gtmeecData) === 'object') {\n    if (!userData.email && gtmeecData.email) userData.email = gtmeecData.email;\n    if (!userData.phone && gtmeecData.phone) userData.phone = gtmeecData.phone;\n    if (!userData.last_name && gtmeecData.last_name) userData.last_name = gtmeecData.last_name;\n    if (!userData.first_name && gtmeecData.first_name) userData.first_name = gtmeecData.first_name;\n    if (!userData.city && gtmeecData.city) userData.city = gtmeecData.city;\n    if (!userData.state && gtmeecData.state) userData.state = gtmeecData.state;\n    if (!userData.zip_code && gtmeecData.zip_code) userData.zip_code = gtmeecData.zip_code;\n    if (!userData.country && gtmeecData.country) userData.country = gtmeecData.country;\n    if (!userData.external_id && gtmeecData.external_id)\n      userData.external_id = gtmeecData.external_id;\n  }\n\n  return userData;\n}\n\nfunction generateRequestUrl() {\n  return 'https://business-api.tiktok.com/open_api/v' + API_VERSION + '/event/track/';\n}\n\nfunction generateRequestOptions(data) {\n  return {\n    headers: {\n      'Content-Type': 'application/json',\n      'Access-Token': data.accessToken\n    },\n    method: 'POST'\n  };\n}\n\nfunction sendRequest(data, mappedData) {\n  const requestUrl = generateRequestUrl();\n  const requestOptions = generateRequestOptions(data);\n\n  sendHttpRequest(\n    requestUrl,\n    (statusCode, headers, body) => {\n      if (!data.useOptimisticScenario) {\n        return statusCode >= 200 && statusCode < 400 ? data.gtmOnSuccess() : data.gtmOnFailure();\n      }\n    },\n    requestOptions,\n    JSON.stringify(mappedData)\n  );\n}\n\n/*==============================================================================\n  Helpers\n==============================================================================*/\n\nfunction shouldExitEarly(data, eventData) {\n  if (!isConsentGivenOrNotRequired(data, eventData)) {\n    data.gtmOnSuccess();\n    return true;\n  }\n\n  const url = getUrl(eventData);\n  if (url && url.lastIndexOf('https://gtm-msr.appspot.com/', 0) === 0) {\n    data.gtmOnSuccess();\n    return true;\n  }\n}\n\nfunction getUrl(eventData) {\n  return eventData.page_location || getRequestHeader('referer') || eventData.page_referrer;\n}\n\nfunction getCookieDomain(data) {\n  return !data.cookieDomain || data.cookieDomain === 'auto'\n    ? computeEffectiveTldPlusOne(getEventData('page_location') || getRequestHeader('referer')) ||\n        'auto'\n    : data.cookieDomain;\n}\n\nfunction roundValue(value) {\n  if (!value) return value;\n  return Math.round(makeNumber(value) * 100) / 100;\n}\n\nfunction isHashed(value) {\n  if (!value) return false;\n  return makeString(value).match('^[A-Fa-f0-9]{64}$') !== null;\n}\n\nfunction isValidValue(value) {\n  const valueType = getType(value);\n  return valueType !== 'null' && valueType !== 'undefined' && value !== '' && value === value;\n}\n\nfunction isConsentGivenOrNotRequired(data, eventData) {\n  if (data.adStorageConsent !== 'required') return true;\n  if (eventData.consent_state) return !!eventData.consent_state.ad_storage;\n  const xGaGcs = eventData['x-ga-gcs'] || ''; // x-ga-gcs is a string like \"G110\"\n  return xGaGcs[2] === '1';\n}\n\n\n___SERVER_PERMISSIONS___\n\n[\n  {\n    \"instance\": {\n      \"key\": {\n        \"publicId\": \"read_event_data\",\n        \"versionId\": \"1\"\n      },\n      \"param\": [\n        {\n          \"key\": \"eventDataAccess\",\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\": \"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\": \"ttclid\"\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                \"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\": \"_ttp\"\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                \"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\": \"_gtmeec-tt\"\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\": \"send_http\",\n        \"versionId\": \"1\"\n      },\n      \"param\": [\n        {\n          \"key\": \"allowedUrls\",\n          \"value\": {\n            \"type\": 1,\n            \"string\": \"specific\"\n          }\n        },\n        {\n          \"key\": \"urls\",\n          \"value\": {\n            \"type\": 2,\n            \"listItem\": [\n              {\n                \"type\": 1,\n                \"string\": \"https://business-api.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\": \"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\": \"ttclid\"\n              },\n              {\n                \"type\": 1,\n                \"string\": \"_ttp\"\n              },\n              {\n                \"type\": 1,\n                \"string\": \"_gtmeec-tt\"\n              }\n            ]\n          }\n        }\n      ]\n    },\n    \"clientAnnotations\": {\n      \"isEditedByUser\": true\n    },\n    \"isRequired\": true\n  },\n  {\n    \"instance\": {\n      \"key\": {\n        \"publicId\": \"read_request\",\n        \"versionId\": \"1\"\n      },\n      \"param\": [\n        {\n          \"key\": \"headerWhitelist\",\n          \"value\": {\n            \"type\": 2,\n            \"listItem\": [\n              {\n                \"type\": 3,\n                \"mapKey\": [\n                  {\n                    \"type\": 1,\n                    \"string\": \"headerName\"\n                  }\n                ],\n                \"mapValue\": [\n                  {\n                    \"type\": 1,\n                    \"string\": \"referer\"\n                  }\n                ]\n              }\n            ]\n          }\n        },\n        {\n          \"key\": \"headersAllowed\",\n          \"value\": {\n            \"type\": 8,\n            \"boolean\": true\n          }\n        },\n        {\n          \"key\": \"requestAccess\",\n          \"value\": {\n            \"type\": 1,\n            \"string\": \"specific\"\n          }\n        },\n        {\n          \"key\": \"headerAccess\",\n          \"value\": {\n            \"type\": 1,\n            \"string\": \"specific\"\n          }\n        },\n        {\n          \"key\": \"queryParameterAccess\",\n          \"value\": {\n            \"type\": 1,\n            \"string\": \"any\"\n          }\n        }\n      ]\n    },\n    \"clientAnnotations\": {\n      \"isEditedByUser\": true\n    },\n    \"isRequired\": true\n  }\n]\n\n\n___TESTS___\n\nscenarios: []\nsetup: \"const JSON = require('JSON');\\nconst Promise = require('Promise');\\n\\nconst\\\n  \\ expectedBigQuerySettings = {\\n  logBigQueryProjectId: 'logBigQueryProjectId',\\n\\\n  \\  logBigQueryDatasetId: 'logBigQueryDatasetId',\\n  logBigQueryTableId: 'logBigQueryTableId'\\n\\\n  };\\nconst requiredConsoleKeys = ['Type', 'TraceId', 'Name'];\\nconst requiredBqKeys\\\n  \\ = ['timestamp', 'type', 'trace_id', 'tag_name'];\\nconst expectedBqOptions = {\\\n  \\ ignoreUnknownValues: true };\\n\\nconst expectedValue = 'test';\\nconst expectedPixelId\\\n  \\ = '1111111111111';\\n\\nconst mockData = {\\n  logBigQueryProjectId: expectedBigQuerySettings.logBigQueryProjectId,\\n\\\n  \\  logBigQueryDatasetId: expectedBigQuerySettings.logBigQueryDatasetId,\\n  logBigQueryTableId:\\\n  \\ expectedBigQuerySettings.logBigQueryTableId,\\n  eventType: 'custom',\\n  accessToken:\\\n  \\ expectedValue,\\n  pixelId: expectedPixelId,\\n  eventName: expectedValue\\n};\\n\\n\\\n  mock('sendHttpRequest', (requestUrl, callback, requestOptions, requestBody) => {\\n\\\n  \\  if (typeof callback === 'function') {\\n    callback(200);\\n  } else {\\n    requestBody\\\n  \\ = requestOptions;\\n    requestOptions = callback;\\n    return Promise.create((resolve,\\\n  \\ reject) => {\\n      resolve({ statusCode: 200 });\\n    });  \\n  }\\n});\\n\\nmock('getRequestHeader',\\\n  \\ (header) => {\\n  if (header === 'trace-id') return 'expectedTraceId';\\n});\\n\\n\\\n  mock('getTimestampMillis', 1747945830456);\"\n\n\n___NOTES___\n\n2026-09-03 - Change Notes:\n  - Add Customer Type to Automap Custom Data mappings, supporting \"new\"/\"returning\" values from eventData.customer_type\n\n2026-06-29 Change Notes:\n - Logging removal.\n\nCreated on 10/11/2020, 18:14:02\n\n\n",
                "galleryReference": {
                    "host": "github.com",
                    "owner": "stape-io",
                    "repository": "tiktok-tag",
                    "version": "6b4930488b19c03c508f05ac8124e776f5892d02",
                    "signature": "c4686d1bed59c91745871a560471985fe8c3b87be3b9256be2e4eacbbc07ceff",
                    "galleryTemplateId": "K8M24"
                }
            },
            {
                "accountId": "6374306328",
                "containerId": "262778781",
                "templateId": "14",
                "name": "Conversions API Tag",
                "fingerprint": "1788192494721",
                "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_NCN6S\",\n  \"version\": 1,\n  \"displayName\": \"Conversions API Tag\",\n  \"categories\": [\n    \"CONVERSIONS\"\n  ],\n  \"brand\": {\n    \"id\": \"github.com_facebookincubator\",\n    \"displayName\": \"facebookincubator\",\n    \"thumbnail\": \"data:image/jpeg;base64,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\\u003d\"\n  },\n  \"description\": \"A server-side tag template that prepares information from your tagging server to be sent through Conversions API.\",\n  \"containerContexts\": [\n    \"SERVER\"\n  ]\n}\n\n\n___TEMPLATE_PARAMETERS___\n\n[\n  {\n    \"type\": \"TEXT\",\n    \"name\": \"pixelId\",\n    \"displayName\": \"Pixel ID\",\n    \"simpleValueType\": true,\n    \"valueValidators\": [\n      {\n        \"type\": \"NON_EMPTY\"\n      }\n    ]\n  },\n  {\n    \"type\": \"TEXT\",\n    \"name\": \"apiAccessToken\",\n    \"displayName\": \"API Access Token\",\n    \"simpleValueType\": true,\n    \"valueValidators\": [\n      {\n        \"type\": \"NON_EMPTY\"\n      }\n    ],\n    \"help\": \"To use the Conversions API, you need an access token. See \\u003ca href\\u003d\\\"https://developers.facebook.com/docs/marketing-api/conversions-api/get-started#access-token\\\"\\u003ehere\\u003c/a\\u003e for generating an access token.\"\n  },\n  {\n    \"type\": \"TEXT\",\n    \"name\": \"testEventCode\",\n    \"displayName\": \"Test Event Code\",\n    \"simpleValueType\": true,\n    \"help\": \"Code used to verify that your server events are received correctly by Conversions API. Use this code to test your server events in the Test Events feature in Events Manager. See \\u003ca href\\u003d\\\"https://developers.facebook.com/docs/marketing-api/conversions-api/using-the-api#testEvents\\\"\\u003e Test Events Tool\\u003c/a\\u003e for an example.\"\n  },\n  {\n    \"type\": \"SELECT\",\n    \"name\": \"actionSource\",\n    \"displayName\": \"Action Source\",\n    \"macrosInSelect\": false,\n    \"selectItems\": [\n      {\n        \"value\": \"website\",\n        \"displayValue\": \"Website\"\n      },\n      {\n        \"value\": \"email\",\n        \"displayValue\": \"Email\"\n      },\n      {\n        \"value\": \"app\",\n        \"displayValue\": \"App\"\n      },\n      {\n        \"value\": \"phone_call\",\n        \"displayValue\": \"Phone Call\"\n      },\n      {\n        \"value\": \"chat\",\n        \"displayValue\": \"Chat\"\n      },\n      {\n        \"value\": \"physical_store\",\n        \"displayValue\": \"Physical Store\"\n      },\n      {\n        \"value\": \"system_generated\",\n        \"displayValue\": \"System Generated\"\n      },\n      {\n        \"value\": \"other\",\n        \"displayValue\": \"Other\"\n      }\n    ],\n    \"simpleValueType\": true,\n    \"help\": \"This field allows you to specify where your conversions occurred. Knowing where your events took place helps ensure your ads go to the right people. See \\u003ca href\\u003d\\\"https://developers.facebook.com/docs/marketing-api/conversions-api/parameters/server-event#action-source\\\"\\u003ehere\\u003c/a\\u003e for more information.\"\n  },\n  {\n    \"type\": \"CHECKBOX\",\n    \"name\": \"extendCookies\",\n    \"checkboxText\": \"Extend Meta Pixel cookies (fbp/fbc)\",\n    \"simpleValueType\": true\n  },\n  {\n    \"type\": \"CHECKBOX\",\n    \"name\": \"enableEventEnhancement\",\n    \"checkboxText\": \"Enable Event Enhancement\",\n    \"simpleValueType\": true,\n    \"help\": \"Enable Use of HTTP Only Secure Cookie (gtmeec) to Enhance Event Data\"\n  }\n]\n\n\n___SANDBOXED_JS_FOR_SERVER___\n\n// Sandbox Javascript imports\nconst getAllEventData = require('getAllEventData');\nconst getType = require('getType');\nconst sendHttpRequest = require('sendHttpRequest');\nconst JSON = require('JSON');\nconst Math = require('Math');\nconst getTimestampMillis = require('getTimestampMillis');\nconst sha256Sync = require('sha256Sync');\nconst toBase64 = require('toBase64');\nconst fromBase64 = require('fromBase64');\nconst getCookieValues = require('getCookieValues');\nconst setCookie = require('setCookie');\nconst decodeUriComponent = require('decodeUriComponent');\nconst parseUrl = require('parseUrl');\nconst computeEffectiveTldPlusOne = require('computeEffectiveTldPlusOne');\n\n// Constants\nconst API_ENDPOINT = 'https://graph.facebook.com';\nconst API_VERSION = 'v25.0';\nconst PARTNER_AGENT = 'gtmss-1.0.0-0.0.10';\nconst GTM_EVENT_MAPPINGS = {\n  \"add_payment_info\": \"AddPaymentInfo\",\n  \"add_to_cart\": \"AddToCart\",\n  \"add_to_wishlist\": \"AddToWishlist\",\n  \"gtm.dom\": \"PageView\",\n  \"page_view\": \"PageView\",\n  \"purchase\": \"Purchase\",\n  \"search\": \"Search\",\n  \"begin_checkout\": \"InitiateCheckout\",\n  \"generate_lead\": \"Lead\",\n  \"view_item\": \"ViewContent\",\n  \"sign_up\": \"CompleteRegistration\"\n};\n\nfunction isAlreadyHashed(input){\n  return input && (input.match('^[A-Fa-f0-9]{64}$') != null);\n}\n\nfunction setFbCookie(name, value, expire) {\n  setCookie(name, value, {\n    domain: 'auto',\n    path: '/',\n    samesite: 'Lax',\n    secure: true,\n    'max-age': expire || 7776000, // default to 90 days\n    httpOnly: false\n  });\n}\n\nfunction setHttpOnlyCookie(name, value, expire) {\n  setCookie(name, value, {\n    domain: 'auto',\n    path: '/',\n    samesite: 'strict',\n    secure: true,\n    'max-age': expire || 7776000, // default to 90 days\n    httpOnly: true\n  });\n}\n\nfunction getFbcValue() {\n  let fbc = eventModel['x-fb-ck-fbc'] || getCookieValues('_fbc', true)[0];\n  const url = eventModel.page_location;\n  const subDomainIndex = url ? computeEffectiveTldPlusOne(url).split('.').length - 1 : 1;\n  const parsedUrl = parseUrl(url);\n  if (parsedUrl && parsedUrl.searchParams.fbclid) {\n    fbc = 'fb.' + subDomainIndex + '.' + getTimestampMillis() + '.' + decodeUriComponent(parsedUrl.searchParams.fbclid);\n  }\n\n  return fbc;\n}\n\nfunction hashFunction(input){\n  const type = getType(input);\n  if(type == 'undefined' || input == 'undefined') {\n    return undefined;\n  }\n\n  if(input == null || isAlreadyHashed(input)){\n    return input;\n  }\n\n  return sha256Sync(input.trim().toLowerCase(), {outputEncoding: 'hex'});\n}\n\nfunction getContentFromItems(items) {\n    return items.map(item => {\n        return {\n            \"id\": (item.item_id || item.item_name) || undefined,\n            \"item_price\": item.price || undefined,\n            \"quantity\": item.quantity || undefined,\n        };\n    });\n}\n\nfunction getMetaEventName(gtmEventName) {\n  return GTM_EVENT_MAPPINGS[gtmEventName] || gtmEventName;\n}\n\nconst eventModel = getAllEventData();\nconst event = {};\nevent.event_name = getMetaEventName(eventModel.event_name);\nevent.event_time = eventModel.event_time || (Math.round(getTimestampMillis() / 1000));\nevent.event_id = eventModel.event_id;\nevent.event_source_url = eventModel.page_location;\nif(eventModel.action_source || data.actionSource) {\n  event.action_source = eventModel.action_source ? eventModel.action_source : data.actionSource;\n}\nevent.referrer_url = eventModel.page_referrer;\n\n\nevent.user_data = {};\n// Default Tag Parameters\nevent.user_data.client_ip_address = eventModel.ip_override;\nevent.user_data.client_user_agent = eventModel.user_agent;\n\n\n// Commmon Event Schema Parameters\nevent.user_data.em = eventModel['x-fb-ud-em'] ||\n                        (eventModel.user_data != null ? hashFunction(eventModel.user_data.email_address) : undefined);\n\nlet normalizedPhoneNumber = null;\nif (eventModel.user_data && eventModel.user_data.phone_number) {\n  normalizedPhoneNumber = eventModel.user_data.phone_number.replace(\"+\", \"\").replace(\"-\", \"\").replace(\" \", \"\").replace(\"(\", \"\").replace(\")\", \"\");\n  normalizedPhoneNumber = hashFunction(normalizedPhoneNumber);\n}\nevent.user_data.ph = eventModel['x-fb-ud-ph'] || (normalizedPhoneNumber != null ? normalizedPhoneNumber : undefined);\n\nconst addressData = (eventModel.user_data != null && eventModel.user_data.address != null) ? eventModel.user_data.address : {};\nevent.user_data.fn = eventModel['x-fb-ud-fn'] || hashFunction(addressData.first_name);\nevent.user_data.ln = eventModel['x-fb-ud-ln'] || hashFunction(addressData.last_name);\nevent.user_data.ct = eventModel['x-fb-ud-ct'] || hashFunction(addressData.city);\nevent.user_data.st = eventModel['x-fb-ud-st'] || hashFunction(addressData.region);\nevent.user_data.zp = eventModel['x-fb-ud-zp'] || hashFunction(addressData.postal_code);\nevent.user_data.country = eventModel['x-fb-ud-country'] || hashFunction(addressData.country);\n\n// Conversions API Specific Parameters\nevent.user_data.ge = eventModel['x-fb-ud-ge'];\nevent.user_data.db = eventModel['x-fb-ud-db'];\nevent.user_data.external_id = eventModel['x-fb-ud-external_id'];\nevent.user_data.subscription_id = eventModel['x-fb-ud-subscription_id'];\nevent.user_data.fbp = eventModel['x-fb-ck-fbp'] || getCookieValues('_fbp', true)[0];\nevent.user_data.fbc = getFbcValue();\nevent.user_data.fb_login_id = eventModel['x-fb-ud-fb-login-id'] || (eventModel.user_data != null && eventModel.user_data.fb_login_id != null ? eventModel.user_data.fb_login_id : undefined);\n\nevent.custom_data = {};\nevent.custom_data.currency = eventModel.currency;\nevent.custom_data.value = eventModel.value;\nevent.custom_data.search_string = eventModel.search_term;\nevent.custom_data.order_id = eventModel.transaction_id;\nevent.custom_data.content_category = eventModel['x-fb-cd-content_category'];\nevent.custom_data.content_ids = eventModel['x-fb-cd-content_ids'];\nevent.custom_data.content_name = eventModel['x-fb-cd-content_name'];\nevent.custom_data.content_type = eventModel['x-fb-cd-content_type'];\nconst invalidString = \"[object Object]\";\nevent.custom_data.contents = (eventModel['x-fb-cd-contents'] != null && eventModel['x-fb-cd-contents'].indexOf(invalidString) == 0 ? null : (typeof(eventModel['x-fb-cd-contents']) == \"string\" ? JSON.parse(eventModel['x-fb-cd-contents']) : eventModel['x-fb-cd-contents'])) || (eventModel.items != null ? getContentFromItems(eventModel.items) : undefined);\n\nconst customProperties = (eventModel.custom_properties != null) ? (eventModel.custom_properties.indexOf(invalidString) == 0 ? null : (typeof(eventModel.custom_properties) == \"string\" ?JSON.parse(eventModel.custom_properties) : eventModel.custom_properties))  : {};\nfor (const property in customProperties) {\n    event.custom_data[property] = customProperties[property];\n}\nevent.custom_data.num_items = eventModel['x-fb-cd-num_items'];\nevent.custom_data.predicted_ltv = eventModel['x-fb-cd-predicted_ltv'];\nevent.custom_data.status = eventModel['x-fb-cd-status'];\nevent.custom_data.delivery_category = eventModel['x-fb-cd-delivery_category'];\n\nevent.data_processing_options = eventModel.data_processing_options;\nevent.data_processing_options_country = eventModel.data_processing_options_country;\nevent.data_processing_options_state = eventModel.data_processing_options_state;\n\nfunction setGtmEecCookie(value) {\n  const cookieJsonStr = JSON.stringify(value);\n\n  const gtmeecCookieValueBase64 = toBase64(cookieJsonStr);\n\n  setHttpOnlyCookie('_gtmeec', gtmeecCookieValueBase64);\n}\n\n//sets first party cookie with latest merged user data.\nfunction setResponseHeaderCookies(user_data) {\n  let gtmeecCookie = JSON.parse('{}');\n\n  // if user_data has new information, gtmeec data is overriden\n  if (user_data.em) {\n    gtmeecCookie.em = user_data.em;\n  }\n\n  if (user_data.ph) {\n    gtmeecCookie.ph = user_data.ph;\n  }\n\n  if (user_data.ln) {\n    gtmeecCookie.ln = user_data.ln;\n  }\n\n  if (user_data.fn) {\n    gtmeecCookie.fn = user_data.fn;\n  }\n\n  if (user_data.ct) {\n    gtmeecCookie.ct = user_data.ct;\n  }\n\n  if (user_data.st) {\n    gtmeecCookie.st = user_data.st;\n  }\n\n  if (user_data.zp) {\n    gtmeecCookie.zp = user_data.zp;\n  }\n\n  if (user_data.ge) {\n    gtmeecCookie.ge = user_data.ge;\n  }\n\n  if (user_data.db) {\n    gtmeecCookie.db = user_data.db;\n  }\n\n  if (user_data.country) {\n    gtmeecCookie.country = user_data.country;\n  }\n\n  if (user_data.external_id){\n    gtmeecCookie.external_id = user_data.external_id;\n  }\n\n  if (user_data.fb_login_id) {\n    gtmeecCookie.fb_login_id = user_data.fb_login_id;\n  }\n\n  setGtmEecCookie(gtmeecCookie);\n}\n\n//enhance event data with first party `_gtmeec` cookie\nfunction enhanceEventData(user_data) {\n\n  const cookieValues = getCookieValues('_gtmeec', true);\n\n  if (!cookieValues) {\n    return user_data;\n  }\n\n  if (cookieValues.length == 0) {\n    return user_data;\n  }\n\n  const encodedValue = cookieValues[0];\n\n  if (!encodedValue) {\n    return user_data;\n  }\n\n  const jsonStr = fromBase64(encodedValue);\n  if (!jsonStr) {\n    return user_data;\n  }\n\n  const gtmeecData = JSON.parse(jsonStr);\n\n  // if incoming event has already have the customer information then don't change\n  if (gtmeecData) {\n    if (!user_data.em && gtmeecData.em) {\n      user_data.em = gtmeecData.em;\n    }\n\n    if (!user_data.ph && gtmeecData.ph) {\n      user_data.ph = gtmeecData.ph;\n    }\n\n    if (!user_data.ln && gtmeecData.ln) {\n      user_data.ln = gtmeecData.ln;\n    }\n\n    if (!user_data.fn && gtmeecData.fn) {\n      user_data.fn = gtmeecData.fn;\n    }\n\n    if (!user_data.ct && gtmeecData.ct) {\n      user_data.ct = gtmeecData.ct;\n    }\n\n    if (!user_data.st && gtmeecData.st) {\n      user_data.st = gtmeecData.st;\n    }\n\n    if (!user_data.zp && gtmeecData.zp) {\n      user_data.zp = gtmeecData.zp;\n    }\n\n    if (!user_data.ge && gtmeecData.ge) {\n      user_data.ge = gtmeecData.ge;\n    }\n\n    if (!user_data.db && gtmeecData.db) {\n      user_data.db = gtmeecData.db;\n    }\n\n    if (!user_data.country && gtmeecData.country) {\n      user_data.country = gtmeecData.country;\n    }\n\n    if (!user_data.external_id && gtmeecData.external_id) {\n      user_data.external_id = gtmeecData.external_id;\n    }\n\n    if (!user_data.fb_login_id && gtmeecData.fb_login_id) {\n      user_data.fb_login_id = gtmeecData.fb_login_id;\n    }\n  }\n\n  return user_data;\n}\n\n//send events to CAPI Server\nfunction sendEventToCapiServers(pixel_event) {\n\n  // if event enhancement is enabled then event data is enhanced\n  let partnerAgent = PARTNER_AGENT;\n  if (data.enableEventEnhancement) {\n    pixel_event.user_data = enhanceEventData(pixel_event.user_data);\n    partnerAgent =  PARTNER_AGENT + '-ee';\n  }\n\n  const eventRequest = {data: [pixel_event], partner_agent: partnerAgent};\n\n  if(eventModel.test_event_code || data.testEventCode) {\n    eventRequest.test_event_code = eventModel.test_event_code ? eventModel.test_event_code : data.testEventCode;\n  }\n\n  const routeParams = 'events?access_token=' + data.apiAccessToken;\n  const graphEndpoint = [API_ENDPOINT,\n                         API_VERSION,\n                         data.pixelId,\n                         routeParams].join('/');\n\n  const requestHeaders = {headers: {'content-type': 'application/json'}, method: 'POST'};\n  return sendHttpRequest(\n    graphEndpoint,\n    (statusCode, headers, response) => {\n      if (statusCode >= 200 && statusCode < 300) {\n\n        if (data.extendCookies && pixel_event.user_data.fbc) {\n          setFbCookie('_fbc', pixel_event.user_data.fbc);\n        }\n\n        if (data.extendCookies && pixel_event.user_data.fbp) {\n          setFbCookie('_fbp', pixel_event.user_data.fbp);\n        }\n\n        if (data.enableEventEnhancement) {\n          setResponseHeaderCookies(pixel_event.user_data);\n        }\n\n        data.gtmOnSuccess();\n      } else {\n        data.gtmOnFailure();\n      }\n    },\n    requestHeaders,\n    JSON.stringify(eventRequest)\n  );\n}\n\nsendEventToCapiServers(event);\n\n\n___SERVER_PERMISSIONS___\n\n[\n  {\n    \"instance\": {\n      \"key\": {\n        \"publicId\": \"read_event_data\",\n        \"versionId\": \"1\"\n      },\n      \"param\": [\n        {\n          \"key\": \"eventDataAccess\",\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\": \"send_http\",\n        \"versionId\": \"1\"\n      },\n      \"param\": [\n        {\n          \"key\": \"allowedUrls\",\n          \"value\": {\n            \"type\": 1,\n            \"string\": \"specific\"\n          }\n        },\n        {\n          \"key\": \"urls\",\n          \"value\": {\n            \"type\": 2,\n            \"listItem\": [\n              {\n                \"type\": 1,\n                \"string\": \"https://graph.facebook.com/\"\n              }\n            ]\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\": \"_fbp\"\n              },\n              {\n                \"type\": 1,\n                \"string\": \"_fbc\"\n              },\n              {\n                \"type\": 1,\n                \"string\": \"_gtmeec\"\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\": \"_fbc\"\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                \"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\": \"_fbp\"\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                \"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\": \"_gtmeec\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"*\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"*\"\n                  },\n                  {\n                    \"type\": 1,\n                    \"string\": \"secure\"\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\n\n___TESTS___\n\nscenarios:\n- name: on EventModel model data tag triggers to send to Conversions API\n  code: |-\n    // Act\n    runCode(testConfigurationData);\n\n    //Assert\n    assertApi('sendHttpRequest').wasCalledWith(requestEndpoint, actualSuccessCallback, requestHeaderOptions, JSON.stringify(requestData));\n    assertApi('gtmOnSuccess').wasCalled();\n- name: on Event with common event schema triggers tag to send to Conversions API\n  code: |-\n    const preTagFireEventTime = Math.round(getTimestampMillis() / 1000);\n    const common_event_schema = {\n        event_name: testData.event_name,\n        client_id: 'client123',\n        ip_override: testData.ip_address,\n        user_agent: testData.user_agent,\n        page_referrer: testData.page_referrer,\n      };\n    mock('getAllEventData', () => {\n      return common_event_schema;\n    });\n\n    // Act\n    runCode(testConfigurationData);\n\n    //Assert\n    const actualTagFireEventTime = JSON.parse(httpBody).data[0].event_time;\n    assertThat(actualTagFireEventTime-preTagFireEventTime).isLessThan(1);\n    assertApi('gtmOnSuccess').wasCalled();\n- name: on sending action source from Client, Tag overrides the preset configuration\n  code: |-\n    // Act\n    mock('getAllEventData', () => {\n      inputEventModel.action_source = testData.action_source;\n      return inputEventModel;\n    });\n    runCode(testConfigurationData);\n\n    //Assert\n    assertThat(JSON.parse(httpBody).data[0].action_source).isEqualTo(inputEventModel.action_source);\n- name: on receiving event, if GTM Standard Event then Tag converts to corresponding\n    Conversions API Event, passes through as-is if otherwise\n  code: |-\n    // Act\n    mock('getAllEventData', () => {\n      inputEventModel.event_name = 'add_to_wishlist';\n      return inputEventModel;\n    });\n    runCode(testConfigurationData);\n\n    //Assert\n    assertThat(JSON.parse(httpBody).data[0].event_name).isEqualTo('AddToWishlist');\n\n\n    // Act\n    mock('getAllEventData', () => {\n      inputEventModel.event_name = 'custom_event';\n      return inputEventModel;\n    });\n    runCode(testConfigurationData);\n\n    //Assert\n    assertThat(JSON.parse(httpBody).data[0].event_name).isEqualTo('custom_event');\n\n    // Act\n    mock('getAllEventData', () => {\n      inputEventModel.event_name = 'generate_lead';\n      return inputEventModel;\n    });\n    runCode(testConfigurationData);\n\n    //Assert\n    assertThat(JSON.parse(httpBody).data[0].event_name).isEqualTo('Lead');\n- name: On receiving event, hashes the the user_data fields if they are not already\n    hashed\n  code: |-\n    // Un-hashed raw email_address from Common Event Schema is hashed before posted to Conversions API.\n\n    // Act\n    mock('getAllEventData', () => {\n      inputEventModel = {};\n      inputEventModel['x-fb-ud-em'] = null;\n      inputEventModel['x-fb-ud-ph'] = null;\n      inputEventModel['x-fb-ud-fn'] = null;\n      inputEventModel['x-fb-ud-ln'] = null;\n      inputEventModel['x-fb-ud-ct'] = null;\n      inputEventModel['x-fb-ud-st'] = null;\n      inputEventModel['x-fb-ud-zp'] = null;\n      inputEventModel['x-fb-ud-country'] = null;\n      inputEventModel.user_data = {};\n      inputEventModel.user_data.email_address = 'foo@bar.com';\n      inputEventModel.user_data.phone_number = '1234567890';\n      inputEventModel.user_data.address = {};\n      inputEventModel.user_data.address.first_name = 'Foo';\n      inputEventModel.user_data.address.last_name = 'Bar';\n      inputEventModel.user_data.address.city = 'Menlo Park';\n      inputEventModel.user_data.address.region = 'ca';\n      inputEventModel.user_data.address.postal_code = '12345';\n      inputEventModel.user_data.address.country = 'usa';\n      return inputEventModel;\n    });\n    runCode(testConfigurationData);\n\n    //Assert\n    assertThat(JSON.parse(httpBody).data[0].user_data.em).isEqualTo(hashFunction('foo@bar.com'));\n    assertThat(JSON.parse(httpBody).data[0].user_data.ph).isEqualTo(hashFunction('1234567890'));\n    assertThat(JSON.parse(httpBody).data[0].user_data.fn).isEqualTo(hashFunction('Foo'));\n    assertThat(JSON.parse(httpBody).data[0].user_data.ln).isEqualTo(hashFunction('Bar'));\n    assertThat(JSON.parse(httpBody).data[0].user_data.ct).isEqualTo(hashFunction('Menlo Park'));\n    assertThat(JSON.parse(httpBody).data[0].user_data.st).isEqualTo(hashFunction('ca'));\n    assertThat(JSON.parse(httpBody).data[0].user_data.zp).isEqualTo(hashFunction('12345'));\n    assertThat(JSON.parse(httpBody).data[0].user_data.country).isEqualTo(hashFunction('usa'));\n\n    // Un-hashed raw email_address in mixed-case is converted to lowercase, hashed and posted to Conversions API.\n\n    // Act\n    mock('getAllEventData', () => {\n      inputEventModel.user_data.email_address = 'FOO@BAR.com';\n      return inputEventModel;\n    });\n    runCode(testConfigurationData);\n\n    //Assert\n    assertThat(JSON.parse(httpBody).data[0].user_data.em).isEqualTo(hashFunction('foo@bar.com'));\n\n\n    // Already sha256(email_address) field from GA4 schema, is unchanged, is posted as-is to Conversions API.\n\n    // Act\n    mock('getAllEventData', () => {\n      inputEventModel.user_data.email_address = hashFunction('foo@bar.com');\n      return inputEventModel;\n    });\n    runCode(testConfigurationData);\n\n    //Assert\n    assertThat(JSON.parse(httpBody).data[0].user_data.em).isEqualTo(hashFunction('foo@bar.com'));\n\n    // Already null email field from GA4 schema, is sent as null to Conversions API.\n\n    // Act\n    mock('getAllEventData', () => {\n      inputEventModel = {};\n      inputEventModel.user_data = {};\n      inputEventModel.user_data.email_address = null;\n      return inputEventModel;\n    });\n    runCode(testConfigurationData);\n\n    //Assert\n    assertThat(JSON.parse(httpBody).data[0].user_data.em).isNull();\n- name: On receiving event with fbp/fbc cookies, it is sent to Conversions API\n  code: |-\n    // Act\n    mock('getAllEventData', () => {\n      inputEventModel['x-fb-ck-fbp'] = null;\n      inputEventModel['x-fb-ck-fbc'] = null;\n      return inputEventModel;\n    });\n\n    mock('getCookieValues', (cookieName) => {\n      if(cookieName === '_fbp') return ['fbp_cookie'];\n      if(cookieName === '_fbc') return ['fbc_cookie'];\n    });\n\n    runCode(testConfigurationData);\n\n    //Assert\n    assertThat(JSON.parse(httpBody).data[0].user_data.fbp).isEqualTo('fbp_cookie');\n    assertThat(JSON.parse(httpBody).data[0].user_data.fbc).isEqualTo('fbc_cookie');\n- name: On receiving GA4 event, with the items info, tag parses them into Conversions\n    API schema\n  code: |-\n    // Act\n    let items = [\n        {\n          item_id: '1',\n          quantity: 5,\n          price: 123.45,\n        },\n        {\n          item_id: '2',\n          quantity: 10,\n          price: 123.45,\n        }\n      ];\n\n    mock('getAllEventData', () => {\n      inputEventModel = {};\n      inputEventModel['x-fb-cd-contents'] = null;\n      inputEventModel.items = items;\n      return inputEventModel;\n    });\n    runCode(testConfigurationData);\n\n    //Assert\n    let actual_contents = JSON.parse(httpBody).data[0].custom_data.contents;\n    assertThat(JSON.parse(httpBody).data[0].custom_data.contents.length).isEqualTo(items.length);\n    for( var i = 0; i < items.length; i++) {\n      assertThat(actual_contents[i].id).isEqualTo(items[i].item_id);\n      assertThat(actual_contents[i].item_price).isEqualTo(items[i].price);\n      assertThat(actual_contents[i].quantity).isEqualTo(items[i].quantity);\n    }\n\n    // Act\n    mock('getAllEventData', () => {\n      inputEventModel = {};\n      inputEventModel.items = null;\n      return inputEventModel;\n    });\n    runCode(testConfigurationData);\n\n    //Assert\n    assertThat(JSON.parse(httpBody).data[0].custom_data.contents).isUndefined();\n- name: When address is missing it skips parsing the nested fields\n  code: |\n    mock('getAllEventData', () => {\n      inputEventModel['x-fb-ud-em'] = null;\n      inputEventModel['x-fb-ud-ph'] = null;\n      inputEventModel['x-fb-ud-fn'] = null;\n      inputEventModel['x-fb-ud-ln'] = null;\n      inputEventModel['x-fb-ud-ct'] = null;\n      inputEventModel['x-fb-ud-st'] = null;\n      inputEventModel['x-fb-ud-zp'] = null;\n      inputEventModel['x-fb-ud-country'] = null;\n      inputEventModel.user_data = {};\n      inputEventModel.user_data.email_address = 'foo@bar.com';\n      inputEventModel.user_data.phone_number = '1234567890';\n      return inputEventModel;\n    });\n\n    runCode(testConfigurationData);\n\n    assertThat(JSON.parse(httpBody).data[0].user_data.em).isEqualTo(hashFunction('foo@bar.com'));\n    assertThat(JSON.parse(httpBody).data[0].user_data.ph).isEqualTo(hashFunction('1234567890'));\n    assertThat(JSON.parse(httpBody).data[0].user_data.fn).isUndefined();\n    assertThat(JSON.parse(httpBody).data[0].user_data.ln).isUndefined();\n    assertThat(JSON.parse(httpBody).data[0].user_data.ct).isUndefined();\n    assertThat(JSON.parse(httpBody).data[0].user_data.st).isUndefined();\n    assertThat(JSON.parse(httpBody).data[0].user_data.zp).isUndefined();\n    assertThat(JSON.parse(httpBody).data[0].user_data.country).isUndefined();\n- name: When parameters are undefined skip parsing\n  code: |\n    mock('getAllEventData', () => {\n      inputEventModel = {};\n      inputEventModel['x-fb-ud-em'] = null;\n      inputEventModel['x-fb-ud-ph'] = null;\n      inputEventModel['x-fb-ud-fn'] = null;\n      inputEventModel['x-fb-ud-ln'] = null;\n      inputEventModel['x-fb-ud-ct'] = null;\n      inputEventModel['x-fb-ud-st'] = null;\n      inputEventModel['x-fb-ud-zp'] = null;\n      inputEventModel['x-fb-ud-country'] = null;\n      inputEventModel['x-fb-ud-fb-login-id'] = null;\n      inputEventModel.user_data = {};\n      inputEventModel.user_data.email_address = undefined;\n      inputEventModel.user_data.phone_number = '1234567890';\n      inputEventModel.user_data.address = {};\n      inputEventModel.user_data.address.first_name = 'John';\n      inputEventModel.user_data.address.last_name = undefined;\n      inputEventModel.user_data.address.city = 'menlopark';\n      inputEventModel.user_data.address.region = 'ca';\n      inputEventModel.user_data.address.postal_code = '94025';\n      inputEventModel.user_data.address.country = 'usa';\n      inputEventModel.user_data.fb_login_id = 123456789;\n      return inputEventModel;\n    });\n\n    runCode(testConfigurationData);\n\n    assertThat(JSON.parse(httpBody).data[0].user_data.em).isUndefined();\n    assertThat(JSON.parse(httpBody).data[0].user_data.ph).isEqualTo(hashFunction('1234567890'));\n    assertThat(JSON.parse(httpBody).data[0].user_data.fn).isEqualTo(hashFunction('John'));\n    assertThat(JSON.parse(httpBody).data[0].user_data.ln).isUndefined();\n    assertThat(JSON.parse(httpBody).data[0].user_data.ct).isEqualTo(hashFunction('menlopark'));\n    assertThat(JSON.parse(httpBody).data[0].user_data.st).isEqualTo(hashFunction('ca'));\n    assertThat(JSON.parse(httpBody).data[0].user_data.zp).isEqualTo(hashFunction('94025'));\n    assertThat(JSON.parse(httpBody).data[0].user_data.country).isEqualTo(hashFunction('usa'));\n    assertThat(JSON.parse(httpBody).data[0].user_data.fb_login_id).isEqualTo(123456789);\n- name: Set Meta cookies (fbp / fbc) if 'extendCookies' checkbox is ticked\n  code: |\n    runCode({\n      pixelId: '123',\n      apiAccessToken: 'abc',\n      testEventCode: 'test123',\n      actionSource: 'source123',\n      extendCookies: true\n    });\n\n    //Assert\n    assertApi('setCookie').wasCalled();\n    assertApi('gtmOnSuccess').wasCalled();\n- name: Do not set Meta cookies (fbp / fbc) if 'extendCookies' checkbox is ticked\n  code: |\n    runCode({\n      pixelId: '123',\n      apiAccessToken: 'abc',\n      testEventCode: 'test123',\n      actionSource: 'source123',\n      extendCookies: false\n    });\n\n    //Assert\n    assertApi('setCookie').wasNotCalled();\n    assertApi('gtmOnSuccess').wasCalled();\n- name: On receiving event, sets the data_processing_options field if present\n  code: |\n    mock('getAllEventData', () => {\n      inputEventModel.data_processing_options = testData.data_processing_options;\n      inputEventModel.data_processing_options_country = testData.data_processing_options_country;\n      inputEventModel.data_processing_options_state = testData.data_processing_options_state;\n      return inputEventModel;\n    });\n    runCode(testConfigurationData);\n\n    //Assert\n    assertThat(JSON.parse(httpBody).data[0].data_processing_options).isEqualTo(inputEventModel.data_processing_options);\n    assertThat(JSON.parse(httpBody).data[0].data_processing_options_country).isEqualTo(inputEventModel.data_processing_options_country);\n    assertThat(JSON.parse(httpBody).data[0].data_processing_options_state).isEqualTo(inputEventModel.data_processing_options_state);\n- name: Set Event Enhancement Cookie (gtmeec) if `enableEventEnhancement` is ticked\n  code: |-\n    mock('getAllEventData', () => {\n      inputEventModel = {};\n      inputEventModel.event_name = 'purchase';\n      inputEventModel.user_data = {};\n      inputEventModel.user_data.email_address = 'foo@bar.com';\n      inputEventModel.user_data.phone_number = '1234567890';\n      return inputEventModel;\n    });\n\n    runCode(testConfigurationData);\n\n    runCode({\n      pixelId: '123',\n      apiAccessToken: 'abc',\n      testEventCode: 'test123',\n      actionSource: 'source123',\n      enableEventEnhancement: true,\n      extendCookies: false\n    });\n\n    let cookieOptions = {\n        domain: 'auto',\n        path: '/',\n        samesite: 'strict',\n        secure: true,\n        'max-age': 7776000, // default to 90 days\n        httpOnly: true\n    };\n\n    //Assert\n    assertApi('getCookieValues').wasCalledWith('_gtmeec', true);\n    assertApi('setCookie').wasCalledWith('_gtmeec', 'eyJlbSI6IjBjN2U2YTQwNTg2MmU0MDJlYjc2YTcwZjhhMjZmYzczMmQwN2MzMjkzMWU5ZmFlOWFiMTU4MjkxMWQyZThhM2IiLCJwaCI6ImM3NzVlN2I3NTdlZGU2MzBjZDBhYTExMTNiZDEwMjY2MWFiMzg4MjljYTUyYTY0MjJhYjc4Mjg2MmYyNjg2NDYifQ==', cookieOptions);\n    assertApi('gtmOnSuccess').wasCalled();\n- name: Do not set Event Enhancement Cookie (gtmeec) if `enableEventEnhancement` is\n    not ticked\n  code: |-\n    runCode({\n      pixelId: '123',\n      apiAccessToken: 'abc',\n      testEventCode: 'test123',\n      actionSource: 'source123',\n      extendCookies: false,\n      enableEventEnhancement: false\n    });\n\n    //Assert\n    assertApi('getCookieValues').wasNotCalledWith('_gtmeec', true);\n    assertApi('setCookie').wasNotCalled();\n    assertApi('gtmOnSuccess').wasCalled();\n- name: Parse gtmeec Cookie and Enrich Event When `enableEventEnhancement` is ticked\n  code: |\n    mock('getAllEventData', () => {\n      inputEventModel = {};\n      inputEventModel.event_name = 'purchase';\n      inputEventModel.user_data = {};\n      return inputEventModel;\n    });\n\n    runCode(testConfigurationData);\n\n    const cookieName = '_gtmeec';\n    const val = true;\n\n    mock('getCookieValues', (cookieName, val) => {\n      return ['eyJlbSI6ImVlMjc4OTQzZGU4NGU1ZDYyNDM1NzhlZTFhMTA1N2JjY2UwZTUwZGFhZDk3NTVmNDVkZmE2NGI2MGIxM2JjNWQiLCJwaCI6ImM3NzVlN2I3NTdlZGU2MzBjZDBhYTExMTNiZDEwMjY2MWFiMzg4MjljYTUyYTY0MjJhYjc4Mjg2MmYyNjg2NDYifQ=='];\n    });\n\n    runCode({\n      pixelId: '123',\n      apiAccessToken: 'abc',\n      testEventCode: 'test123',\n      actionSource: 'source123',\n      enableEventEnhancement: true,\n      extendCookies: false\n    });\n\n    let cookieOptions = {\n        domain: 'auto',\n        path: '/',\n        samesite: 'strict',\n        secure: true,\n        'max-age': 7776000, // default to 90 days\n        httpOnly: true\n    };\n\n    // Assert\n    assertApi('getCookieValues').wasCalledWith('_gtmeec', true);\n    assertApi('setCookie').wasCalledWith('_gtmeec', 'eyJlbSI6ImVlMjc4OTQzZGU4NGU1ZDYyNDM1NzhlZTFhMTA1N2JjY2UwZTUwZGFhZDk3NTVmNDVkZmE2NGI2MGIxM2JjNWQiLCJwaCI6ImM3NzVlN2I3NTdlZGU2MzBjZDBhYTExMTNiZDEwMjY2MWFiMzg4MjljYTUyYTY0MjJhYjc4Mjg2MmYyNjg2NDYifQ==', cookieOptions);\n    assertApi('gtmOnSuccess').wasCalled();\n\n    assertThat(JSON.parse(httpBody).data[0].user_data.em).isEqualTo('ee278943de84e5d6243578ee1a1057bcce0e50daad9755f45dfa64b60b13bc5d');\n    assertThat(JSON.parse(httpBody).data[0].user_data.ph).isEqualTo('c775e7b757ede630cd0aa1113bd102661ab38829ca52a6422ab782862f268646');\nsetup: |-\n  // Arrange\n  const JSON = require('JSON');\n  const Math = require('Math');\n  const getTimestampMillis = require('getTimestampMillis');\n  const sha256Sync = require('sha256Sync');\n\n  // helper methods\n  function hashFunction(input) {\n    return sha256Sync(input.trim().toLowerCase(), {outputEncoding: 'hex'});\n  }\n\n  const testConfigurationData = {\n    pixelId: '123',\n    apiAccessToken: 'abc',\n    testEventCode: 'test123',\n    actionSource: 'source123'\n  };\n\n  const testData = {\n    event_name: \"Test1\",\n    event_time: \"123456789\",\n    test_event_code: \"test123\",\n    action_source: 'website',\n    page_referrer: 'https://www.facebook.com',\n    user_data: {\n      ip_address: '1.2.3.4',\n      user_agent: 'Test_UA',\n      email: 'test@example.com',\n      phone_number: '123456789',\n      first_name: 'foo',\n      last_name: 'bar',\n      gender: 'm',\n      date_of_brith: '19910526',\n      city: 'menlopark',\n      state: 'ca',\n      country: 'us',\n      zip: '12345',\n      external_id: 'user123',\n      subscription_id: 'abc123',\n      fbp: 'test_browser_id',\n      fbc: 'test_click_id',\n      fb_login_id: 123456789,\n    },\n    custom_data: {\n      currency: 'USD',\n      value: '123',\n      search_string: 'query123',\n      transaction_id: 'order_123',\n      content_category: 'testCategory',\n      content_ids: ['123', '456'],\n      content_name: 'Foo',\n      content_type: 'product',\n      contents:  [{'id': '123', 'quantity': 2}, {'id': '456', 'quantity': 2}],\n      num_items: '4',\n      predicted_ltv: '10000',\n      delivery_category: 'home_delivery',\n      status: 'subscribed',\n    },\n    \"data_processing_options\": [\"LDU\"],\n    \"data_processing_options_country\": 1,\n    \"data_processing_options_state\": 1000,\n  };\n\n  let inputEventModel = {\n    'event_name': testData.event_name,\n    'event_time': testData.event_time,\n    'page_referrer': testData.page_referrer,\n    'ip_override': testData.user_data.ip_address,\n    'user_agent': testData.user_data.user_agent,\n    'test_event_code': testData.test_event_code,\n    'x-fb-ud-em': testData.user_data.email,\n    'x-fb-ud-ph': testData.user_data.phone_number,\n    'x-fb-ud-fn': testData.user_data.first_name,\n    'x-fb-ud-ln': testData.user_data.last_name,\n    'x-fb-ud-ge': testData.user_data.gender,\n    'x-fb-ud-db': testData.user_data.date_of_brith,\n    'x-fb-ud-ct': testData.user_data.city,\n    'x-fb-ud-st': testData.user_data.state,\n    'x-fb-ud-zp': testData.user_data.zip,\n    'x-fb-ud-country': testData.user_data.country,\n    'x-fb-ud-external_id': testData.user_data.external_id,\n    'x-fb-ud-subscription_id': testData.user_data.subscription_id,\n    'x-fb-ud-fb-login-id': testData.user_data.fb_login_id,\n    'x-fb-ck-fbp': testData.user_data.fbp,\n    'x-fb-ck-fbc': testData.user_data.fbc,\n    'currency': testData.custom_data.currency,\n    'value': testData.custom_data.value,\n    'search_term': testData.custom_data.search_string,\n    'transaction_id': testData.custom_data.transaction_id,\n    'x-fb-cd-status': testData.custom_data.status,\n    'x-fb-cd-content_category': testData.custom_data.content_category,\n    'x-fb-cd-content_name': testData.custom_data.content_name,\n    'x-fb-cd-content_type': testData.custom_data.content_type,\n    'x-fb-cd-contents': testData.custom_data.contents,\n    'x-fb-cd-num_items': testData.custom_data.num_items,\n    'x-fb-cd-predicted_ltv': testData.custom_data.predicted_ltv,\n    'x-fb-cd-delivery_category': testData.custom_data.delivery_category,\n    'data_processing_options': testData.data_processing_options,\n    'data_processing_options_country': testData.data_processing_options_country,\n    'data_processing_options_state': testData.data_processing_options_state,\n  };\n\n  const expectedEventData = {\n  'event_name': testData.event_name,\n  'event_time': testData.event_time,\n  'action_source': testConfigurationData.actionSource,\n  'referrer_url': testData.page_referrer,\n  'user_data': {\n    'client_ip_address': testData.user_data.ip_address,\n    'client_user_agent': testData.user_data.user_agent,\n    'em': testData.user_data.email,\n    'ph': testData.user_data.phone_number,\n    'fn': testData.user_data.first_name,\n    'ln': testData.user_data.last_name,\n    'ct': testData.user_data.city,\n    'st': testData.user_data.state,\n    'zp': testData.user_data.zip,\n    'country': testData.user_data.country,\n    'ge': testData.user_data.gender,\n    'db': testData.user_data.date_of_brith,\n    'external_id': testData.user_data.external_id,\n    'subscription_id': testData.user_data.subscription_id,\n    'fbp': testData.user_data.fbp,\n    'fbc': testData.user_data.fbc,\n    'fb_login_id': testData.user_data.fb_login_id,\n  },\n    'custom_data': {\n      'currency': testData.custom_data.currency,\n      'value': testData.custom_data.value,\n      'search_string': testData.custom_data.search_string,\n      'order_id': testData.custom_data.transaction_id,\n      'content_category': testData.custom_data.content_category,\n      'content_name': testData.custom_data.content_name,\n      'content_type': testData.custom_data.content_type,\n      'contents': testData.custom_data.contents,\n      'num_items': testData.custom_data.num_items,\n      'predicted_ltv': testData.custom_data.predicted_ltv,\n      'status': testData.custom_data.status,\n      'delivery_category': testData.custom_data.delivery_category,\n    },\n    'referrer_url': 'https://www.facebook.com',\n    'data_processing_options': testData.data_processing_options,\n    'data_processing_options_country': testData.data_processing_options_country,\n    'data_processing_options_state': testData.data_processing_options_state,\n  };\n\n  mock('getAllEventData', () => {\n    return inputEventModel;\n  });\n\n  const apiEndpoint = 'https://graph.facebook.com';\n  const apiVersion = 'v25.0';\n  const partnerAgent = 'gtmss-1.0.0-0.0.10';\n\n  const routeParams = 'events?access_token=' + testConfigurationData.apiAccessToken;\n  const requestEndpoint = [apiEndpoint,\n                          apiVersion,\n                          testConfigurationData.pixelId,\n                          routeParams].join('/');\n\n  let requestData = {\n                      data: [expectedEventData],\n                      partner_agent: partnerAgent,\n                      test_event_code: testData.test_event_code\n                     };\n\n  const requestHeaderOptions = {headers: {'content-type': 'application/json'}, method: 'POST'};\n\n  let actualSuccessCallback, httpBody;\n  mock('sendHttpRequest', (postUrl, response, options, body) => {\n    actualSuccessCallback = response;\n    httpBody = body;\n    actualSuccessCallback(200, {}, '');\n  });\n\n\n___NOTES___\n\nCreated on 8/5/2020, 10:20:28 AM\n\n\n",
                "galleryReference": {
                    "host": "github.com",
                    "owner": "facebookincubator",
                    "repository": "ConversionsAPI-Tag-for-GoogleTagManager",
                    "version": "a575edb31aa447469b855c3006ed9991dad711cf",
                    "signature": "3e8ee0e2e9d9914f8c4cfa90d59ae1f4a3188baf79bbcffd4c7b934387c2c164",
                    "galleryTemplateId": "NCN6S"
                }
            },
            {
                "accountId": "6374306328",
                "containerId": "262778781",
                "templateId": "17",
                "name": "Facebook Conversion API",
                "fingerprint": "1789878686286",
                "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_5TP8W\",\n  \"version\": 1,\n  \"displayName\": \"Facebook Conversion API\",\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,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAYAAADDPmHLAAAAAXNSR0IArs4c6QAAAIRlWElmTU0AKgAAAAgABQESAAMAAAABAAEAAAEaAAUAAAABAAAASgEbAAUAAAABAAAAUgEoAAMAAAABAAIAAIdpAAQAAAABAAAAWgAAAAAAAABIAAAAAQAAAEgAAAABAAOgAQADAAAAAQABAACgAgAEAAAAAQAAAICgAwAEAAAAAQAAAIAAAAAAu7RpdAAAAAlwSFlzAAALEwAACxMBAJqcGAAAAVlpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IlhNUCBDb3JlIDYuMC4wIj4KICAgPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4KICAgICAgPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIKICAgICAgICAgICAgeG1sbnM6dGlmZj0iaHR0cDovL25zLmFkb2JlLmNvbS90aWZmLzEuMC8iPgogICAgICAgICA8dGlmZjpPcmllbnRhdGlvbj4xPC90aWZmOk9yaWVudGF0aW9uPgogICAgICA8L3JkZjpEZXNjcmlwdGlvbj4KICAgPC9yZGY6UkRGPgo8L3g6eG1wbWV0YT4KGV7hBwAAPdVJREFUeAG9fVusZdlV3brPunXvrapudzduY0Mbd2wUY4xxY8fEjhXyAAQS4aEQpEBQpCBCFAm+IgUJRVGifCQKUiIliEQJ4iciH4lEABECRAgIwgQLgoPAMfgBbbvb/ayqW1X3UY+MMeYca829zz63qtyCXXX2mmvOMceca6619zn7nH3P2bh79+69hu3evXvt2rVr7fadO20D/UceeaRtbW3RFPrbt9sGDJcvX4Z+W/qj69fb6dmZ5MuXLrXtnR3JN27caCcnJ5IPDw/a7u4Fybdu3Wy3bh1LPtjfbxf29iSfnZ2269ePJO/u7rbDw0PJtxHz+vVryK21nZ3tdunSZenvIseryJUG5nj5CvUb7d7du9Kz3djcbFeg39jYFI54+m1gEJevXGmbsHO7ceMIuZ5KZlzG53bz5s12fHwL0kY7OECuFyJX6mjjdvHiPh4XJZ9ivEfgIn7vwoW2f3Ag/XRsOxjbJehZ8o1W63cJ9dvp9as5LddvH/Xby/odHx9nTveUD/PidnqKnI5uaPw7GNdB1pXzq7lGfWMmBW8Ni6HtbG1iIrdVqLOzO7Kc3b7Tbt9GUeF5ena3bd+7C/29dgrdGR7cToG5txELhn704XYG/MZmYiBbT98tPFgKcgbPPWDpG/jb5IGNmHsNGOaDJO5gIsnDhbF1b0P+zI35U881zfkl7+bmPS1u6u/c4Rg2xEM9uSL2GKdzJd55ELO1FXkwH+u3gdnxGAp+E1jquQ08x7alOt5F4syj1o/xWq9fjMP+zmme67ZjKHaMYQv57ezUXO9osR9e2GmbiHmPxztXQG7bPPJZSJZ4/+Jee/azL7cP/86z7WOffLU9/9ItOZ1hpdhve3tLydPjNgJzMNx2tjehj6OKZ5E8sbRtLCgfbZyAO5gkblV/FwuKC4zb5uaGbMySuTEGIzD5bcSY66FGbC48juqeFoAc0JM+B6sCR6pdvwEf5nonToKKu5VnhnV6juG2xoCzD7DbeZbkuG7Dxm1LY4iDQYsy9RwDc0LFgUJsji3rV+vh+hFF/X1zWhcbdT3FQXO4v93e/vTj7QPve2v70qefBGsUgvOy8fLLL2sF8Kj/0G892/7Rj/xG+7VP3GiPXNpqj+9u4LhDEkicheZ2G8XKOk70dzCQrONa/RZIUBttxNKHGwuzlXqqblsPG4vJjUjG5kbNdtFzAmmpeuKMp2x81dOnjo08MYWICzLmxY2L/A7A7DHsXE9MxU/GADzHzc169pZiUzfXMzaHTb3rR3/WLtcVahQ5WZ9l6vU4heLjr97GADbav/zOt7Xv+GvvbE++/jFwYl5feOGFe7u7O+3nfun327f/gw+193/FQTvY22pnGDGJlCwz9wYS6rhJaxOUf6J6xMs6RmwHX5cPh1ccYgiR7KpelBrAdAw5uMUYsK3oE8/CJpE0rl/BM2LYFmKbhojiM+GqMWZEjq0YGZtP7Vy8/+P3j9rf+9o3tH/+g9/YDvb32saNo2v3fu8Pnm9f9f2/0P7KF11op5h4Tr4OMBK7Ipnn+Q3ByuZ8mKwPiFUOge3pdOGcMPZz8RcHAhCrReziZrvIohbiK7lP/CtRwSh2ciiOeWtQ+9LPW9UtycbZp2Jsi5bnSFpfd7DdfuZ/X20//kPvbX/r29/XNvcPLrWf/5VPYHA4+WEwtz35TNq8U641PYKdwBxiIre0L2GrnTIeUgU2rNbNY1RGYvAoIfzENVTUxOsM6wbGmpIm6fpisp3+zIO70NkSXHDSAKhlTmic1AoXbbHJV9ihSWcokqvzFSDHrM1ZZBdqmvjUdfXmnfbBdxy2H/7Pv9s+9ofPts1Xr91qv/xbz7X3Pr7bTvAKMk6PJkqCcxtjZ0HlM7c5eRPa7v7n0w6OIY1cQqIlrMYYwSe00OkZ0TAlIsxGIvuRb4aR64gxdCHRkv5UWBQFd1SYz21oxmKj3liI2pLXfFUt7OAKOIDpwtcUu9sb7f88f9J+72PPt81XXj1qv/vccdvb2cz8zJpOJu/tjNyjIlyuczscTcnkCEosBylTqGSLfh6ZiY1BhCv9qZZjOqtPkPpCh4xwcVBwcstGvf5VXSLAEUvCPtTHQ1yCpQ5NSiEkUgwRODSUCdQGAZeuIbpFr9tpqdnVQQFkLrXsp29tg6Jwph/1dgDty6/iKu/ateuoWwTphRSQ2MHqctQqEx96BrATdF2fkwWbIsDAlg/D2cpW9O5DlTYsiHRga18KjBX9rqUbtmSxYygBruwFR3FCUTs9CEAYg0zQkcqwCW12VD/KE2P0zYGezIJAaT7qJ1s1VHkCik41U659dtk/vYs3t3bbJo9CX9aEd9lzwpAYH8qyjKOLxNDaFcQiQlFIhH0sImK4EReS23CzMmzqeSLFk27QcSy0+2zCGOSQD91LCHalCCH2qgZEkVAVnjGqgEhjO2NSZmBv5mC/6jUYKlKZTa+Dx2QexlYwK4pvNUwwxj58y6f7Tb6V6jdzgoJBI8I9Dkw5MGUK3sopymphs1OPMqgK2gTZssz0MUlgM2jHbsSq6H0zsn7KtMamBv2ab7yuKVVLUU1RB5sSlr/t4upp2mHkrMRkxw5J2U/jmME41K6iUB99hI7RFRpTd+wExS4RfguuHSW/BEDmm3XbfK/+mO9CAsVHXfk5lKwLHEVAUJCw7hQ3OOGhEqbPP22KHkbzGUqTdYIltoeR3RZzsJ8yG4KVBPXYZMKOyXkTDn3ZoEwfLQwvLuOJSVwsHJOk3jiqSwihohg4Q8CgGPaRdezmfraooOzMAUio5z632Tn9zjMLioqTa3ez3cJnCDj7r05BpUwfxXcOzs99tjqb1eAz2Vhzz2tEfcfQt/qnk1X0FdYKt8TRxj5H6cklWnJGyEYkmtAkkB47ddGybx624qUOj9hlm1iq51tSS22uuS+NPT8FDXgkgLiVRKbXuNMANIRNvred76qukConjJpwnVTTT0AXQzbYYbuXq4Cw8FWM3NGrLDaRemBDL19WmgI2NVmAsFnplr54wKinkwR1Pyei2MmrsNipBY9bYdDHFk9NYOnFB4ik2UiOINAnAbHSiSJ27Edy4WyM9MQz9/E6qrqz5n1MYss4wbx+X0kW5chzAxO/eXR01PYgKJ8ZZYRDCivGKLjhvcZQTOOZIZD16YUaDtyWFHpjixSTToeEScWN6ZpGT1yfQPYLEVNj1w+asSlj6KIioZvsES9GVbRWaDyVUEQJpD435uRAUOngSla93qBMOwovmHb0TY5CZRWtixt9jRcPONniKuDi3oW4CjC/28wuasMVKmbsAYh6h2bgHQP6MGUuk07qHqBRIQduvnDC4ryi50hulVskKwD10jnpPlnhv35vRiKGPCR7zjTidzB7AkNYyStYOcLZwhIurI7QW51uszdCdHMMFF2nNMGMDhcbPs3EVUBHDo4oV8/CawJtnJg0hlkOEc9RBxdDzrVLuvBYbxmMlOaMtkZ+/dRNGCh1FiN13zJODddlOPEw0SDRUq+tC+AbslIRnqDMS4dZeKlm5LJOOaU/1YTZli7RlBhSuI/W4gQ/65yHgY0fw+Mq4LBfBQz3GIRzYu5900B6TwJroQKjx5gdToKCrwu3Y6ZU1btbRMPezMn0NPW4ToRKbjLQkblIkzvrUtknlA7YjM1uKHOfrl2nGOyVcxUwzI+vr/jgvRLsc4vT/Ajh3EgbtQ4eytFHC2c+ZcqXQG7JF53ZnhjaaysIuEnKq4BbJ/o4vI91UCQzgK6LeFbI0oP62RaTEwbGm+fq3GZuy90FfgGTd2LuHQoRxVLPIoNP9E5w4p/paAAAyJYAF0ZcMWEUed/BDt5r55trvL/gGJ+vXD25226ifeUUd1GB6wQUgDTeQMf7EbhALuAz/T3cVLCLBzmkA2gXN8FQ5n0R5Dw+4z0LfB5ntHO2ambK7Gfq9mJ3m1cBvJlhbBUJmYPHJgh2YY398DF3ByCWowV2sIQ07w8u4rnZH+JqOCkZI9B+PUAfyskOY6YPPRmnePumMb3iKHN0h159MwoITAKPJt7FtIfJYqwXrp+1j7yE+yRv4tPVS9vtfU9eaG//4sP22OUL7dHLe3jOxc0vwOtGDywQ3cwCP965c+P4Nq7N77Tjk9v6SP4lcH366mm7hkl/7gg3dGAhveeL99oFLAr633cRaGC584BUMRYmFtU2rwK4+rq9SMT6dBU0gdLiwxFgn8kbQQB2i1epgbBZHCZEKLMkO+NCoMwJiH140o+Xm+EfViOMll/Ao0jkT05jpuNSEOWdbhmX+lw0Cmgrc+AdOjhqd7fadUzar34KN5DiA7Xvevfr2vd+y5Pt7W99ffvCJx9pj145aIcHF3Cf3hZuacPtdBGq78WIHRcSbyvju3M8KNmenN7GDatnus3t1q3T9srVm+1f//hvtN9/9qhdxk07+OT+wTcGzmAaCq4C9nAVoHsCXZQ5n54rHMIFhPdET97iWOIEbTWaa+Lj49VGkvUllAsGuiQOOvg4JvXEV4V0g0+ME7xcekFELv6xLAY8AouDSSAO5X1M/I2TO+3nP3q9fc2XXW7//u+/q73/PW9pb/6ix3F5FXdHO4PRBitTVYrYKSJWO4/mTdw0WjcunPn2Ez/1kfahP7zWHsF9fnceZAVE+kFTZWgYextbvwqY2XWUTU6IBPCIyKPBNVdXpjGZghINQbyqIHZRA6KxRadjQwn84KHKZ4M0q7EPKYjuffYyjHSQwxaccbahJmIHJx2GjpbwCSt7soKYp+8LON3/Au6b/OCbD9p//acfaB/86re1xx6N28DpETfEmh++UzKRyjp20Bkvc/TSzobP/3yaWHnKptH8plCyRU9K2yhzA4ZnnO0D3L+Ohdw5ujU9xrEISyeZTpAWCYoTucADMxaLA5r4L9qliWR1xtEb0cM35HDEvsdOvQfJLuThg44DDaVAMRba0RUfBW4mD4O1wxT3R+7huZe3cv/C/7vV/tX3fFn7m9/2VZj4+BsG3v3LjQcHJ5yv+jku9ufjM25JLxLyCBQ7ynGGIHeMghZtNdl1MoG05TAVF1cBx8drrwICyfpxMK6j+B3ENVMWZUEUvedBkBHf3WhNPtVOe4XTBuWGjkwTOzruZ/Lssmxu42ivA4HMbuYSuKAhBZ6Odcr/3LVT3Lq/1X7t33x9++qvelqp8CiKSTef1JNJr4uAct3c92Ko2Ip7KNkDoBNlbtapHzmwItt3cG/69CqAaALC0/OTJ8HgMSmhudnDS0HjXMAZ/zDt50PjMtPXch1XxA8rc47xxSiMZ8tX2/s4Wj718kl765P77Uf+8Te0p970WJ7m+Uqaf6uAarlQ6o1d1Xuyh3VVqvhVa2ic34rdhYphxHCrbDsdIW/hNcfmEf6M6wKe12irdmImixVEss9BBEI3V7Mec93axMnxGrc5t2JjN/SUqLXG2eXkp0NoA0OZt8o9d/Wsvf2Nh+0//LNv0uTzeZi14eUfJ+y8SauTvoSr/hVb5XlpnPlcP+l7mFYWJ81rXgXojiBP9NyH9aKODydvjFvyG2PZLY+qahvFJyK2OY/1ta2Yqqc85V/tc9x+BE+phMioneqM5zX7TbxAury/0/4tjvw3vP5KvAjjX2LQC5N/3kQJVHbGupbFJLHqqzzHTfqT1LOjAWCntqLTThVEzruuAvwXOgMawALvpvvpbF9i8NNDJ4s8ete+XZHCw+iN1dLDAP06ZLx0imUwjTF0IUWmOzjCf/nTp+03f+Qb2xvf8Ohk8unvCWV73oTN7dWPPNXXWLe0r9042JF6wqyEgTYXRNaiwBrmmWzzEFcBviMoGSZN5a/yBISObW7n9tfSX8e5Th+xMPLF5+VRkZC4x6OQUbN/Yav94h/eaD/2/V/ZnvmKp/Cczz80XT7lcwI9qUvjnNvrhK+zVcwSp3TMOQaxOtYynvAfYxR3XgXgE4o5vRVx+u52qvGQ1RC5hlKX0eg7nwnrBD+x6DQ01Sz0zvNP+BxS8wibzwHoJTjOEtnJxUI/Xuu/cnTWvunLH23f+o1f2SMsTfJ8AheyX1FVnioT6L7bFeeqYLKZvgqp5/Iynl6EBPZ+kPA8t8m/UJ1eBQxUSCTEgx2b3IoHnW5zNhGg7yf4rg3vRduUZ3IgF1MPC6ZlmgCv2KSgzRbKg5gv/D788eP2A9/9TLt8uBenyjz6mfR8crgI1h2xXiBLduvckrvK7J+7jZRXYVwM3T6TacDbFrwVYJNf5uA7gqYsUZwovguFBMXVmacuvaAz9UN1V7nzXBQsI5VzWYfPkDqBQpAIgviSFEXjH1E+hw9gvvMvfkF73zNxrc9TPzdPvCfJbbUJWHb0Mc5tMUs0LzuW12Envq4FW8tMNdKdQNVJvU4U+HSSX2Shq4B1DuLiq6iyBcdUR7Njui0uDynW0YTr0otHWpRfss/jygdUbCPbknMXuyAyFp1/NvWRPz5p3/Z1b9N7+nzuJ3edEE+SW6ZQ7ZmSmrme/apb7Yd35a58E9lz40LwaPWQ3Low7EtnA4YMG77VBR8q4K0u42qAAU0tQVAGemp1z23lea1yhl2kcTy3E1A6emzRukdkkUHAcwXf6n3TG/bau7/8qaQCBpUqyMkETuItdDyRnnT2qzxx4QTWQBPjQscvvLpPCi6G2+5aFIDym1a2D/bxWUC8jd1hIws4FJ+Y/AKTyKAVNLe/9v469nX6iIi8EsDGWbLlZh0l8/BDno++eNK+84NvbG/8wkeF41HCCfNESvkQO0+2XdjXgaqv2bG2tDRqc8v4fNMpPmRSLh1OTI6TA+NjuHXUEAKgnHQVcIrvCJJ/9ZqzoM//mdjcKvKi1Aqnsg9khF+V6MjN8QtRGHK/pF/SVacxsaF1LGOiP859eF8cz/+fefGs/bl3vVFXAjr9cwVgU+FTNsODts7UHPGaYp7P/dku7G7jhdtmuQ+gcKiE3BXdWsrAsELb/CYuf4VJ4D0ZpOKlE/pWyS9Oh2N+i50E5y2UlYRMbMO8n3rGXTFZMTeOfj3dkikuBDWILncdJld/Iocj4898yRMZGD7Qe+LEURZEB50j2J8Qf1fSCy9db8997mp76eUjfLPYib4r6BwKzQGrzjduPv25G+11F3EzCD+h0rtcMZ7z/BdtOOvz+41wR9C4CnBJWSpu9RiirWsHULi6s8lttX3e8lhtCxTzSKNPt76I5ckR0M5pj4XsUdFyjPfHn3nTxfb6J64ILdwsdl0MCTq3CTwhG/h7/M+2//Izv9N+9kOfab/2SXzVHJ97R7rLPJFu4PA08J63XGwXcZmq120+I3lYywwrWrnxswBcBUy+Jm7KM88MVlV0ilph/1NWnJdNHN1OKJYz8dymtvhg56WjO+09b32kXb4U3/3HQvEI9sbJrNu8X21TeaP95H//7fbN//BX2+FjW+2dj+22v/z0vt5ZnOLu37uFiZveD+gVss7XOS9UCipcBezoG6fGMAdQut41UQRkAa1h6O6Pgrkw3bXnNtdEf3qUmi3Y5x5BZb9xAMXxHD49L05en7Q84nXa7AjRscc7bl44vtve8AS/FHLc0hVHMOPFYvDYar+e5gVMbLx9vNl+/cMfb9/8d36pfe1fekTP3/wmluPbqJ9eCAb3GIkZllui7dERHACV02ElEAbpsasY3H3GNwE3+S2YGHdsc+bsr/Ca027s65EO2ejyCYXlPHCzOnpDMeU3yi38hpiuUw8yW+MXdTnd0oc7EXgIuEKoF32fw4ciTz5+qNuwPdH1DOC8bVvXp54YPufzxs5/9xMfbu98Zl9fwHXrlN97yDwiU2biB/2Yt/vOctKuFAPWDqCQ47RO4+WOilAqfzyN8BtS8axStglYOfYDSBMMqOj7URW+6oZBAxdIWK5yPhJnQ3QjgOQEdFlko1fN9kU71IGPPvYaJ1oEphh6O0YR3HOruuK+/UuHcSOmJzny9zimTPZdau3/iU+90H7sQy+0L7i8o/cY4mxBD+ThPJHhYA5p9IN9kjU7LmqYY5DSJXJuZ4SZjlE3z87wfbETdjOm0g38KfrNJ6PUFn8v0LXYieOfUIdjLYlFek4yBzILLSvOhPzG06WtngmqvIStuk/+8Uv4G4H4juKq15TrjRznZes027lVKL8BFJ1wJLAXX53QqxLo2yYt+riK2MZ3PuuzAN8RNJiifOyTSlty1sLalNVW14uMuMHSkX9qwngKyMQVeQxiegLOtJAwr7O9caLrZFfZGLbL+qjcCy/hC6RxhEVdQhdZhBw8ceJ3zqXqGSY8pGdR5YqdSNlCV4ttWa3AYc9FoAZnuz1+R5AiFMxgChZPaDzJZz7nNkl2LuZP3hgnVY6BUrRjbKxhjG81k6mep3JOsE/pFW+d22rLWrer1/Ht6DuMlrmAb0SY5jYsVQrW8Bme0jrIupLP9TN3cmzya2Lrd+pGuPDk3hz2Zcyl4tlDPsIAB3DgK+uqTE34h+1B99VHcVd4xjHF/GMMHomjzPvWs43Jp7R0lC/piK0bv+FbryqrEvI86rQfZwQWzyPoNedACa6DJ7f0yeJiWF9bytx4FYDPAjb5vfN8P0I+nbSkA53U/cm/g4Ko7CNJrF67U4j/BRWiIeyZ0e0cvE5v32o3bxQuerT7Ye6wGG2tGUe/Ht1VJmLeX1oQPAA82zVPT6h1Y6pH7CgkcxxnhGIN0QSEKVgiNDTs1EIne9iUd14F4I0gMyQo/dmYg7JQ2pnJzGGLHgEh8XWKLrnpnNvwsCbadXqjzrOv2iKHecmcGVtv9K196932hQxFnWzLnHDL9KmyOWpbc61yYELDhTG3Mceev4zYseWEV7ASLjq9WBQwQ1QwXXkVcIpPhMi+sFHtRaXv/5E/tfESyi6abHEAIKdMWDqjQjd6Dy75NDj3mA7H1mXtPPriEUeKOutJeb+JdeS1balDEV2qiZuzNy7asqeoR+jk3HWFyrq+dGxLA64CdvBngZs38PMn06sAA92aKScXBeL0O1Gh2JECZeVqyH5/1kgqqsk2tuhNdcN6P4l+w3eVy3a247gaHlnJaZhqTguP9KXT+9TxnJ5qY/sIkGUqY5iOJ/K2X7ZygsWcprPecJOrnyAdzXxdAyWuAi7gZ2TGNY8dV1of7RkUzWz65RH5YJ+xTMOuVWwDZ2v3smKlDd+p1wpIilUuavwYPsZxSaxaB25IPAMsnQWWdMNrnRTxq3VVUxfskDtOR1b22HQDWa1wax1NE6AmBlcBu/qFDk8S4X1LJQul7wDo/Y7Q5HJF2d9FUSgoF9IYzjPJHFVd/aue8pKtcvipgzrLI9MqVebBMD/y53173ffskJSRQ91HDs4vYLYHe9gsJ1FUHUpVeTaQqYc9py16uBNYnwXs71/EVUASCVUIzE+VXlBAKFCq43wiabIYuCi04NCGVeQTWe5VI2yiq1O4ak91NVWZAKfHSdHCJbqDUshGWJ0PRV283ecYglF8RSaiTnyVh/dcYkbgcxrMEXLkIULshGCnO488Ixc6iCm7UejgDm8axnnaFhPqvge8N3GMzwJ0FTBCJWTdzClgHkt0Ii5iKaC8ez9T0CtEyFk8aiNeAtHh6wYlrjZyiG/hIoabgqUIGeqhCQz7oQ1YFCIKFfhwYho8gwYe2HAPJ2p7nqnKxguBXctup8hZr/CrFL0PgYrcxMUuH8IEcMBjRFkpu8Vg6AJgd5V15l90wxlvB5/qKmAkQia6av30BMkOzATm1waBzqxHFnlkkc0vBp2SEx0xwtI5RobJZzsNEc8TXKHDHxGqi7yogzKb6jeBMrlztjrpPuqrbsW18mmBI1oP2IVwm6yQ6VQb6XYlTlFUDMO771aHIL5dhFcB2/wRRNwF1UGTWU4tHWOyIoqJ1ONE56Jhn5MtPIudm/ruoHU/2iku4lOXUwzRg1AtB7wwDs49DIaf7d9vI41RnED6tYP7+9anAsag73kLgX9l9KaLm7iLB3+EwZ/leQ3bLbyryG8fmeSAgcxLwgn2AaJjOAH2U3nAxd8LyDuCXApmF2ge3z5Zzwsf6GQt5DrC5OXwLLK5g5EWayJRYKCIhRNkYQ8rNXzYx5L7Gb4X5Rf/ALda8Ru68FZnDgVCbnSyg3VsqbsMh1+52m58b/wSqs2jaCgqF3pZ2MTYbvy8feXaSXv25661Z/88voaFeX2+G3J811v22iX8zaLuByQPxlPT0dByjK572HPQ2dQUti/gvjD+Tp8LSlYd7ZNiwVNHerjG9Hr6Bjkl+UZuGcdRx6pMA+oeNibJcA6ZWsFGXvaKdrAyNbyixZHBb+z66X/ywXblEsaE+/upf9CN2FPcvPHUFz0ml+pr2e3SIqDTXE/dt3z9O9oH3vOUPmauk0Xbw2yM/Z/+2++0X/7dl9sTh9vx+Q3rlkWrR/p4zoWxn5Jz7cNHtcO7f7oVgL99O70KIACTK5R2GQXpZj37CzQFT2V4AZQ+Gt2wsRurctijT4t11kz9iJhvQiaMReCpkbd1f837vxS/gBq//zv3edA+J5IF94TOZfNUu3Vu7fPOt7/Jqtfc/uTP/147wj2BTyK3+D3VqJyrxdaVjMUWPdYnpNzTiPseTvj6j1mZQBmiE5OfFhvpa1ktdlVHo/oJWrFZkfaeasZR8HU7+2QOpJptGiQGxu/T4wLwt3jMYOd2I0N+Xdvq5HNC121eMNXuxTH9xrCKeDCZc8V7FK7i193+4Nnr7Yl9fj/gKICy4g4qvYYkLeRUhf6cUNv81Wt+XWnfxO0A0Fs0gH2zu+2gGb4nSiC3QWaaVb3PArQ4wPAjhc5QEtJe8q9/yEm1Js55QOGJEfu8z4ipc0uct+prnXFzm/WRQ3xjGH2oX7/NqqK8Y+xHN0/aR58/bk/gBaXftvGEx+80oCqsTdI7isO5BMqBO10F4Aelb966hasAPj+PjQWO4g9dzAVQNBncE6x4Gg2gv1OxHP06zRVT0VMe+sc2xUx7xrjlxMwzqjbLbucTab3bdRO4Tm8/thWjvMqsRB8jZr75qL5Xr91sH331TN8dXNwE6RWggMF60qXnisAjFmIwKg/clcy7n/OzAHjVORNLDT+zk7NGkjMjVxoTsl0np0WZjnh+cTg0Vapg81b7kDlQF93tsE4l293SanneTj0Dx0mrPu7Pse6bc96vesoeIf+KqOHvFnhZqQUCx14JHPr240QrFbZGwE5dnCkyYua7GVcBHIRTSWJFdvg0FtA4gu2oiJlWxVPGQ76pH6EiRYUJHMXBXYAeTFclb+/PBJh9JKmQOWCiXKzqsTRh1rklvsr2p26Js9rtW/3X+VS9K6Z7C/tyMDNaFIwT23nRV6lVU5pTMFG46D5FXgVs8iqAPy/eNwETTSaK6hYMwdap1U4Uozt007mjPm1dHNzdqwsZrGMVJnYTTNFDFLwu2CIbWQttHdu5ft43dp1+iWOdzlzr7THIz710A99ZN57/Y+LDuw8NZdRrgCwnzx+0ae1Dpw/04KLFklcBegoY5ac1SLWnrEcqyaRHkqR6xckRe2tekY0AyTUUlhjHMsXsS2dD6sYly3CAZBQniQP2o4L6UQNlncyqr37WVyz5HIOyMZSXtopdslNHDuP4Z+Es06efu94e38cC8MHqxc9WeLSp0yIgETY9DRgbqsl+8wRXAXwRuLxFGYMEmFxqLq58mF1G5kRNbAKYu9rsEzb2bA256kUiu7lHC8mdgPWuo6ZaBWVR+fDmvnXztuIoG2/Z9to3x5Kt6uZyXWhTGz+1O2t/9NxRe3J2CRi4USv3qWFZojRZIChdKnngKmAXfxa4eQtXATs8SsJbbpOJBFoOBAgUz9Dcc2HYjz7E2drphCCKFuOJDE/7K0bqQh4MwTvtm8/aKQ/YofDRyEmxTPxcdvGtd0vs3Nf+FWMdW29z+zq9cUsLR8cWHG/iEvATz9/U28D8TmqtYQ0YlQFIldfrAEZB38VQlxipo4WoWPgsgHeE51UAkWOLqUq82MDQZ8HLI6Y/Ep9EBBH7dKib/WgNPFsvicEQOGPMMOzUBCYzFGQezX5CYwwuMAtumTbKftjHdraeIPPYx9h5a7w5qp+xldfyPK/AxqivHd1qv/3Ccbugvy8wCyscVVIN+1PhvBKlcnMTqDb39vamnwVw0PjH4gY+vbysWLC0qEn+iU45OvA0Knt82MreYLRVBMLZe1iYX9FaDJfJ/rxJINCT5dZ495cmhTrbHWzet97tEq9tbKt9iYu/FHL9Kr7Io7xDaX9MRy9olCIqG7KNgfYa0VTiReDZ6Vnb5gKYXAWYmUUOlojgGZN3IRYGu24nPB2powktNXWROBkZYBcUIOoph0dIllcxxslhZTcv5rzvwtuRduuMnbfGurXdfbdVX2XbGWdJb3ttX+QVAH4yyLnZpnpkiVRyyL2uAo1DJWGpRQ8fBp1wAZistjF9APHlJDv0DmXC4hxB/TwpATTj6cCiJgm9pCUftqD1GSd03lPLLTDpYGO3eYCT5ITyGnShF/PsfCEYU304SdYbXnXVZv28pZ915mC75Es9sbHFuJ5/4RomjIZUu00VUd0Fcq1GgXb3ZFGzeYxfkOaXIvetelA576uygY/9AFDqvZrR0Eqa4BQ448PH/hVjnaAT3hFwYDKrVNTCR2HDUIsvXlIxfvLTbrnqiZ3b7M+2+oR+ZDZ4RpwV34xPrBfxZ56/ji8vjl8KU4zitDiOYq/LIascByTeCuaLwG0tAFh6mkTxFSUa7eWVrqEUfWqEsmJ6+hkI2XPnswG7iomdj3aN2BNQnbovBfDyP3DyzzCONl1CofWk0Dvo5clu3yqmK1OoRV7CxWQ5g6n3UrwcYl8s1cOZEcMPtvg7Qc8+f9Tegi+G8lsAKkDOGMc7IlMKBvO4zxjWaWF5AUTwQRGoQiqvdKWnWeg46VdDsA5wJBZRAsd9iRoOGHVdIGaZtvDMdzqqv4vKewK4+Ru5pr4P1luaUOvOO/ore4yYJapZVsT5st34DSOf+Gz5ZjC48R091Y+l4KNTQcrAPT5stlvX4RC2L+JF4BmW1nKa0NrLALQ+CvoRnxgHYoCA89gmdyZcI0MmPl27xX0uhPAiZi4H3ItFPHBkMfi5OX+f7wzff6MctOv0E8GxmIgnlr/vd3Fvt4+RDh6vF4FJ7ON+bSMn/OAEruFv4+vdIpmKyISpWsiRXx+0izucPvv8q+1TLx23R8vbwOTm5jZ6Y1/plEfHxoh1sOBF4ClfBF7gVYAPn8EBKWlkg2wmWYKopyAbpsNYgSO9ZDFbj2A9OYZMs88CPQNoKmbYFR9hODH8udUTfP/O9/7QT+NyiWeBiN8DniMQyW8I//VP3Wg//Hefad/+Tc+I02eR+cRXqvMWAXH/8Sd+vf3oT32sve31+MwFt6k96Mac9FOxGNMhrv95+tdCrMWCzINQJ0Q65EYxYNyjlz6CYKcDC5ynZ0tXAQBzHuUzduYubbJmQwMD8FjtEWljt28xlcVFlnqkU7GKCqLBbNKqj7PEi/hlr8k67LHXCKAg/hJ+PvXTf3x83y9trCxeGOctAp7C/+9n4wjmV7w98BZDw2LGaRo7xaJzzvaoBaqNDn9cWgOBTFfupKeggoSeftpS0ItA/nFo32Qo/W6AkETx3B/TpvsDE67GiSgwnUlIS0TUAgGmDwg2n8oLTPjMUWooejv4zElryBdwJK/JnqDFjcOiH19pczLrpqMOCrfVVrHrFoHuUMJdPOKvzg8oM7f4XkAmgYefdyFzLTjbqCtJU9PnCvNEP26xIgLBG0LwZ4FaAPzzcGOES2AEdAgSTMmjAJmJGRyN0C4TEzHEAH0wJR+MjB+v7K1jJkvbql2+Cb2HcyXZg3HJv+rIFUi9wl5zgNaJpvd8Mcz7NYIGBl5i+FKA28gOSx8pDP/Ixyjm5q3f9mUFW5vFQV6qrExgeX7o08GgWAD8pvh4yZzY3oiDdNgo94fJtd6gR78GSCjdaLNbzckMboM8kpdfgqfP9AMd+NqvvmYLe4wgxxHkC/s4/wzDjBvF8gS5NXbet37S1vB59I4IqJFnRU7D4pFMuNDpCOQl6spPcOpt41xrAVM/wQaTbgjh19hMbLVHAxNXmyg0kqRjVG6RUNdLkzjZkyLlaMgrj47wdFhbQyhl4dNqUPeexoshxl6QGV7lzEnp+SSXm+kEWTva+9kHEhJTmcSbWKNThjZJ137g8Lj4vE9ZawjgoS8ytMoxD0gGEQ5PebwK0C1hZ7NVWI7dYFeU9LRspohq2iBPXTcRm5t1HBxlJqdWdsqBiH0OMH1VEOETFaD0SL7ETpaCK0l8yl53NnW3NUKdaD8lsLW8xu0B1MjAyRBdxiSRCTrJhI4uzpOJV6A0sJFIm+12oorzjT8P51VAPgUUa49GSuiVHCfCTNRzow8fVc/j1/p6LFMX25AGg72MMANjWrZ/xQQD9wM1+EteFA2BTNEqc0z51/e0YPOAqYtivcfMUtIKCxTJV5FZ9kg0fZy3KdTmuLgQKPYNneijOmnwjHQMBN0Qwr+L7NuEpWtjpdPmB0sorB3Ypq6rLFBvma1l8lfZvdDVPZGxeRj2c2tf42YtUtCsu0FfLxYnxSfX4OsO1Gb+bqF68I2xc6vs1tXWdr3oK37MXalWHRzdZdvl7ER/nC29YDWGvArQLWGTqwB4MYk49tBx1CRVlGAOWz8HpZL47mMnEnYnsbuHjvrRAtYDGDHOPdYElr14DMSwmI8txxOFdXnDGk8wIS/uS0AXj+3SIljSdc4SdlCOrJwN22FnnM4gWR7YFXUZ29BP/IggqZyDT/54U2r9VQDQAokpPQvBSAuSrgJCE8nLEwq3E3R0wBvWVUxYqB82S9GOEpl5rhcHc++OOdVYrLU4ZnIbfKXHPNOBrR9eDLY5j/u3TqginSfjWq72UOuAnLuXVOlRjzub+sFBhZUEZ3HwRZG8Ldxd6wtyHjT7U75IPEzhy8BKWsEioCwCmd9tglTs8HS2ZX1l/pmAXGpEeyQXq+GAPvtQhUcsssip9sKz8hMvkt4me2/uZ+/AIoysWSE8IgQQTNBAWCyzpQnFCB0YWJieKgWOKlozBKCDhKFNHHgrWF8Xv7sbfx4+nCilE5FOwoDMqhfR/HWmkiGPu/TM5aDB2MmkhsSiCWvuFb9qqk8kt8pW9VVOZFZcxV8ZYOUPeX7kG+Gngwc6EyiNcUgwk15DyZ7CMdY6rqhljCUWHWR22WhO8sCBU3Azy8BTii36RPIqQH8YYtNymynUTEhvdZ4el32tJbgSWE49mpFmtdE/+kpYcW2nD2XbAzusLm1gyD9iEFu2BxiDj/LiJbFOfJUnOAdGKsxKeWeiMa5AK8cxACntGsECpxEVHDF9CBBoGn4FSPcOZAcbzNu8LXzydwF5hA8mJA2dqMmXEZh8HEgO0qdJCVStp4Mx5UcBm5LPbCVLEzbvQx9opmbe0BgVvO7paBEQDulDHnao9hCpG19eRTu3QIY89qoBCjhfDO6vXQCDgsEm+XdTH9SI7TpZU8fu/O3f+xA6Xkb3Asn5oka58iti+EWR/MOQyVWAU9QpPTLrk0+ejNYH3JPvQkTjPldkp6QK/1iGUYripxWq6ROH0x9YDoD48Sje8uk7OieBBp0G+lcf9h2n+xbB42TrRVDMEo2Z6yf9zKde3jkT5cd6z55G53klBWjrCCZRemcJ4eUhG/88fHwWUOASuctwxSR29JVrX3bQJsZQtZpM2yJ0t+vUkcOzUuSdKnvRGMJ2TNf6qQvLQJJlFHNIwU70+s1H+Lxd77HGoiDcjWmgpOhIyVpX4Lyc6mhWoqXjfJQruFTo6+J5W3gPaE+ueGu7Mbw4f1690tgnSaOLPU9J7KR96D3MdHBDwP0G4IWVtEltBrmLQoss1JNc088WBpxzdLIUeIT7UW1eFFV3vhyRYgge7Cy6a+12ibDaLKPVOGd0S+7KG58F5FVAfFXsChAzJ27O4ITUEVOtGR7ehEYiA5ca8Q2qtENRkdNYU5t8k4A+fjC6OcIc+66ri6E60REBjYsRjZ7MRMzGaP0DnfoNJg8eXr85jOhnThF55LOaCce5pA3ycRZh0MQx4MxFsXkVgF+NxZvAToVO3pQqOgu2Xoy09QAjfEjFFwmUnoIM9LARs4qLnKynX/X16GwnmjLnvOqCJY2lM63NtNdhKXAhPOykrxS/JxWxNN3U8ZHhBem4DN5txZC6bBIYjf8UXKfgdFnKffPmzVv6uvju3dlc5q7okLDM1iJgRrqlg+Sec1g46IHpRqAp1z4ZuA0dPflvIIctsLGP44hR8OiQjNr7xWTnYrOKhVua/HVnBvupLXwxanKFNOyRl46t8kKwuCrRHM1IGoBycuNIx5bOVed8FR1XAfzp2E1+VSzOBqNGoohQsWLIhEcS8pxV0oc+DdnUgCMbLw5Pi8mIGGyWMnp394KZcxtvFp+MAgcvVIe6UZmIK52c5oyw14pmBp78XsBOEADrEz5tagjJkRdByhc650mzDi4K0hM13cr6yLERCAweHJ040XGFWTtvPgMofXxvJe+eXvzTsD7bijYIRKQJty5bRaOsFCIhgqXnLvXUZWqhgY/c7MvusizXsptOfhoUjzKtKKX6VpKX0VESqNTLxWuEAGEJcbZ3AT3h7lcYdbZXPeWuR0BNtM4EC9Gl0gg6Ra8KbJzAeFu4LKaOhA12fwG3xik8EyigFPXTsZPPAgAiborNnhpRJsIoDQe6YlNxq55Y4weSKqNsnyLDPtXRIzTcx2bN4ItFUpfKiBt+zNc5k6XKwbo0yWEZ+z6xUFV5IEJyJoxdI9cxRApxBPdsIGhS009sPLsRTGcYcy0LEd4RQ9yzgMLu5mcBOzuzqwBwctCR7EhNiSmj1HEZ8pFbBKUNj5nbRGEHtskX8WyIk1YwBxFlP8wlu/K0Jvw7TrmRy8mwxaMDMp6IUu5Y9+GBaq1bBJ5s26OdEA4iSFyiDh/ZRD5MNbNLfOCoM16sxPFBA7Z7WATqk1cA8qSROHhLnwGcrzC4E5xXAXgKSIfgzK5Dh1JEtislRu8KiVwwHuCwUGJmAY69kVSnZsIV+GCjf2WgHHa6LDxdZy6kLqSFg2rWwyyrHNUv5DkXc6rb/ezCJm1lp36WZu+PhTswmsxKAFlzi13NgRD/kU5fEEpidbd580b8aFQ1jRhRqR5YzGQvjxSRptTDaMbKFtNnC2kCb429IwDRgbHeuKEfDBVtXLYg6VmQEB31I8wMPO9GBj7K51b372fvA+kOFpZbHtncet6U0eFcpKkLWizU20AnycWb/QQo134VgBsDt2AoUOMiPA2KDIGHC2U/YEJH+4yYcuhsSWViqa0TyP5AhmTd0E85Rm9I9qGmViPSVj1cIXWccXZERHnap4snl60fgufO9qpbLyc/05U44g2J3oyVLGzxUDf9pCrl6Tb5qSdn4cIdlnCQFZ8FbG/hNwwixIypd02UNFyWyir74TzZxykn/GI/MWfHJ6a6EMLkJHO4S87QOUHzzGE4G2GRTuKjI267imWCSJICsIYLHls9zbLPiZ/rqD9v65NK0GoocdLkTymFB05PVUw3U6ZrPP8TnZvGODqxMJfGCEyqtw8ODvpPx8qVg2VUt+Zjay630hFrGya0yDQPm3p9pwGKJ8lUZMjZDT90uj6J2XAjDnIUKIXeJ8DAIlFlfrXzBTR8yLC0ccLnR/ySrvuuUIYi0weMfNgnjhl50q1zyuSc0pmFS9u8IdnS8yiCEPgs4BifBG/yI8H69ePCOXJ0RnYmYSw/Jjoo12abDuSe8JOLNmx+ilGn4ihDOcERlHqJAlBSDurVXFJvFVuGc5/mpc1HuFtiLLs990ywFAA65qfgRZZO/GljQ/982E5nqpIF3bCEjraQRtspwotwvPvHH49eeCPINMJih74Oa/dDVXpD1FIu9glV6VD0ZNLbfkxMNim5iz5b42VPLlWHNvTtp1pEQbIu9I5aAZOW0Fnfe8nb+6uCj35OfpUH0okMTZVqeqvJAOnU2Wa+PavUedhdD6AXQbgjN1GFg22xIALBOOxv3phfBYg1Qc5GdHUYM5k+zsbtDNK73d6FMOlwRFyHprmeETjq7qLsO+Vwok9Rp4tU3Jk7YZzACpdnwXDReZLNyon3kV/lgasEjll0RTSnkshEPLk9F+PRhk2vZLqrzR4HRzRkwmIxhC7Q+lEtXgXgizA2z3wVYCa1U4oe7X6COc7DEWPcioy4Dj2xoVP7rlLXwYkyN54pNLFZCPKRNtSCyCI8lVLlbtZ3HFKQs/Sr1zq9MOIfQTw9Q8MUomcd2y53ISJy+kNV985mBi48RvQWd4Jvrb0K6KiHFBx/0U0Vj5EZx9YyBcvWs+D9QVIDSoCOTXNOEk97XAt8cGPZJKsfJ0XdnhXm3C/wp8VH/XwhnDv5E253YgIzLSnNzc7QRy4aw2zcHlPUo+asUSdHFGZgHb+0CLZ5eJhXAebpGXSheDykOInuAOdwzEOqz50NaN1lS0r3SVvkGq2nQSUe7Gud4LTg44nuK1s6zid9jqtPBXObcirKnmJNkHYauGXrzALWlcqX+eQSDh+55eD6YkkfjrfTJhsV+LsAXQVs49cjJ1cB5unUDyBkrAmSujwap/olMBHQMzbNFVL75HN+bLm571lmX/4BcArqQS94mNJ1HkyssUtnH6HzliDqHuYs0LEMizw0pGzJl6mhHUlaJ3wWKHTcR/7GjKcIWmJ520Z+blo8+CwgrgLq+MMqkFKxbc5gnPVujU+G3kz0AKuPnV+9C2h9eq34pIIVs41xLbtgWgg+QnjaB4A4AUOv15by5fN6J8jAtUGpZmZPuBdDRT+IPKFDZ9IHQQxvMrCk5ZKI496ShiXrYAmp9gO9lBst20c3buCHKAZVAEkA3Vy9xGJdumSdY2QqfuHpeUHIo2tUwARJyNgd7yAP0kbSHBwJRJE8dbJj3u8XACxBt/ZI1+l4vkrWpKmMZlhNeEkjzPnEFEMIttlCzbQykoE52eTrgCBXN+NMrgJu88ZAZFFySO+pJiONpgeAilDnMBCprIrk9KjtJ0glhELQxFeKc2Xiw4dTv+i9oqxxqzwCzY/6paO/n9qH24q0EprZQumo0xY92Ogz/GJZD82wRLDsm6hkoIVVFxHuBN/axB1BPXFz0VnyAksh7CKx3SdlGhfdU1n55/707Rvw5pEPDG6tN5Z9PqX0rcpcDOgrFnbJoXKaz36z/nyy1/XnetPdv8XBx4kpcSlqOMVZ9xHmBAqaoJmrHOs882tkVIlO6EDStu1DfBagbwo1oLJnkChcyaaK9rPO/O67jXjurWkdsJjX8c2hM9wIFwbBh7IEmIk8O5WtnuJ9sDzUZE/pwExFTZZLs+g0YbZDj0O3pmRLKLGwzQ9DiNhrBaSBDhIJgIBG+eOOIF0FXL580J5+3S6+xTIDEayI9MwtudxdaeUD7Xm4Qhf+RdHFQiDRBrYOshJ9QeEngHgaCBbI8QSr8rNwOvLq4RKWzke8fai07IVAnWW31K1uHgctVQ6k4tiimOxgPpwvXGIktQqxcHpVupD89MX/WDypi3CRAV73HR7gncDHX3fYPvDlT7RPXcXXhuIDAg1SeDI+5OY4PZn0X+rTdF4Ic00K1pWzxOb6NcRQdySEydyLcY3fPFpODNVeFDPI6Crgg/EOJ0g11wV3q/p4spjR59NKjFX9AdKCZfpPHGy1p596DLeFn9xsf/UDT7XPvHC77fGvRJe2QjDMRanVhv6Ke2LYdLg7mSEJ5Wd99qWrhElAVcfTeb4Fzi+X2PIoiH7wiSJ3yVpIAkNFHD21P2Q7+MhfuxAmLswlFWzwYD8e6obdEGMCqpAeXaC959kgthgn9eRNu1p83zBe+B3iS6f/5ydvth/4hi9p73zHm9vm0Y1b7V1f9sb2L77nS9vP/ua1dnhhSz9OxO+o5Xcu8wpxA63IKOMhnRKPABoAlMIYy6SJMY/11GVy5B/c9OcjYqiVj/VoEUOxzW0sY3euwmF98gKiKx7yOBa/WNayb4+JUq7u107yKnSqUZ6ZO+uH+LzyUmwgocqaRO6hh4x/I7/Ik36qjceuPpHmKPUrmB2c3a/sb7ePv3jS3v/FB+1v/433xlVAhL/XvvuvvxvPCXvt+370I+0RfLft05e39A3a05FEb/WogX5RGfq1prWGpagLXPZ3O3db0i/oqNLk6vtiKyCKHSe40BPHBcOtLgjqal8AY8Crr7AVkS1r2hrekCWdbUvtDM9hPYun+E9+5rR9x194vP3g972vveH1V3RG2L5y5bIS56r8rm97d/uKP/tE+8X/9Yn2Wx99pf3Ri8daHzHciFTHAJe+PYie8KwdYo41M9EDQxu3qmdf80MBW439WvTKB/F27yLabZ4mg5/7pQmd641xO7xD2uCp6Q5uwcaT8gli5NBkZGyOkVsdQ9VP6lTw5Ol1qnoY5voDfBP6t77jsfZ1H3xre/97n24H+xfatWvXNT680Aw4nx+uXn0Vfy7EnycFycYOvkoUfz+ElK9fP2p37uBnq5DupUuH+BgxfsHo6OgGvl79DPrWDg8P4bsj+ebNG/A9lby/f4CfKd9N/S38SfKxirCP3yzmL5Yx+tnZabuBdyS57eDXLHmbGmPxTaqjI/xqNjz4mQVjUH8Xd7JcP4oB8CPNw8NLWlgcw/XroeeCvnSJ+jgyOYa7d/EjEuhTz98C4ImT74QyPreLF/fbFVwVXb50ET/0cLOPgb+vzB/Z5saf2OGDG3W0ceMXbfDbVrjt4ps3qGesF1+6hscrOu1zbBwD86SNY5vXjwvixqR+++C7gEzxA5LgZ/24kZ/148Z8GJu1pI5f/MUin2AOWFfO6ROPP4JxsX4wAXjt2jWMGy/8x8qNpE5O8M4give6Ry+j1gzb2sHFjXYHv8DBLC5fhj6fLC/hp0z5daPcLrPYeGeJ2/Hxlv72nFlwwFtbsTBOD3fareOQD7AwtvFHKdzu3r2NiQvfKN6+9PfwsxnXERtjaTtYAPsHMQDy7kPPEXMBHGABeDvg2FlgTPClS8w1No7hLr6uWwvg8hWr2yW8GmahyHkJPJta3KS+pwVI4N1yWqDMhcmNuXqreC5WxuH26COYwO27GgN/pOniRS7u2C7h6+mX6ndpXf1Olut3++wCFk3c3MWFsbsbC+POnTMsMtSVdUI6XHgcp3Nj+/8ByB4/N+ev/3AAAAAASUVORK5CYII\\u003d\"\n  },\n  \"description\": \"Tag that send the event data from the GA4/Data clients to Facebook Conversion API.\",\n  \"containerContexts\": [\n    \"SERVER\"\n  ]\n}\n\n\n___TEMPLATE_PARAMETERS___\n\n[\n  {\n    \"type\": \"GROUP\",\n    \"name\": \"configGroup\",\n    \"subParams\": [\n      {\n        \"type\": \"SELECT\",\n        \"name\": \"inheritEventName\",\n        \"displayName\": \"Event Name Setup Method\",\n        \"selectItems\": [\n          {\n            \"value\": \"inherit\",\n            \"displayValue\": \"Inherit from client\"\n          },\n          {\n            \"value\": \"override\",\n            \"displayValue\": \"Override\"\n          }\n        ],\n        \"simpleValueType\": true,\n        \"defaultValue\": \"inherit\",\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\": \"AppendValue\",\n                        \"displayValue\": \"AppendValue\"\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                    \"valueValidators\": [\n                      {\n                        \"type\": \"NON_EMPTY\"\n                      }\n                    ]\n                  }\n                ]\n              },\n              {\n                \"value\": \"custom\",\n                \"displayValue\": \"Custom\",\n                \"subParams\": [\n                  {\n                    \"type\": \"TEXT\",\n                    \"name\": \"eventNameCustom\",\n                    \"simpleValueType\": true,\n                    \"valueValidators\": [\n                      {\n                        \"type\": \"NON_EMPTY\"\n                      }\n                    ]\n                  }\n                ]\n              }\n            ],\n            \"simpleValueType\": true,\n            \"defaultValue\": \"standard\",\n            \"enablingConditions\": [\n              {\n                \"paramName\": \"inheritEventName\",\n                \"paramValue\": \"override\",\n                \"type\": \"EQUALS\"\n              }\n            ],\n            \"displayName\": \"Event Type\"\n          }\n        ],\n        \"help\": \"\\u003cb\\u003eInherit from client\\u003c/b\\u003e\\n\\u003cbr/\\u003e\\nIf the incoming request follows the \\u003cb\\u003eGoogle Analytics 4 (GA4)\\u003c/b\\u003e schema, the following mappings will be applied to convert GA4 \\u003ci\\u003eEvent Names\\u003c/i\\u003e into the Conversion API \\u003ci\\u003eEvent Name\\u003c/i\\u003e equivalent:\\n\\u003cbr/\\u003e\\n\\u003cul\\u003e\\n\\u003cli\\u003e\\u003ci\\u003epage_view\\u003c/i\\u003e → \\u003ci\\u003ePageView\\u003c/i\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003ci\\u003egtm.dom\\u003c/i\\u003e → \\u003ci\\u003ePageView\\u003c/i\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003ci\\u003eadd_payment_info\\u003c/i\\u003e → \\u003ci\\u003eAddPaymentInfo\\u003c/i\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003ci\\u003eadd_to_cart\\u003c/i\\u003e → \\u003ci\\u003eAddToCart\\u003c/i\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003ci\\u003eadd_to_wishlist\\u003c/i\\u003e → \\u003ci\\u003eAddToWishlist\\u003c/i\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003ci\\u003esign_up\\u003c/i\\u003e → \\u003ci\\u003eCompleteRegistration\\u003c/i\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003ci\\u003ebegin_checkout\\u003c/i\\u003e → \\u003ci\\u003eInitiateCheckout\\u003c/i\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003ci\\u003egenerate_lead\\u003c/i\\u003e → \\u003ci\\u003eLead\\u003c/i\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003ci\\u003epurchase\\u003c/i\\u003e → \\u003ci\\u003ePurchase\\u003c/i\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003ci\\u003esearch\\u003c/i\\u003e → \\u003ci\\u003eSearch\\u003c/i\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003ci\\u003eview_item\\u003c/i\\u003e → \\u003ci\\u003eViewContent\\u003c/i\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003ci\\u003eview_item_list\\u003c/i\\u003e → \\u003ci\\u003eViewContent\\u003c/i\\u003e (conditional)\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003ci\\u003econtact\\u003c/i\\u003e → \\u003ci\\u003eContact\\u003c/i\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003ci\\u003ecustomize_product\\u003c/i\\u003e → \\u003ci\\u003eCustomizeProduct\\u003c/i\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003ci\\u003edonate\\u003c/i\\u003e → \\u003ci\\u003eDonate\\u003c/i\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003ci\\u003efind_location\\u003c/i\\u003e → \\u003ci\\u003eFindLocation\\u003c/i\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003ci\\u003eschedule\\u003c/i\\u003e → \\u003ci\\u003eSchedule\\u003c/i\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003ci\\u003estart_trial\\u003c/i\\u003e → \\u003ci\\u003eStartTrial\\u003c/i\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003ci\\u003esubmit_application\\u003c/i\\u003e → \\u003ci\\u003eSubmitApplication\\u003c/i\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003ci\\u003esubscribe\\u003c/i\\u003e → \\u003ci\\u003eSubscribe\\u003c/i\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003ci\\u003egtm4wp.addProductToCartEEC\\u003c/i\\u003e → \\u003ci\\u003eAddToCart\\u003c/i\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003ci\\u003egtm4wp.productClickEEC\\u003c/i\\u003e → \\u003ci\\u003eViewContent\\u003c/i\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003ci\\u003egtm4wp.checkoutOptionEEC\\u003c/i\\u003e → \\u003ci\\u003eInitiateCheckout\\u003c/i\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003ci\\u003egtm4wp.checkoutStepEEC\\u003c/i\\u003e → \\u003ci\\u003eAddPaymentInfo\\u003c/i\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003ci\\u003egtm4wp.orderCompletedEEC\\u003c/i\\u003e → \\u003ci\\u003ePurchase\\u003c/i\\u003e\\u003c/li\\u003e\\n\\u003c/ul\\u003e\\n\\u003cbr/\\u003e\\nPlease note that it provides partial event mapping. Not all GA4 events can be mapped to Conversion API Event Name.\"\n      },\n      {\n        \"type\": \"SELECT\",\n        \"name\": \"actionSource\",\n        \"displayName\": \"Action Source\",\n        \"selectItems\": [\n          {\n            \"value\": \"website\",\n            \"displayValue\": \"Website\"\n          },\n          {\n            \"value\": \"email\",\n            \"displayValue\": \"Email\"\n          },\n          {\n            \"value\": \"app\",\n            \"displayValue\": \"App\"\n          },\n          {\n            \"value\": \"phone_call\",\n            \"displayValue\": \"Phone Call\"\n          },\n          {\n            \"value\": \"chat\",\n            \"displayValue\": \"Chat\"\n          },\n          {\n            \"value\": \"physical_store\",\n            \"displayValue\": \"Physical Store\"\n          },\n          {\n            \"value\": \"system_generated\",\n            \"displayValue\": \"System Generated\"\n          },\n          {\n            \"value\": \"business_messaging\",\n            \"displayValue\": \"Business Messaging\"\n          },\n          {\n            \"value\": \"other\",\n            \"displayValue\": \"Other\"\n          }\n        ],\n        \"simpleValueType\": true,\n        \"valueValidators\": [\n          {\n            \"type\": \"NON_EMPTY\"\n          }\n        ],\n        \"defaultValue\": \"website\",\n        \"help\": \"\\u003cb\\u003eEmail\\u003c/b\\u003e — Conversion happened over email.\\n\\u003cbr/\\u003e\\n\\u003cb\\u003eWebsite\\u003c/b\\u003e — Conversion was made on your website.\\n\\u003cbr/\\u003e\\n\\u003cb\\u003eApp\\u003c/b\\u003e — Conversion was made on your mobile app.\\n\\u003cbr/\\u003e\\n\\u003cb\\u003ePhone Call\\u003c/b\\u003e — Conversion was made over the phone.\\n\\u003cbr/\\u003e\\n\\u003cb\\u003eChat\\u003c/b\\u003e — Conversion was made via a messaging app, SMS, or online messaging feature.\\n\\u003cbr/\\u003e\\n\\u003cb\\u003ePhysical Store\\u003c/b\\u003e — Conversion was made in person at your physical store, helping to optimize your omni-channel marketing strategy.\\n\\u003cbr/\\u003e\\n\\u003cb\\u003eSystem Generated\\u003c/b\\u003e — Conversion happened automatically, such as a subscription renewal set to auto-pay, often linked with CRM CAPI for Meta Lead Ads.\\n\\u003cbr/\\u003e\\n\\u003cb\\u003eBusiness Messaging\\u003c/b\\u003e — Conversion was made from ads that click to Messenger, Instagram or WhatsApp.\\n\\u003cbr/\\u003e \\n\\u003cb\\u003eOther\\u003c/b\\u003e — Conversion happened in a way that is not listed.\",\n        \"alwaysInSummary\": true\n      },\n      {\n        \"type\": \"SELECT\",\n        \"name\": \"messaging_channel\",\n        \"displayName\": \"Messaging Channel\",\n        \"macrosInSelect\": false,\n        \"selectItems\": [\n          {\n            \"value\": \"messenger\",\n            \"displayValue\": \"Messenger\"\n          },\n          {\n            \"value\": \"whatsapp\",\n            \"displayValue\": \"WhatsApp\"\n          },\n          {\n            \"value\": \"instagram\",\n            \"displayValue\": \"Instagram\"\n          }\n        ],\n        \"simpleValueType\": true,\n        \"defaultValue\": \"messenger\",\n        \"enablingConditions\": [\n          {\n            \"paramName\": \"actionSource\",\n            \"paramValue\": \"business_messaging\",\n            \"type\": \"EQUALS\"\n          }\n        ],\n        \"valueValidators\": [\n          {\n            \"type\": \"NON_EMPTY\"\n          }\n        ],\n        \"alwaysInSummary\": true\n      },\n      {\n        \"type\": \"TEXT\",\n        \"name\": \"pixelId\",\n        \"displayName\": \"Facebook Pixel ID\",\n        \"simpleValueType\": true,\n        \"valueValidators\": [\n          {\n            \"type\": \"NON_EMPTY\"\n          }\n        ],\n        \"help\": \"Set to a valid Facebook Pixel ID.\"\n      },\n      {\n        \"type\": \"TEXT\",\n        \"name\": \"accessToken\",\n        \"displayName\": \"API Access Token\",\n        \"simpleValueType\": true,\n        \"help\": \"Set to your Facebook API Access Token. See \\u003ca href\\u003d\\\"https://developers.facebook.com/docs/marketing-api/server-side-api/get-started#access-token\\\" target\\u003d\\\"_blank\\\"\\u003ehere\\u003c/a\\u003e for more information.\",\n        \"valueValidators\": [\n          {\n            \"type\": \"NON_EMPTY\"\n          }\n        ]\n      },\n      {\n        \"type\": \"CHECKBOX\",\n        \"name\": \"enableMultipixelSetup\",\n        \"checkboxText\": \"Add Multiple Facebook Pixel IDs\",\n        \"simpleValueType\": true,\n        \"help\": \"Add one \\u003ci\\u003eFacebook Pixel ID\\u003c/i\\u003e and one \\u003ci\\u003eAccess Token\\u003c/i\\u003e per line.\",\n        \"subParams\": [\n          {\n            \"type\": \"SIMPLE_TABLE\",\n            \"name\": \"pixelIdAndAccessTokenTable\",\n            \"simpleTableColumns\": [\n              {\n                \"defaultValue\": \"\",\n                \"displayName\": \"Facebook Pixel ID\",\n                \"name\": \"pixelId\",\n                \"type\": \"TEXT\",\n                \"valueValidators\": [\n                  {\n                    \"type\": \"NON_EMPTY\"\n                  }\n                ]\n              },\n              {\n                \"defaultValue\": \"\",\n                \"displayName\": \"API Access Token\",\n                \"name\": \"accessToken\",\n                \"type\": \"TEXT\",\n                \"valueValidators\": [\n                  {\n                    \"type\": \"NON_EMPTY\"\n                  }\n                ]\n              }\n            ],\n            \"enablingConditions\": [\n              {\n                \"paramName\": \"enableMultipixelSetup\",\n                \"paramValue\": true,\n                \"type\": \"EQUALS\"\n              }\n            ],\n            \"newRowButtonText\": \"Add Pixel ID\"\n          }\n        ],\n        \"enablingConditions\": [\n          {\n            \"paramName\": \"useAppSecretProof\",\n            \"paramValue\": true,\n            \"type\": \"NOT_EQUALS\"\n          }\n        ]\n      },\n      {\n        \"type\": \"TEXT\",\n        \"name\": \"testId\",\n        \"displayName\": \"Test ID\",\n        \"simpleValueType\": true,\n        \"help\": \"Provide a Test ID if you want to test server-side events in the Test Events feature of Events Manager.\\n\\u003cbr/\\u003e\\nIt automatically uses the value in \\u003ci\\u003eeventData.test_event_code\\u003c/i\\u003e, if present.\",\n        \"valueHint\": \"TEST123\"\n      },\n      {\n        \"type\": \"SELECT\",\n        \"name\": \"overrideCookieDomain\",\n        \"displayName\": \"Override the cookie domain\",\n        \"macrosInSelect\": true,\n        \"selectItems\": [\n          {\n            \"value\": false,\n            \"displayValue\": \"False\"\n          },\n          {\n            \"value\": true,\n            \"displayValue\": \"True\"\n          }\n        ],\n        \"simpleValueType\": true,\n        \"subParams\": [\n          {\n            \"type\": \"TEXT\",\n            \"name\": \"overridenCookieDomain\",\n            \"displayName\": \"Cookie Domain\",\n            \"simpleValueType\": true,\n            \"enablingConditions\": [\n              {\n                \"paramName\": \"overrideCookieDomain\",\n                \"paramValue\": false,\n                \"type\": \"NOT_EQUALS\"\n              }\n            ],\n            \"help\": \"Enable this option to override the cookie domain.\\u003cbr\\u003eEnter your website\\u0027s top-level domain as a fixed value (e.g., example.com). \\u003cbr\\u003e If left as \\\"auto\\\", the top-level domain will be automatically determined using the following priority: \\u003cul\\u003e \\u003cli\\u003eTop-level domain of the \\u003ci\\u003eForwarded\\u003c/i\\u003e header (if present).\\u003c/li\\u003e \\u003cli\\u003eTop-level domain of the \\u003ci\\u003eX-Forwarded-Host\\u003c/i\\u003e header (if present).\\u003c/li\\u003e \\u003cli\\u003eTop-level domain of the \\u003ci\\u003eHost\\u003c/i\\u003e header.\\u003c/li\\u003e \\u003c/ul\\u003e\",\n            \"defaultValue\": \"auto\",\n            \"valueHint\": \"example.com\",\n            \"alwaysInSummary\": true\n          }\n        ],\n        \"defaultValue\": false\n      },\n      {\n        \"type\": \"CHECKBOX\",\n        \"name\": \"generateFbp\",\n        \"checkboxText\": \"Generate _fbp cookie if it does not exist\",\n        \"simpleValueType\": true,\n        \"defaultValue\": true,\n        \"alwaysInSummary\": true\n      },\n      {\n        \"type\": \"CHECKBOX\",\n        \"name\": \"useHttpOnlyCookie\",\n        \"checkboxText\": \"Use HttpOnly cookies for _fbc and _fbp\",\n        \"simpleValueType\": true,\n        \"help\": \"If enabled, Forbids JavaScript from accessing the \\u003ci\\u003e_fbc\\u003c/i\\u003e and \\u003ci\\u003e_fbp\\u003c/i\\u003e cookies.\"\n      },\n      {\n        \"type\": \"CHECKBOX\",\n        \"name\": \"enableEventEnhancement\",\n        \"checkboxText\": \"Enable Event Enhancement\",\n        \"simpleValueType\": true,\n        \"help\": \"Enable Use of HTTP Only Secure Cookie (gtmeec) to Enhance Event Data.\",\n        \"defaultValue\": true,\n        \"alwaysInSummary\": true\n      },\n      {\n        \"type\": \"CHECKBOX\",\n        \"name\": \"useOptimisticScenario\",\n        \"checkboxText\": \"Use Optimistic Scenario\",\n        \"simpleValueType\": true,\n        \"help\": \"The tag will call gtmOnSuccess() without waiting for a response from the API. This will speed up sGTM response time however your tag will always return the status fired successfully even in case it is not.\"\n      }\n    ]\n  },\n  {\n    \"displayName\": \"Server Event Data Override\",\n    \"name\": \"serverEventDataListGroup\",\n    \"groupStyle\": \"ZIPPY_OPEN_ON_PARAM\",\n    \"type\": \"GROUP\",\n    \"subParams\": [\n      {\n        \"type\": \"LABEL\",\n        \"name\": \"serverEventDataLabel\",\n        \"displayName\": \"Check \\u003ca href\\u003d\\\"https://developers.facebook.com/docs/marketing-api/conversions-api/parameters/server-event\\\"\\u003ethis documentation\\u003c/a\\u003e for more details on which parameters you can override.\\u003cbr/\\u003e\\u003cbr/\\u003e\"\n      },\n      {\n        \"type\": \"CHECKBOX\",\n        \"name\": \"autoMapServerEventData\",\n        \"checkboxText\": \"Automap Server Event Data\",\n        \"simpleValueType\": true,\n        \"help\": \"If enabled, the tag will attempt to automatically map parameters from your event data.\\n\\u003cbr/\\u003e\\u003cbr/\\u003e\\nAny value you manually enter in a field below will always override the auto-mapped value.\\n\\u003cbr/\\u003e\\u003cbr/\\u003e\\nDefault mappings:\\n\\u003cul\\u003e\\n\\u003cli\\u003eSource URL:\\n\\u003cul\\u003e\\n\\u003cli\\u003e\\u003ci\\u003eeventData.page_location\\u003c/i\\u003e\\u003c/li\\u003e\\n\\u003c/ul\\u003e\\n\\u003c/li\\u003e\\n\\u003cli\\u003eReferrer URL:\\n\\u003cul\\u003e\\n\\u003cli\\u003e\\u003ci\\u003eeventData.page_referrer\\u003c/i\\u003e\\u003c/li\\u003e\\n\\u003c/ul\\u003e\\n\\u003c/li\\u003e\\n\\u003cli\\u003eEvent ID:\\n\\u003cul\\u003e\\n\\u003cli\\u003e\\u003ci\\u003eeventData.event_id\\u003c/i\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003ci\\u003eeventData.transaction_id\\u003c/i\\u003e\\u003c/li\\u003e\\n\\u003c/ul\\u003e\\n\\u003c/li\\u003e\\n\\u003c/ul\\u003e\",\n        \"defaultValue\": true\n      },\n      {\n        \"name\": \"serverEventDataList\",\n        \"simpleTableColumns\": [\n          {\n            \"valueValidators\": [\n              {\n                \"type\": \"NON_EMPTY\"\n              }\n            ],\n            \"defaultValue\": \"event_id\",\n            \"displayName\": \"Property Name\",\n            \"name\": \"name\",\n            \"isUnique\": true,\n            \"type\": \"SELECT\",\n            \"selectItems\": [\n              {\n                \"value\": \"event_time\",\n                \"displayValue\": \"Event Time\"\n              },\n              {\n                \"value\": \"event_source_url\",\n                \"displayValue\": \"Source URL\"\n              },\n              {\n                \"value\": \"opt_out\",\n                \"displayValue\": \"Opt Out\"\n              },\n              {\n                \"value\": \"event_id\",\n                \"displayValue\": \"Event ID\"\n              },\n              {\n                \"value\": \"data_processing_options\",\n                \"displayValue\": \"Data Processing Options\"\n              },\n              {\n                \"value\": \"data_processing_options_country\",\n                \"displayValue\": \"Data Processing Options Country\"\n              },\n              {\n                \"value\": \"data_processing_options_state\",\n                \"displayValue\": \"Data Processing Options State\"\n              },\n              {\n                \"value\": \"referrer_url\",\n                \"displayValue\": \"Referrer URL\"\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  },\n  {\n    \"type\": \"GROUP\",\n    \"name\": \"originalEventDataListGroup\",\n    \"displayName\": \"Original Event Data\",\n    \"groupStyle\": \"ZIPPY_OPEN_ON_PARAM\",\n    \"subParams\": [\n      {\n        \"type\": \"LABEL\",\n        \"name\": \"originalEventDataLabel\",\n        \"displayName\": \"Check \\u003ca href\\u003d\\\"https://developers.facebook.com/docs/marketing-api/conversions-api/parameters/original-event\\\"\\u003ethis documentation\\u003c/a\\u003e for more details on which parameters you can override.\\n\\u003cbr/\\u003e\\nUse these parameters to identify the Original Event that happened at an earlier time. Then, use the \\u003ci\\u003eAppendValue\\u003c/i\\u003e event and the other sections to supplement information the Original Event. This is useful for Value Optimization for Profit (using the \\u003ci\\u003enet_revenue\\u003c/i\\u003e parameter), allowing you to report the final profit margin after the initial sale has occurred.\\n\\u003cbr/\\u003e\\u003cbr/\\u003e\"\n      },\n      {\n        \"type\": \"SIMPLE_TABLE\",\n        \"name\": \"originalEventDataList\",\n        \"displayName\": \"\",\n        \"simpleTableColumns\": [\n          {\n            \"defaultValue\": \"\",\n            \"displayName\": \"Property Name\",\n            \"name\": \"name\",\n            \"type\": \"SELECT\",\n            \"isUnique\": true,\n            \"valueValidators\": [\n              {\n                \"type\": \"NON_EMPTY\"\n              }\n            ],\n            \"selectItems\": [\n              {\n                \"value\": \"event_name\",\n                \"displayValue\": \"Original Event Name\"\n              },\n              {\n                \"value\": \"event_time\",\n                \"displayValue\": \"Original Event Time\"\n              },\n              {\n                \"value\": \"order_id\",\n                \"displayValue\": \"Original Order ID\"\n              },\n              {\n                \"value\": \"event_id\",\n                \"displayValue\": \"Original Event ID\"\n              }\n            ]\n          },\n          {\n            \"defaultValue\": \"\",\n            \"displayName\": \"Property Value\",\n            \"name\": \"value\",\n            \"type\": \"TEXT\",\n            \"valueValidators\": [\n              {\n                \"type\": \"NON_EMPTY\"\n              }\n            ]\n          }\n        ],\n        \"valueValidators\": [\n          {\n            \"type\": \"NON_EMPTY\"\n          }\n        ],\n        \"newRowButtonText\": \"Add property\"\n      }\n    ],\n    \"enablingConditions\": [\n      {\n        \"paramName\": \"eventNameStandard\",\n        \"paramValue\": \"AppendValue\",\n        \"type\": \"EQUALS\"\n      },\n      {\n        \"paramName\": \"eventNameCustom\",\n        \"paramValue\": \"AppendValue\",\n        \"type\": \"EQUALS\"\n      }\n    ]\n  },\n  {\n    \"displayName\": \"User Data\",\n    \"name\": \"userDataListGroup\",\n    \"groupStyle\": \"ZIPPY_OPEN_ON_PARAM\",\n    \"type\": \"GROUP\",\n    \"subParams\": [\n      {\n        \"type\": \"LABEL\",\n        \"name\": \"userDataLabel\",\n        \"displayName\": \"User Data is your main \\u003ca href\\u003d\\\"https://www.facebook.com/business/help/765081237991954?id\\u003d818859032317965\\\"\\u003eEvent Match Quality (EMQ) contributor\\u003c/a\\u003e. Matched events improve ad targeting by connecting actions to Meta accounts. Events with better match quality can lead to lower costs per action.\\n\\u003cbr/\\u003e\\nCheck \\u003ca href\\u003d\\\"https://developers.facebook.com/docs/marketing-api/server-side-api/parameters/user-data\\\"\\u003ethis documentation\\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\": \"CHECKBOX\",\n        \"name\": \"autoMapUserData\",\n        \"checkboxText\": \"Automap User Data\",\n        \"simpleValueType\": true,\n        \"help\": \"If enabled, the tag will attempt to automatically map parameters from your event data.\\n\\u003cbr/\\u003e\\u003cbr/\\u003e\\nAny value you manually enter in a field below will always override the auto-mapped value.\\n\\u003cbr/\\u003e\\u003cbr/\\u003e\\nDefault mappings:\\n\\u003cul\\u003e\\n\\u003cli\\u003e\\u003cb\\u003eClick ID:\\u003c/b\\u003e \\u003ci\\u003efbclid URL parameter\\u003c/i\\u003e, \\u003ci\\u003e_fbc cookie\\u003c/i\\u003e, \\u003ci\\u003eeventData.common_cookie._fbc\\u003c/i\\u003e, \\u003ci\\u003eeventData._fbc\\u003c/i\\u003e, \\u003ci\\u003eeventData.fbc\\u003c/i\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003cb\\u003eBrowser ID:\\u003c/b\\u003e \\u003ci\\u003e_fbp cookie\\u003c/i\\u003e, \\u003ci\\u003eeventData.common_cookie._fbp\\u003c/i\\u003e, \\u003ci\\u003eeventData._fbp\\u003c/i\\u003e, \\u003ci\\u003eeventData.fbp\\u003c/i\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003cb\\u003eEmail:\\u003c/b\\u003e \\u003ci\\u003eeventData.email\\u003c/i\\u003e, \\u003ci\\u003eeventData.user_data.email_address\\u003c/i\\u003e, \\u003ci\\u003eeventData.user_data.email\\u003c/i\\u003e, \\u003ci\\u003eeventData.user_data.sha256_email_address\\u003c/i\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003cb\\u003ePhone:\\u003c/b\\u003e \\u003ci\\u003eeventData.phone\\u003c/i\\u003e, \\u003ci\\u003eeventData.user_data.phone_number\\u003c/i\\u003e, \\u003ci\\u003eeventData.user_data.phone\\u003c/i\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003cb\\u003eFirst Name:\\u003c/b\\u003e \\u003ci\\u003eeventData.firstName\\u003c/i\\u003e, \\u003ci\\u003eeventData.FirstName\\u003c/i\\u003e, \\u003ci\\u003eeventData.nameFirst\\u003c/i\\u003e, \\u003ci\\u003eeventData.first_name\\u003c/i\\u003e, \\u003ci\\u003eeventData.user_data.first_name\\u003c/i\\u003e, \\u003ci\\u003eeventData.user_data.address[].first_name\\u003c/i\\u003e, \\u003ci\\u003eeventData.user_data.address[].sha256_first_name\\u003c/i\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003cb\\u003eLast Name:\\u003c/b\\u003e \\u003ci\\u003eeventData.lastName\\u003c/i\\u003e, \\u003ci\\u003eeventData.LastName\\u003c/i\\u003e, \\u003ci\\u003eeventData.nameLast\\u003c/i\\u003e, \\u003ci\\u003eeventData.last_name\\u003c/i\\u003e, \\u003ci\\u003eeventData.user_data.last_name\\u003c/i\\u003e, \\u003ci\\u003eeventData.user_data.address[].last_name\\u003c/i\\u003e, \\u003ci\\u003eeventData.user_data.address[].sha256_last_name\\u003c/i\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003cb\\u003eCity:\\u003c/b\\u003e \\u003ci\\u003eeventData.city\\u003c/i\\u003e, \\u003ci\\u003eeventData.user_data.address[].city\\u003c/i\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003cb\\u003eState:\\u003c/b\\u003e \\u003ci\\u003eeventData.state\\u003c/i\\u003e, \\u003ci\\u003eeventData.region\\u003c/i\\u003e, \\u003ci\\u003eeventData.user_data.region\\u003c/i\\u003e, \\u003ci\\u003eeventData.user_data.address[].region\\u003c/i\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003cb\\u003eZip:\\u003c/b\\u003e \\u003ci\\u003eeventData.zip\\u003c/i\\u003e, \\u003ci\\u003eeventData.postal_code\\u003c/i\\u003e, \\u003ci\\u003eeventData.user_data.postal_code\\u003c/i\\u003e, \\u003ci\\u003eeventData.user_data.address[].postal_code\\u003c/i\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003cb\\u003eCountry:\\u003c/b\\u003e \\u003ci\\u003eeventData.countryCode\\u003c/i\\u003e, \\u003ci\\u003eeventData.country\\u003c/i\\u003e, \\u003ci\\u003eeventData.user_data.country\\u003c/i\\u003e, \\u003ci\\u003eeventData.user_data.address[].country\\u003c/i\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003cb\\u003eGender:\\u003c/b\\u003e \\u003ci\\u003eeventData.gender\\u003c/i\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003cb\\u003eDate of Birth:\\u003c/b\\u003e \\u003ci\\u003eeventData.db\\u003c/i\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003cb\\u003eExternal ID:\\u003c/b\\u003e \\u003ci\\u003eeventData.external_id\\u003c/i\\u003e, \\u003ci\\u003eeventData.user_id\\u003c/i\\u003e, \\u003ci\\u003eeventData.userId\\u003c/i\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003cb\\u003eFB Login ID:\\u003c/b\\u003e \\u003ci\\u003eeventData.fb_login_id\\u003c/i\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003cb\\u003eInstall ID:\\u003c/b\\u003e \\u003ci\\u003eeventData.anon_id\\u003c/i\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003cb\\u003eMobile Advertising ID:\\u003c/b\\u003e \\u003ci\\u003eeventData.madid\\u003c/i\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003cb\\u003eLead ID:\\u003c/b\\u003e \\u003ci\\u003eeventData.lead_id\\u003c/i\\u003e, \\u003ci\\u003eeventData.leadId\\u003c/i\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003cb\\u003eSubscription ID:\\u003c/b\\u003e \\u003ci\\u003eeventData.subscription_id\\u003c/i\\u003e, \\u003ci\\u003eeventData.subscriptionId\\u003c/i\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003cb\\u003ePlaintext IP Address:\\u003c/b\\u003e \\u003ci\\u003eeventData.ip_override\\u003c/i\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003cb\\u003eClient User Agent:\\u003c/b\\u003e \\u003ci\\u003eeventData.user_agent\\u003c/i\\u003e\\u003c/li\\u003e\\n\\u003c/ul\\u003e\",\n        \"defaultValue\": true\n      },\n      {\n        \"type\": \"SELECT\",\n        \"name\": \"userDataObject\",\n        \"displayName\": \"User Data Properties Object\",\n        \"macrosInSelect\": true,\n        \"selectItems\": [],\n        \"simpleValueType\": true,\n        \"help\": \"Provide an object with User Data Properties to merge with the fields below. Any conflicting properties will be overwritten.\",\n        \"notSetText\": \"(not set)\"\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                \"value\": \"client_ip_address\",\n                \"displayValue\": \"Client IP Address\"\n              },\n              {\n                \"value\": \"client_user_agent\",\n                \"displayValue\": \"Client User Agent\"\n              },\n              {\n                \"value\": \"fbc\",\n                \"displayValue\": \"Click ID\"\n              },\n              {\n                \"value\": \"fbp\",\n                \"displayValue\": \"Browser ID\"\n              },\n              {\n                \"value\": \"subscription_id\",\n                \"displayValue\": \"Subscription ID\"\n              },\n              {\n                \"value\": \"lead_id\",\n                \"displayValue\": \"Lead ID\"\n              },\n              {\n                \"value\": \"fb_login_id\",\n                \"displayValue\": \"FB Login ID\"\n              },\n              {\n                \"value\": \"anon_id\",\n                \"displayValue\": \"Install ID\"\n              },\n              {\n                \"value\": \"madid\",\n                \"displayValue\": \"Mobile Advertiser ID\"\n              },\n              {\n                \"value\": \"page_id\",\n                \"displayValue\": \"Page ID\"\n              },\n              {\n                \"value\": \"page_scoped_user_id\",\n                \"displayValue\": \"Page Scoped User ID\"\n              },\n              {\n                \"value\": \"ctwa_clid\",\n                \"displayValue\": \"Click to WhatsApp ID\"\n              },\n              {\n                \"value\": \"ig_account_id\",\n                \"displayValue\": \"IG Account ID\"\n              },\n              {\n                \"value\": \"ig_sid\",\n                \"displayValue\": \"Click to Instagram 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  },\n  {\n    \"displayName\": \"App Data\",\n    \"name\": \"appDataListGroup\",\n    \"type\": \"GROUP\",\n    \"subParams\": [\n      {\n        \"type\": \"LABEL\",\n        \"name\": \"appDataLabel\",\n        \"displayName\": \"Check \\u003ca href\\u003d\\\"https://developers.facebook.com/docs/marketing-api/conversions-api/parameters/app-data\\\"\\u003ethis documentation\\u003c/a\\u003e for more details on which parameters you can override.\\n\\u003cbr/\\u003e\\u003cbr/\\u003e\"\n      },\n      {\n        \"type\": \"CHECKBOX\",\n        \"name\": \"autoMapAppData\",\n        \"checkboxText\": \"Automap App Data\",\n        \"simpleValueType\": true,\n        \"help\": \"If enabled, the tag will attempt to automatically map parameters from your event data.\\n\\u003cbr/\\u003e\\u003cbr/\\u003e\\nAny value you manually enter in a field below will always override the auto-mapped value.\\n\\u003cbr/\\u003e\\u003cbr/\\u003e\\nDefault mappings:\\n\\u003cul\\u003e\\n\\u003cli\\u003eIf \\u003ci\\u003eeventData.app_data\\u003c/i\\u003e is an object, it is used directly.\\u003c/li\\u003e\\n\\u003cli\\u003eOtherwise:\\n\\u003cul\\u003e\\n\\u003cli\\u003eAdvertiser Tracking Enabled: \\u003ci\\u003eeventData.advertiser_tracking_enabled\\u003c/i\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003eApplication Tracking Enabled: \\u003ci\\u003eeventData.application_tracking_enabled\\u003c/i\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003eExt Info: \\u003ci\\u003eeventData.extinfo\\u003c/i\\u003e, or built from \\u003ci\\u003eeventData[x-ga-platform]\\u003c/i\\u003e, \\u003ci\\u003eeventData.app_id\\u003c/i\\u003e, \\u003ci\\u003eeventData.app_version\\u003c/i\\u003e, \\u003ci\\u003eeventData[x-ga-os_version]\\u003c/i\\u003e, \\u003ci\\u003eeventData[x-ga-device_model]\\u003c/i\\u003e, \\u003ci\\u003eeventData.language\\u003c/i\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003eCampaign IDs: \\u003ci\\u003eeventData.campaign_ids\\u003c/i\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003eInstall Referrer: \\u003ci\\u003eeventData.install_referrer\\u003c/i\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003eInstaller Package: \\u003ci\\u003eeventData.installer_package\\u003c/i\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003eURL Schemes: \\u003ci\\u003eeventData.url_schemes\\u003c/i\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003eVendor ID: \\u003ci\\u003eeventData.vendor_id\\u003c/i\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003eWindows Attribution ID: \\u003ci\\u003eeventData.windows_attribution_id\\u003c/i\\u003e\\u003c/li\\u003e\\n\\u003c/ul\\u003e\\n\\u003c/li\\u003e\\n\\u003c/ul\\u003e\",\n        \"defaultValue\": true\n      },\n      {\n        \"type\": \"SELECT\",\n        \"name\": \"appDataObject\",\n        \"displayName\": \"App Data Properties Object\",\n        \"macrosInSelect\": true,\n        \"selectItems\": [],\n        \"simpleValueType\": true,\n        \"help\": \"Provide an object with App Data Properties to merge with the fields below. Any conflicting properties will be overwritten.\",\n        \"notSetText\": \"(not set)\"\n      },\n      {\n        \"name\": \"appDataList\",\n        \"simpleTableColumns\": [\n          {\n            \"valueValidators\": [\n              {\n                \"type\": \"NON_EMPTY\"\n              }\n            ],\n            \"defaultValue\": \"\",\n            \"displayName\": \"Property Name\",\n            \"name\": \"name\",\n            \"isUnique\": true,\n            \"type\": \"SELECT\",\n            \"selectItems\": [\n              {\n                \"value\": \"advertiser_tracking_enabled\",\n                \"displayValue\": \"Advertiser Tracking Enabled\"\n              },\n              {\n                \"value\": \"application_tracking_enabled\",\n                \"displayValue\": \"Application Tracking Enabled\"\n              },\n              {\n                \"value\": \"extinfo\",\n                \"displayValue\": \"Ext Info\"\n              },\n              {\n                \"value\": \"campaign_ids\",\n                \"displayValue\": \"Campaign IDs\"\n              },\n              {\n                \"value\": \"install_referrer\",\n                \"displayValue\": \"Install Referrer\"\n              },\n              {\n                \"value\": \"installer_package\",\n                \"displayValue\": \"Installer Package\"\n              },\n              {\n                \"value\": \"url_schemes\",\n                \"displayValue\": \"URL Schemes\"\n              },\n              {\n                \"value\": \"vendor_id\",\n                \"displayValue\": \"Vendor ID\"\n              },\n              {\n                \"value\": \"windows_attribution_id\",\n                \"displayValue\": \"Windows Attribution 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\": \"actionSource\",\n        \"paramValue\": \"app\",\n        \"type\": \"EQUALS\"\n      }\n    ],\n    \"groupStyle\": \"ZIPPY_OPEN_ON_PARAM\"\n  },\n  {\n    \"displayName\": \"Custom Data\",\n    \"name\": \"customDataListGroup\",\n    \"groupStyle\": \"ZIPPY_OPEN_ON_PARAM\",\n    \"type\": \"GROUP\",\n    \"subParams\": [\n      {\n        \"type\": \"LABEL\",\n        \"name\": \"customDataLabel\",\n        \"displayName\": \"Check \\u003ca href\\u003d\\\"https://developers.facebook.com/docs/marketing-api/conversions-api/parameters/custom-data\\\"\\u003ethis documentation\\u003c/a\\u003e for more details on which parameters you can override.\\n\\u003cbr/\\u003e\\u003cbr/\\u003e\"\n      },\n      {\n        \"type\": \"CHECKBOX\",\n        \"name\": \"autoMapCustomData\",\n        \"checkboxText\": \"Automap Custom Data\",\n        \"simpleValueType\": true,\n        \"help\": \"If enabled, the tag will attempt to automatically map parameters from your event data.\\n\\u003cbr/\\u003e\\u003cbr/\\u003e\\nAny value you manually enter in a field below will always override the auto-mapped value.\\n\\u003cbr/\\u003e\\u003cbr/\\u003e\\nDefault mappings:\\n\\u003cul\\u003e\\n\\u003cli\\u003eValue:\\n\\u003cul\\u003e\\n\\u003cli\\u003e\\u003ci\\u003eeventData[\\u0027x-ga-mp1-ev\\u0027]\\u003c/i\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003ci\\u003eeventData[\\u0027x-ga-mp1-tr\\u0027]\\u003c/i\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003ci\\u003eeventData.value\\u003c/i\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003ci\\u003eSum of Price * Quantity from eventData.items[] or eventData.ecommerce.items[]\\u003c/i\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003ci\\u003e0\\u003c/i\\u003e, if event is \\\"Purchase\\\" and no value is defined\\u003c/li\\u003e\\n\\u003c/ul\\u003e\\n\\u003c/li\\u003e\\n\\u003cli\\u003eCurrency:\\n\\u003cul\\u003e\\n\\u003cli\\u003e\\u003ci\\u003eeventData.currency\\u003c/i\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003ci\\u003eCurrency from eventData.items[] or eventData.ecommerce.items[]\\u003c/i\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003ci\\u003eUSD\\u003c/i\\u003e, if event is \\\"Purchase\\\" and no currency is defined\\u003c/li\\u003e\\n\\u003c/ul\\u003e\\n\\u003c/li\\u003e\\n\\u003cli\\u003eContents:\\n\\u003cul\\u003e\\n\\u003cli\\u003e\\u003ci\\u003eeventData.items[]\\u003c/i\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003ci\\u003eeventData.ecommerce.items[]\\u003c/i\\u003e\\u003c/li\\u003e\\n\\u003c/ul\\u003e\\n\\u003c/li\\u003e\\n\\u003cli\\u003eContent Type:\\n\\u003cul\\u003e\\n\\u003cli\\u003e\\u003ci\\u003eeventData[x-fb-cd-content_type]\\u003c/i\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003e\\u003ci\\u003eeventData.content_type\\u003c/i\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003eDefault: \\u003ci\\u003eproduct\\u003c/i\\u003e\\u003c/li\\u003e\\n\\u003c/ul\\u003e\\n\\u003c/li\\u003e\\n\\u003cli\\u003eOrder ID:\\n\\u003cul\\u003e\\n\\u003cli\\u003e\\u003ci\\u003eeventData.transaction_id\\u003c/i\\u003e\\u003c/li\\u003e\\n\\u003c/ul\\u003e\\n\\u003c/li\\u003e\\n\\u003cli\\u003eSearch String:\\n\\u003cul\\u003e\\n\\u003cli\\u003e\\u003ci\\u003eeventData.search_term\\u003c/i\\u003e\\u003c/li\\u003e\\n\\u003c/ul\\u003e\\n\\u003c/li\\u003e\\n\\u003c/ul\\u003e\",\n        \"defaultValue\": true,\n        \"subParams\": [\n          {\n            \"type\": \"GROUP\",\n            \"name\": \"autoMapCustomDataSettingsGroup\",\n            \"subParams\": [\n              {\n                \"type\": \"TEXT\",\n                \"name\": \"itemIdKey\",\n                \"displayName\": \"Custom Item ID Key\",\n                \"simpleValueType\": true,\n                \"help\": \"Optional.\\n\\u003cbr/\\u003e\\u003cbr/\\u003e\\nYou can specify a custom key, which will be used to set the content Item ID, by default \\u003ci\\u003eitem_id\\u003c/i\\u003e will be used. This may be useful if you are using WooCommerce extensions.\",\n                \"canBeEmptyString\": true\n              },\n              {\n                \"type\": \"SELECT\",\n                \"name\": \"mapItemDataTo\",\n                \"displayName\": \"Map item data to\",\n                \"selectItems\": [\n                  {\n                    \"value\": \"contents\",\n                    \"displayValue\": \"Contents\"\n                  },\n                  {\n                    \"value\": \"content_ids\",\n                    \"displayValue\": \"Content IDs\"\n                  },\n                  {\n                    \"value\": \"both\",\n                    \"displayValue\": \"Both Contents and Content IDs\"\n                  }\n                ],\n                \"simpleValueType\": true,\n                \"defaultValue\": \"contents\",\n                \"help\": \"Choose which parameter(s) to use when mapping item data: Contents, Content IDs or both.\"\n              }\n            ],\n            \"enablingConditions\": [\n              {\n                \"paramName\": \"autoMapCustomData\",\n                \"paramValue\": false,\n                \"type\": \"NOT_EQUALS\"\n              }\n            ]\n          }\n        ]\n      },\n      {\n        \"type\": \"SELECT\",\n        \"name\": \"customDataObject\",\n        \"displayName\": \"Custom Data Properties Object\",\n        \"macrosInSelect\": true,\n        \"selectItems\": [],\n        \"simpleValueType\": true,\n        \"help\": \"Provide an object with Custom Data Properties to merge with the fields below. Any conflicting properties will be overwritten.\",\n        \"notSetText\": \"(not set)\"\n      },\n      {\n        \"name\": \"customDataList\",\n        \"simpleTableColumns\": [\n          {\n            \"valueValidators\": [\n              {\n                \"type\": \"NON_EMPTY\"\n              }\n            ],\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\": \"tagExecutionConsentSettingsGroup\",\n    \"displayName\": \"Tag Execution Consent Settings\",\n    \"groupStyle\": \"ZIPPY_CLOSED\",\n    \"subParams\": [\n      {\n        \"type\": \"RADIO\",\n        \"name\": \"adStorageConsent\",\n        \"radioItems\": [\n          {\n            \"value\": \"optional\",\n            \"displayValue\": \"Send data always\"\n          },\n          {\n            \"value\": \"required\",\n            \"displayValue\": \"Send data in case marketing consent given\",\n            \"help\": \"Aborts the tag execution if marketing consent (\\u003ci\\u003ead_storage\\u003c/i\\u003e Google Consent Mode or Stape\\u0027s Data Tag parameter) is not given.\"\n          }\n        ],\n        \"simpleValueType\": true,\n        \"defaultValue\": \"optional\"\n      }\n    ]\n  },\n  {\n    \"type\": \"GROUP\",\n    \"name\": \"moreSettingsGroup\",\n    \"displayName\": \"More Settings\",\n    \"groupStyle\": \"ZIPPY_OPEN_ON_PARAM\",\n    \"subParams\": [\n      {\n        \"type\": \"CHECKBOX\",\n        \"name\": \"useAppSecretProof\",\n        \"checkboxText\": \"Use App Secret Proof\",\n        \"simpleValueType\": true,\n        \"help\": \"Optional. \\u003cbr/\\u003e\\u003cbr/\\u003e Use this field only if your Business Manager’s Conversions API Application requires API calls to include the \\u003ci\\u003eapp secret proof\\u003c/i\\u003e.   \\u003cbr/\\u003e\\u003cbr/\\u003e You’ll encounter this requirement if event requests fail with the error:  \\u003ci\\u003e\\\"API calls from the server require an appsecret_proof argument\\\"\\u003c/i\\u003e. \\u003cbr/\\u003e\\u003cbr/\\u003e \\u003ca href\\u003d\\\"https://developers.facebook.com/docs/graph-api/guides/secure-requests#appsecret_proof\\\"\\u003eLearn more\\u003c/a\\u003e about how to generate this value.\",\n        \"subParams\": [\n          {\n            \"type\": \"TEXT\",\n            \"name\": \"appSecretProof\",\n            \"displayName\": \"App Secret Proof\",\n            \"simpleValueType\": true,\n            \"enablingConditions\": [\n              {\n                \"paramName\": \"useAppSecretProof\",\n                \"paramValue\": true,\n                \"type\": \"EQUALS\"\n              }\n            ],\n            \"valueValidators\": [\n              {\n                \"type\": \"NON_EMPTY\"\n              }\n            ]\n          }\n        ]\n      },\n      {\n        \"type\": \"CHECKBOX\",\n        \"name\": \"mapViewItemListToViewContent\",\n        \"checkboxText\": \"Automap GA4 \\\"view_item_list\\\" event to \\\"ViewContent\\\"\",\n        \"simpleValueType\": true,\n        \"defaultValue\": false,\n        \"help\": \"When enabled with \\\"Inherit from client\\\" \\u003ci\\u003eEvent Name Setup Method\\u003c/i\\u003e:\\n\\u003cul\\u003e\\n\\u003cli\\u003eMaps the GA4 \\\"view_item_list\\\" event to \\\"ViewContent\\\".\\u003c/li\\u003e\\n\\u003cli\\u003eSets \\\"content_type\\\" to \\\"product_group\\\" if an items array is present.\\u003c/li\\u003e\\n\\u003c/ul\\u003e\",\n        \"enablingConditions\": [\n          {\n            \"paramName\": \"inheritEventName\",\n            \"paramValue\": \"inherit\",\n            \"type\": \"EQUALS\"\n          }\n        ]\n      }\n    ]\n  }\n]\n\n\n___SANDBOXED_JS_FOR_SERVER___\n\nconst computeEffectiveTldPlusOne = require('computeEffectiveTldPlusOne');\nconst createRegex = require('createRegex');\nconst decodeUriComponent = require('decodeUriComponent');\nconst encodeUriComponent = require('encodeUriComponent');\nconst fromBase64 = require('fromBase64');\nconst generateRandom = require('generateRandom');\nconst getAllEventData = require('getAllEventData');\nconst getCookieValues = require('getCookieValues');\nconst getRequestHeader = require('getRequestHeader');\nconst getTimestampMillis = require('getTimestampMillis');\nconst getType = require('getType');\nconst JSON = require('JSON');\nconst makeNumber = require('makeNumber');\nconst makeString = require('makeString');\nconst Math = require('Math');\nconst parseUrl = require('parseUrl');\nconst Promise = require('Promise');\nconst sendHttpRequest = require('sendHttpRequest');\nconst setCookie = require('setCookie');\nconst sha256Sync = require('sha256Sync');\nconst testRegex = require('testRegex');\nconst toBase64 = require('toBase64');\n\n/*==============================================================================\n==============================================================================*/\n\nconst eventData = getAllEventData();\nconst API_VERSION = '26.0';\nconst PARTNER_AGENT_STRING = 'stape-gtmss-2.1.7' + (data.enableEventEnhancement ? '-ee' : '');\n\nif (shouldExitEarly(data, eventData)) {\n  return data.gtmOnSuccess();\n}\n\nconst ids = getClickAndBrowserId(data, eventData);\nconst fbc = ids.fbc;\nconst fbp = ids.fbp;\nsetIDsCookies(data, fbc, fbp);\n\nconst mappedPostBody = mapEvent(data, eventData, fbc, fbp);\nsendRequests(data, mappedPostBody);\n\nif (data.useOptimisticScenario) {\n  return data.gtmOnSuccess();\n}\n\n/*==============================================================================\n  Vendor related functions\n==============================================================================*/\n\nfunction setIDsCookies(data, fbc, fbp) {\n  const cookieOptions = {\n    domain: isUIFieldTrue(data.overrideCookieDomain)\n      ? data.overridenCookieDomain || 'auto'\n      : 'auto',\n    path: '/',\n    samesite: 'Lax',\n    secure: true,\n    'max-age': 7776000, // 90 days\n    HttpOnly: !!data.useHttpOnlyCookie\n  };\n\n  if (fbc) {\n    setCookie('_fbc', fbc, cookieOptions);\n  }\n\n  if (fbp) {\n    setCookie('_fbp', fbp, cookieOptions);\n  }\n}\n\nfunction getClickAndBrowserId(data, eventData) {\n  const ids = {\n    fbc:\n      getCookieValues('_fbc')[0] ||\n      (eventData.common_cookie || {})._fbc ||\n      eventData._fbc ||\n      eventData.fbc,\n    fbp:\n      getCookieValues('_fbp')[0] ||\n      (eventData.common_cookie || {})._fbp ||\n      eventData._fbp ||\n      eventData.fbp\n  };\n\n  const url = getUrl(eventData);\n  const subDomainIndex = url ? computeEffectiveTldPlusOne(url).split('.').length - 1 : 1;\n\n  if (url) {\n    const urlParsed = parseUrl(url);\n    if (urlParsed && urlParsed.searchParams.fbclid) {\n      const fbclid = decodeUriComponent(urlParsed.searchParams.fbclid);\n      const fbcParts = ids.fbc ? ids.fbc.split('.') : [];\n\n      if (isValidValue(fbclid) && (!ids.fbc || fbcParts[fbcParts.length - 1] !== fbclid)) {\n        ids.fbc = 'fb.' + subDomainIndex + '.' + getTimestampMillis() + '.' + fbclid;\n      }\n    }\n  }\n\n  if (!ids.fbp && data.generateFbp) {\n    ids.fbp =\n      'fb.' +\n      subDomainIndex +\n      '.' +\n      getTimestampMillis() +\n      '.' +\n      generateRandom(1000000000, 2147483647);\n  }\n\n  return ids;\n}\n\nfunction getEventName(data) {\n  const gaToFacebookEventName = {\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    'gtm4wp.addProductToCartEEC': 'AddToCart',\n    'gtm4wp.productClickEEC': 'ViewContent',\n    'gtm4wp.checkoutOptionEEC': 'InitiateCheckout',\n    'gtm4wp.checkoutStepEEC': 'AddPaymentInfo',\n    'gtm4wp.orderCompletedEEC': 'Purchase'\n  };\n\n  if (data.inheritEventName !== 'override') {\n    if (data.mapViewItemListToViewContent) {\n      gaToFacebookEventName.view_item_list = 'ViewContent';\n    }\n    const eventName = eventData.event_name;\n    return gaToFacebookEventName[eventName] || eventName;\n  }\n\n  let selectedEventName;\n  if (data.eventName === 'standard') {\n    selectedEventName = data.eventNameStandard;\n  } else if (data.eventName === 'custom') {\n    selectedEventName = data.eventNameCustom;\n  }\n\n  if (isValidValue(selectedEventName)) return selectedEventName;\n\n  // An incomplete override falls back to the incoming name, as the inherit branch does.\n  return gaToFacebookEventName[eventData.event_name] || eventData.event_name;\n}\n\nfunction mapEvent(data, eventData, fbc, fbp) {\n  let mappedData = {\n    event_name: getEventName(data),\n    action_source: data.actionSource || 'website',\n    event_time: Math.round(getTimestampMillis() / 1000),\n    custom_data: {},\n    user_data: {}\n  };\n  const mappedPostBody = {\n    data: [mappedData],\n    partner_agent: PARTNER_AGENT_STRING\n  };\n\n  if (eventData.test_event_code || data.testId) {\n    mappedPostBody.test_event_code = eventData.test_event_code\n      ? eventData.test_event_code\n      : data.testId;\n  }\n\n  if (mappedData.action_source === 'app') {\n    mappedData.app_data = {};\n  }\n\n  if (mappedData.action_source === 'business_messaging') {\n    mappedData.messaging_channel = data.messaging_channel;\n  }\n\n  mappedData = addServerEventData(data, eventData, mappedData);\n  mappedData = addUserData(data, eventData, mappedData, fbc, fbp);\n  mappedData = addAppData(data, eventData, mappedData);\n  mappedData = addEcommerceData(data, eventData, mappedData);\n  mappedData = addOriginalEventData(mappedData);\n\n  if (data.enableEventEnhancement) {\n    mappedData.user_data = enhanceEventData(eventData, mappedData.user_data);\n  }\n\n  mappedData = overrideDataIfNeeded(mappedData);\n  mappedData = cleanupData(mappedData);\n  mappedData = hashDataIfNeeded(mappedData);\n\n  if (data.enableEventEnhancement) {\n    setGtmEecCookie(mappedData.user_data);\n  }\n\n  return mappedPostBody;\n}\n\nfunction hashData(key, value) {\n  if (!value) {\n    return value;\n  }\n\n  const type = getType(value);\n\n  if (type === 'undefined' || value === 'undefined') {\n    return undefined;\n  }\n\n  if (type === 'array') {\n    return value.map((val) => {\n      return hashData(key, val);\n    });\n  }\n\n  if (isHashed(value)) {\n    return value;\n  }\n\n  value = makeString(value).trim().toLowerCase();\n\n  if (key === 'ph') {\n    value = normalizePhoneNumber(value);\n  } else if (key === 'ct') {\n    value = value.split(' ').join('');\n  }\n\n  return sha256Sync(value, { outputEncoding: 'hex' });\n}\n\nfunction hashDataIfNeeded(mappedData) {\n  if (mappedData.user_data) {\n    const keysToHash = [\n      'em',\n      'ph',\n      'ge',\n      'db',\n      'ln',\n      'fn',\n      'ct',\n      'st',\n      'zp',\n      'country',\n      'external_id'\n    ];\n    for (let key in mappedData.user_data) {\n      if (keysToHash.indexOf(key) !== -1) {\n        mappedData.user_data[key] = hashData(key, mappedData.user_data[key]);\n      }\n    }\n  }\n\n  return mappedData;\n}\n\nfunction overrideDataIfNeeded(mappedData) {\n  if (getType(data.userDataObject) === 'object') {\n    mergeObj(mappedData.user_data, data.userDataObject);\n  }\n  if (data.userDataList) {\n    data.userDataList.forEach((d) => {\n      mappedData.user_data[d.name] = d.value;\n    });\n  }\n\n  if (getType(data.customDataObject) === 'object') {\n    mergeObj(mappedData.custom_data, data.customDataObject);\n  }\n  if (data.customDataList) {\n    data.customDataList.forEach((d) => {\n      mappedData.custom_data[d.name] = d.value;\n    });\n  }\n\n  if (mappedData.action_source === 'app') {\n    if (getType(data.appDataObject) === 'object') {\n      mergeObj(mappedData.app_data, data.appDataObject);\n    }\n    if (data.appDataList) {\n      data.appDataList.forEach((d) => {\n        mappedData.app_data[d.name] = d.value;\n      });\n    }\n  }\n\n  return mappedData;\n}\n\nfunction cleanupData(mappedData) {\n  if (mappedData.action_source === 'business_messaging') {\n    mappedData.event_source_url = undefined;\n    ['client_ip_address', 'client_user_agent', 'fbc', 'fbp'].forEach(\n      (key) => (mappedData.user_data[key] = undefined)\n    );\n  }\n\n  if (mappedData.user_data) {\n    const userData = {};\n\n    for (let userDataKey in mappedData.user_data) {\n      if (isValidValue(mappedData.user_data[userDataKey])) {\n        userData[userDataKey] = mappedData.user_data[userDataKey];\n      }\n    }\n\n    mappedData.user_data = userData;\n  }\n\n  if (mappedData.custom_data) {\n    const customData = {};\n\n    for (let customDataKey in mappedData.custom_data) {\n      if (isValidValue(mappedData.custom_data[customDataKey])) {\n        customData[customDataKey] = mappedData.custom_data[customDataKey];\n      }\n    }\n\n    if (customData.value === 0 || customData.value === '0') customData.value = '0.00';\n\n    mappedData.custom_data = customData;\n  }\n\n  if (mappedData.app_data) {\n    const appData = {};\n\n    for (let appDataKey in mappedData.app_data) {\n      if (isValidValue(mappedData.app_data[appDataKey])) {\n        appData[appDataKey] = mappedData.app_data[appDataKey];\n      }\n    }\n\n    mappedData.app_data = appData;\n  }\n\n  if (mappedData.original_event_data) {\n    const originalEventData = {};\n\n    for (let originalEventDataKey in mappedData.original_event_data) {\n      if (isValidValue(mappedData.original_event_data[originalEventDataKey])) {\n        originalEventData[originalEventDataKey] =\n          mappedData.original_event_data[originalEventDataKey];\n      }\n    }\n\n    mappedData.original_event_data = originalEventData;\n  }\n\n  for (let key in mappedData) { // Assigned, not rebuilt: the post body holds this reference.\n    if (!isValidValue(mappedData[key])) mappedData[key] = undefined;\n  }\n\n  return mappedData;\n}\n\nfunction addEcommerceData(data, eventData, mappedData) {\n  const autoMapEnabled = data.hasOwnProperty('autoMapCustomData') ? data.autoMapCustomData : true; // To avoid a breaking change.\n  if (autoMapEnabled) {\n    let currencyFromItems = '';\n    let valueFromItems = 0;\n\n    let items;\n    if (getType(eventData.items) === 'array' && eventData.items.length) items = eventData.items;\n    else if (\n      getType(eventData.ecommerce) === 'object' &&\n      getType(eventData.ecommerce.items) === 'array' &&\n      eventData.ecommerce.items.length\n    ) {\n      items = eventData.ecommerce.items;\n    }\n\n    if (items) {\n      mappedData.custom_data.content_type =\n        eventData['x-fb-cd-content_type'] || eventData.content_type || 'product';\n\n      if (\n        data.mapViewItemListToViewContent &&\n        data.inheritEventName !== 'override' &&\n        eventData.event_name === 'view_item_list'\n      ) {\n        mappedData.custom_data.content_type = 'product_group';\n      }\n\n      if (!items[1]) {\n        if (items[0].item_name) mappedData.custom_data.content_name = items[0].item_name;\n        if (items[0].item_category)\n          mappedData.custom_data.content_category = items[0].item_category;\n\n        const singleItemPrice = toFiniteNumber(items[0].price);\n        const singleItemQuantity = toFiniteNumber(items[0].quantity);\n        if (isValidValue(singleItemPrice)) {\n          mappedData.custom_data.value = isValidValue(singleItemQuantity)\n            ? singleItemQuantity * singleItemPrice\n            : singleItemPrice;\n        }\n      }\n\n      const itemIdKey = data.itemIdKey ? data.itemIdKey : 'item_id';\n      const mapItemDataTo = data.mapItemDataTo || 'contents';\n      items.forEach((d) => {\n        if (!currencyFromItems && d.currency) currencyFromItems = d.currency;\n\n        const content = {};\n        let hasContent = false;\n\n        if (isValidValue(d[itemIdKey])) {\n          content.id = makeString(d[itemIdKey]);\n          hasContent = true;\n        }\n        if (d.item_name) {\n          content.title = d.item_name;\n          hasContent = true;\n        }\n        if (d.item_brand) {\n          content.brand = d.item_brand;\n          hasContent = true;\n        }\n        if (d.item_category) {\n          content.category = d.item_category;\n          hasContent = true;\n        }\n\n        const quantity = toFiniteNumber(d.quantity);\n        if (isValidValue(quantity)) {\n          content.quantity = quantity;\n          hasContent = true;\n        }\n\n        const itemPrice = toFiniteNumber(d.price);\n        if (isValidValue(itemPrice)) {\n          content.item_price = itemPrice;\n          hasContent = true;\n          valueFromItems += isValidValue(quantity) ? quantity * itemPrice : itemPrice;\n        }\n\n        if (!hasContent) return;\n\n        if (mapItemDataTo === 'contents' || mapItemDataTo === 'both') {\n          mappedData.custom_data.contents = mappedData.custom_data.contents || [];\n          mappedData.custom_data.contents.push(content);\n        }\n        if (content.id && (mapItemDataTo === 'content_ids' || mapItemDataTo === 'both')) {\n          mappedData.custom_data.content_ids = mappedData.custom_data.content_ids || [];\n          mappedData.custom_data.content_ids.push(content.id);\n        }\n      });\n\n      if (!mappedData.custom_data.contents && !mappedData.custom_data.content_ids) {\n        mappedData.custom_data.content_type = undefined;\n      }\n    }\n\n    const value = toFiniteNumber(\n      eventData['x-ga-mp1-ev'] || eventData['x-ga-mp1-tr'] || eventData.value\n    );\n    if (isValidValue(value)) mappedData.custom_data.value = value;\n\n    const currency = eventData.currency || currencyFromItems;\n    if (currency) mappedData.custom_data.currency = currency;\n\n    if (eventData.search_term) mappedData.custom_data.search_string = eventData.search_term;\n\n    if (eventData.transaction_id) mappedData.custom_data.order_id = eventData.transaction_id;\n\n    if (mappedData.event_name === 'Purchase') {\n      // Facebook rejects a Purchase event with no value at all, so this always assigns one.\n      if (!isValidValue(mappedData.custom_data.value))\n        mappedData.custom_data.value = valueFromItems;\n    }\n\n    if (\n      !mappedData.custom_data.currency &&\n      (isValidValue(mappedData.custom_data.value) || valueFromItems)\n    ) {\n      mappedData.custom_data.currency = 'USD';\n    }\n  }\n\n  return mappedData;\n}\n\nfunction addUserData(data, eventData, mappedData, fbc, fbp) {\n  const autoMapEnabled = data.hasOwnProperty('autoMapUserData') ? data.autoMapUserData : true; // To avoid a breaking change.\n  if (autoMapEnabled) {\n    let address = {};\n    let user_data = {};\n    if (getType(eventData.user_data) === 'object') {\n      user_data = eventData.user_data;\n      const addressType = getType(user_data.address);\n      if (addressType === 'object' || addressType === 'array') {\n        address = user_data.address[0] || user_data.address;\n      }\n    }\n\n    if (fbc) mappedData.user_data.fbc = fbc;\n    if (fbp) mappedData.user_data.fbp = fbp;\n\n    if (eventData.user_agent) mappedData.user_data.client_user_agent = eventData.user_agent;\n\n    if (eventData.ip_override) {\n      mappedData.user_data.client_ip_address = eventData.ip_override\n        .split(' ')\n        .join('')\n        .split(',')[0];\n    }\n\n    if (eventData.fb_login_id) mappedData.user_data.fb_login_id = eventData.fb_login_id;\n\n    if (eventData.anon_id) mappedData.user_data.anon_id = eventData.anon_id;\n\n    if (eventData.madid) mappedData.user_data.madid = eventData.madid;\n\n    const externalId = eventData.external_id || eventData.user_id || eventData.userId;\n    if (externalId) mappedData.user_data.external_id = externalId;\n\n    const subscriptionId = eventData.subscription_id || eventData.subscriptionId;\n    if (subscriptionId) mappedData.user_data.subscription_id = subscriptionId;\n\n    const leadId = eventData.lead_id || eventData.leadId;\n    if (leadId) mappedData.user_data.lead_id = leadId;\n\n    const ln =\n      eventData.lastName ||\n      eventData.LastName ||\n      eventData.nameLast ||\n      eventData.last_name ||\n      user_data.last_name ||\n      address.last_name ||\n      address.sha256_last_name;\n    if (ln) mappedData.user_data.ln = ln;\n\n    const fn =\n      eventData.firstName ||\n      eventData.FirstName ||\n      eventData.nameFirst ||\n      eventData.first_name ||\n      user_data.first_name ||\n      address.first_name ||\n      address.sha256_first_name;\n    if (fn) mappedData.user_data.fn = fn;\n\n    const em =\n      eventData.email ||\n      user_data.email_address ||\n      user_data.email ||\n      user_data.sha256_email_address;\n    if (em) mappedData.user_data.em = em;\n\n    const ph = eventData.phone || user_data.phone_number || user_data.phone;\n    if (ph) mappedData.user_data.ph = ph;\n\n    const ct = eventData.city || address.city;\n    if (ct) mappedData.user_data.ct = ct;\n\n    const st = eventData.state || eventData.region || user_data.region || address.region;\n    if (st) mappedData.user_data.st = st;\n\n    const zp =\n      eventData.zip || eventData.postal_code || user_data.postal_code || address.postal_code;\n    if (zp) mappedData.user_data.zp = zp;\n\n    const country =\n      eventData.countryCode || eventData.country || user_data.country || address.country;\n    if (country) mappedData.user_data.country = country;\n\n    if (eventData.gender) mappedData.user_data.ge = eventData.gender;\n    if (eventData.db) mappedData.user_data.db = eventData.db;\n  }\n  return mappedData;\n}\n\nfunction addServerEventData(data, eventData, mappedData) {\n  const autoMapEnabled = data.hasOwnProperty('autoMapServerEventData')\n    ? data.autoMapServerEventData\n    : true; // To avoid a breaking change.\n  if (autoMapEnabled) {\n    if (eventData.page_location) mappedData.event_source_url = eventData.page_location;\n    if (eventData.page_referrer) mappedData.referrer_url = eventData.page_referrer;\n\n    const eventId = eventData.event_id || eventData.transaction_id;\n    if (eventId) mappedData.event_id = eventId;\n  }\n\n  if (data.serverEventDataList) {\n    const required = ['event_time'];\n\n    data.serverEventDataList.forEach((d) => {\n      // A required field can be replaced but not cleared, so an empty one is ignored.\n      if (required.indexOf(d.name) !== -1 && !isValidValue(d.value)) return;\n      mappedData[d.name] = d.value;\n    });\n\n    if (\n      !mappedData.data_processing_options &&\n      (mappedData.data_processing_options_country || mappedData.data_processing_options_state)\n    ) {\n      mappedData.data_processing_options_country = undefined;\n      mappedData.data_processing_options_state = undefined;\n    }\n  }\n\n  return mappedData;\n}\n\nfunction addAppData(data, eventData, mappedData) {\n  if (mappedData.action_source !== 'app') {\n    return mappedData;\n  }\n\n  const autoMapEnabled = data.hasOwnProperty('autoMapAppData') ? data.autoMapAppData : true; // To avoid a breaking change.\n  if (autoMapEnabled) {\n    if (getType(eventData.app_data) === 'object') {\n      mappedData.app_data = eventData.app_data;\n      return mappedData;\n    }\n\n    mappedData.app_data.advertiser_tracking_enabled = eventData.advertiser_tracking_enabled ? 1 : 0; // Required\n    mappedData.app_data.application_tracking_enabled = eventData.application_tracking_enabled\n      ? 1\n      : 0; // Required\n    if (eventData.extinfo) {\n      mappedData.app_data.extinfo = eventData.extinfo;\n    } else {\n      const platform = makeString(eventData['x-ga-platform'] || '').toLowerCase();\n      const extinfoArray = [\n        platform === 'android' ? 'a2' : platform === 'ios' ? 'i2' : '', // Required\n        eventData.app_id || '',\n        eventData.app_version || '',\n        eventData.app_version ? 'Version ' + eventData.app_version : '',\n        makeString(eventData['x-ga-os_version'] || ''), // Required\n        eventData['x-ga-device_model'] || '',\n        eventData.language || '',\n        '',\n        '',\n        '',\n        '',\n        '',\n        '',\n        '',\n        '',\n        ''\n      ];\n      mappedData.app_data.extinfo = extinfoArray;\n    }\n    if (eventData.campaign_ids) mappedData.app_data.campaign_ids = eventData.campaign_ids;\n    if (eventData.install_referrer)\n      mappedData.app_data.install_referrer = eventData.install_referrer;\n    if (eventData.installer_package)\n      mappedData.app_data.installer_package = eventData.installer_package;\n    if (eventData.url_schemes) mappedData.app_data.url_schemes = eventData.url_schemes;\n    if (eventData.vendor_id) mappedData.app_data.vendor_id = eventData.vendor_id;\n    if (eventData.windows_attribution_id)\n      mappedData.app_data.windows_attribution_id = eventData.windows_attribution_id;\n  }\n\n  return mappedData;\n}\n\nfunction addOriginalEventData(mappedData) {\n  if (mappedData.event_name !== 'AppendValue') {\n    return mappedData;\n  }\n\n  if (data.originalEventDataList) {\n    mappedData.action_source = undefined;\n\n    mappedData.original_event_data = {};\n    data.originalEventDataList.forEach((d) => {\n      mappedData.original_event_data[d.name] = d.value;\n    });\n  }\n\n  return mappedData;\n}\n\nfunction setGtmEecCookie(userData) {\n  const gtmeecCookie = {};\n\n  if (userData.em) gtmeecCookie.em = userData.em;\n  if (userData.ph) gtmeecCookie.ph = userData.ph;\n  if (userData.ln) gtmeecCookie.ln = userData.ln;\n  if (userData.fn) gtmeecCookie.fn = userData.fn;\n  if (userData.ct) gtmeecCookie.ct = userData.ct;\n  if (userData.st) gtmeecCookie.st = userData.st;\n  if (userData.zp) gtmeecCookie.zp = userData.zp;\n  if (userData.ge) gtmeecCookie.ge = userData.ge;\n  if (userData.db) gtmeecCookie.db = userData.db;\n  if (userData.country) gtmeecCookie.country = userData.country;\n  if (userData.external_id) gtmeecCookie.external_id = userData.external_id;\n  if (userData.fb_login_id) gtmeecCookie.fb_login_id = userData.fb_login_id;\n\n  setCookie('_gtmeec', toBase64(JSON.stringify(gtmeecCookie)), {\n    domain: isUIFieldTrue(data.overrideCookieDomain)\n      ? data.overridenCookieDomain || 'auto'\n      : 'auto',\n    path: '/',\n    samesite: 'strict',\n    secure: true,\n    'max-age': 7776000, // 90 days\n    HttpOnly: true\n  });\n}\n\nfunction enhanceEventData(eventData, userData) {\n  const commonCookie = eventData.common_cookie || {};\n\n  const cookieValues = getCookieValues('_gtmeec');\n  if ((!cookieValues || cookieValues.length === 0) && !commonCookie._gtmeec) {\n    return userData;\n  }\n\n  const encodedValue = cookieValues[0] || commonCookie._gtmeec;\n  if (!encodedValue) {\n    return userData;\n  }\n\n  const jsonStr = fromBase64(encodedValue);\n  if (!jsonStr) {\n    return userData;\n  }\n\n  const gtmeecData = JSON.parse(jsonStr);\n\n  if (getType(gtmeecData) !== 'object') {\n    return userData;\n  }\n\n  const keys = 'em,ph,ln,fn,ct,st,zp,ge,db,country,external_id,fb_login_id'.split(',');\n  keys.forEach((key) => {\n    const value = gtmeecData[key];\n    const valueType = getType(value);\n    if (userData[key] || (valueType !== 'string' && valueType !== 'number')) return;\n    if (isValidValue(value)) userData[key] = value;\n  });\n\n  return userData;\n}\n\nfunction sendRequests(data, mappedPostBody) {\n  let pixelsConfig = [\n    {\n      pixelId: data.pixelId,\n      accessToken: data.accessToken,\n      appSecretProof: data.useAppSecretProof ? data.appSecretProof : undefined\n    }\n  ];\n  if (data.enableMultipixelSetup) {\n    pixelsConfig = pixelsConfig.concat(data.pixelIdAndAccessTokenTable);\n  }\n\n  const requests = pixelsConfig.map((pixelConfig) => {\n    const pixelId = pixelConfig.pixelId;\n    const accessToken = pixelConfig.accessToken;\n    const appSecretProof = pixelConfig.appSecretProof;\n    const postUrl =\n      'https://graph.facebook.com/v' +\n      API_VERSION +\n      '/' +\n      enc(pixelId) +\n      '/events?access_token=' +\n      enc(accessToken) +\n      (appSecretProof ? '&appsecret_proof=' + enc(appSecretProof) : '');\n\n    return sendHttpRequest(\n      postUrl,\n      { headers: { 'content-type': 'application/json' }, method: 'POST' },\n      JSON.stringify(mappedPostBody)\n    )\n      .then((result) => {\n        if (result.statusCode < 200 || result.statusCode >= 300) return false;\n        return true;\n      })\n      .catch((result) => {\n        return false;\n      });\n  });\n\n  Promise.all(requests)\n    .then((results) => {\n      if (!data.useOptimisticScenario) {\n        const someRequestFailed = results.some((success) => !success);\n        if (someRequestFailed) return data.gtmOnFailure();\n        return data.gtmOnSuccess();\n      }\n    })\n    .catch((result) => {\n      if (!data.useOptimisticScenario) return data.gtmOnFailure();\n    });\n}\n\n/*==============================================================================\n  Helpers\n==============================================================================*/\n\nfunction getUrl(eventData) {\n  return eventData.page_location || getRequestHeader('referer') || eventData.page_referrer;\n}\n\nfunction shouldExitEarly(data, eventData) {\n  if (!isConsentGivenOrNotRequired(data, eventData)) return true;\n\n  const url = getUrl(eventData);\n  if (url && url.lastIndexOf('https://gtm-msr.appspot.com/', 0) === 0) return true;\n\n  return false;\n}\n\nfunction enc(data) {\n  if (['null', 'undefined'].indexOf(getType(data)) !== -1) data = '';\n  return encodeUriComponent(makeString(data));\n}\n\nfunction isHashed(value) {\n  if (!value) return false;\n  return makeString(value).match('^[A-Fa-f0-9]{64}$') !== null;\n}\n\nfunction isValidValue(value) {\n  const valueType = getType(value);\n  if (valueType === 'null' || valueType === 'undefined' || value !== value) return false;\n  return value !== '' && value !== 'undefined' && value !== 'null';\n}\n\nfunction toFiniteNumber(value) {\n  if (!isValidValue(value)) return undefined;\n\n  const valueType = getType(value);\n  if (valueType !== 'number' && valueType !== 'string') return undefined;\n  if (valueType === 'string' && value.trim() === '') return undefined; // Whitespace coerces to 0.\n\n  const parsed = makeNumber(value);\n  if (parsed * 0 !== 0) return undefined; // Rejects NaN and +/-Infinity.\n\n  return parsed;\n}\n\nfunction normalizePhoneNumber(phoneNumber) {\n  if (!phoneNumber) return phoneNumber;\n  const itemRegex = createRegex('^[0-9]$');\n  return phoneNumber\n    .split('')\n    .filter((item) => testRegex(itemRegex, item))\n    .join('');\n}\n\nfunction isUIFieldTrue(field) {\n  return [true, 'true'].indexOf(field) !== -1;\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 isConsentGivenOrNotRequired(data, eventData) {\n  if (data.adStorageConsent !== 'required') return true;\n  if (eventData.consent_state) return !!eventData.consent_state.ad_storage;\n  const xGaGcs = eventData['x-ga-gcs'] || ''; // x-ga-gcs is a string like \"G110\"\n  return xGaGcs[2] === '1';\n}\n\n\n___SERVER_PERMISSIONS___\n\n[\n  {\n    \"instance\": {\n      \"key\": {\n        \"publicId\": \"read_event_data\",\n        \"versionId\": \"1\"\n      },\n      \"param\": [\n        {\n          \"key\": \"eventDataAccess\",\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\": \"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\": \"_fbc\"\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                \"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\": \"_fbp\"\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                \"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\": \"_gtmeec\"\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\": \"send_http\",\n        \"versionId\": \"1\"\n      },\n      \"param\": [\n        {\n          \"key\": \"allowedUrls\",\n          \"value\": {\n            \"type\": 1,\n            \"string\": \"specific\"\n          }\n        },\n        {\n          \"key\": \"urls\",\n          \"value\": {\n            \"type\": 2,\n            \"listItem\": [\n              {\n                \"type\": 1,\n                \"string\": \"https://graph.facebook.com/\"\n              }\n            ]\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\": \"_fbc\"\n              },\n              {\n                \"type\": 1,\n                \"string\": \"_fbp\"\n              },\n              {\n                \"type\": 1,\n                \"string\": \"_gtmeec\"\n              }\n            ]\n          }\n        }\n      ]\n    },\n    \"clientAnnotations\": {\n      \"isEditedByUser\": true\n    },\n    \"isRequired\": true\n  },\n  {\n    \"instance\": {\n      \"key\": {\n        \"publicId\": \"read_request\",\n        \"versionId\": \"1\"\n      },\n      \"param\": [\n        {\n          \"key\": \"headerWhitelist\",\n          \"value\": {\n            \"type\": 2,\n            \"listItem\": [\n              {\n                \"type\": 3,\n                \"mapKey\": [\n                  {\n                    \"type\": 1,\n                    \"string\": \"headerName\"\n                  }\n                ],\n                \"mapValue\": [\n                  {\n                    \"type\": 1,\n                    \"string\": \"referer\"\n                  }\n                ]\n              }\n            ]\n          }\n        },\n        {\n          \"key\": \"headersAllowed\",\n          \"value\": {\n            \"type\": 8,\n            \"boolean\": true\n          }\n        },\n        {\n          \"key\": \"requestAccess\",\n          \"value\": {\n            \"type\": 1,\n            \"string\": \"specific\"\n          }\n        },\n        {\n          \"key\": \"headerAccess\",\n          \"value\": {\n            \"type\": 1,\n            \"string\": \"specific\"\n          }\n        },\n        {\n          \"key\": \"queryParameterAccess\",\n          \"value\": {\n            \"type\": 1,\n            \"string\": \"any\"\n          }\n        }\n      ]\n    },\n    \"clientAnnotations\": {\n      \"isEditedByUser\": true\n    },\n    \"isRequired\": true\n  }\n]\n\n\n___TESTS___\n\nscenarios:\n- name: Check semantical errors\n  code: \"mock('sendHttpRequest', (requestUrl, requestOptions, requestBody) => {\\n\\\n    \\  return {\\n    then: (callback) => { \\n      callback({ statusCode: 200 });\\n\\\n    \\      return {\\n        then: () => {},\\n        catch: () => {}\\n      };\\n\\\n    \\    },\\n    catch: (callback) => callback()\\n  };\\n});\\n\\nrunCode(mockData);\"\n- name: '[Cookie] Cookie domain is NOT overriden when option is NOT selected'\n  code: |-\n    mockData.overrideCookieDomain = false;\n    mockData.enableEventEnhancement = true;\n\n    const expectedFbp = 'expectedFbp';\n    const expectedFbc = 'expectedFbc';\n    mock('getAllEventData', {\n      _fbp: expectedFbp,\n      _fbc: expectedFbc\n    });\n\n    mock('setCookie', (cookieName, cookieValue, cookieOptions, noEncode) => {\n      switch (cookieName) {\n        case '_fbp':\n        case '_fbc':\n        case '_gtmeec':\n          if (cookieOptions.domain !== 'auto') fail('cookieDomain shouldn\\'t have been overriden');\n          break;\n      }\n    });\n\n    runCode(mockData);\n\n    callLater(() => {\n      assertApi('gtmOnSuccess').wasCalled();\n      assertApi('gtmOnFailure').wasNotCalled();\n    });\n- name: '[Cookie] Cookie domain is overriden when option is selected'\n  code: |-\n    mockData.overrideCookieDomain = true;\n    mockData.overridenCookieDomain = 'example.com';\n    mockData.enableEventEnhancement = true;\n\n    const expectedFbp = 'expectedFbp';\n    const expectedFbc = 'expectedFbc';\n    mock('getAllEventData', {\n      _fbp: expectedFbp,\n      _fbc: expectedFbc\n    });\n\n    mock('setCookie', (cookieName, cookieValue, cookieOptions, noEncode) => {\n      switch (cookieName) {\n        case '_fbp':\n        case '_fbc':\n        case '_gtmeec':\n          assertThat(cookieOptions.domain).isEqualTo(mockData.overridenCookieDomain);\n          break;\n      }\n    });\n\n    runCode(mockData);\n\n    callLater(() => {\n      assertApi('gtmOnSuccess').wasCalled();\n      assertApi('gtmOnFailure').wasNotCalled();\n    });\n- name: '[Action Source = App] Request is sent successfully when using Event Data\n    as source'\n  code: \"mockData.generateFbp = false;\\nmockData.actionSource = 'app';\\nmockData.appDataList\\\n    \\ = undefined;\\nmockData.eventName = 'custom';\\n\\nmock('getAllEventData', {\\n\\\n    \\  app_data: {\\n    advertiser_tracking_enabled: 1,\\n    application_tracking_enabled:\\\n    \\ 0,\\n    extinfo: [\\n      'a2',\\n      'app_id',\\n      'app_version',\\n   \\\n    \\   'Version app_version',\\n      'os_version',\\n      'device_model',\\n     \\\n    \\ 'language',\\n      '',\\n      '',\\n      '',\\n      '',\\n      '',\\n      '',\\n\\\n    \\      '',\\n      '',\\n      ''\\n    ],\\n    campaign_ids: 'expected-campaign_ids',\\n\\\n    \\    install_referrer: 'expected-install_referrer',\\n    installer_package: 'expected-installer_package',\\\n    \\ \\n    url_schemes: ['foobar', 'abcdef'],\\n    vendor_id: 'expected-vendor_id',\\n\\\n    \\    windows_attribution_id: 'expected-windows_attribution_id'\\n  }\\n});\\n\\nconst\\\n    \\ expectedRequestBody = {\\n  data: [\\n    {\\n      event_name: 'test',\\n     \\\n    \\ action_source: 'app',\\n      event_time: 1747945830,\\n      custom_data: {},\\n\\\n    \\      user_data: {},\\n      app_data: {\\n        advertiser_tracking_enabled:\\\n    \\ 1,\\n        application_tracking_enabled: 0,\\n        extinfo: [\\n         \\\n    \\ 'a2',\\n          'app_id',\\n          'app_version',\\n          'Version app_version',\\n\\\n    \\          'os_version',\\n          'device_model',\\n          'language',\\n \\\n    \\         '',\\n          '',\\n          '',\\n          '',\\n          '',\\n  \\\n    \\        '',\\n          '',\\n          '',\\n          ''\\n        ],\\n       \\\n    \\ campaign_ids: 'expected-campaign_ids',\\n        install_referrer: 'expected-install_referrer',\\n\\\n    \\        installer_package: 'expected-installer_package',\\n        url_schemes:\\\n    \\ ['foobar', 'abcdef'],\\n        vendor_id: 'expected-vendor_id',\\n        windows_attribution_id:\\\n    \\ 'expected-windows_attribution_id'\\n      }\\n    }\\n  ],\\n  partner_agent: expectedPartnerAgent\\n\\\n    };\\n\\nmock('sendHttpRequest', (requestUrl, requestOptions, requestBody) => {\\n\\\n    \\  const parsedBody = JSON.parse(requestBody);\\n  assertThat(parsedBody).isEqualTo(expectedRequestBody);\\n\\\n    \\  return Promise.create((resolve, reject) => {\\n    resolve({ statusCode: 200\\\n    \\ });\\n  });    \\n});\\n\\nrunCode(mockData);\\n\\ncallLater(() => {\\n  assertApi('gtmOnSuccess').wasCalled();\\n\\\n    \\  assertApi('gtmOnFailure').wasNotCalled();\\n});\"\n- name: '[Action Source = App] Request is sent successfully when using UI data as\n    source'\n  code: \"mockData.generateFbp = false;\\nmockData.actionSource = 'app';\\nmockData.appDataList\\\n    \\ = [\\n  { name: 'advertiser_tracking_enabled', value: '1' },\\n  { name: 'application_tracking_enabled',\\\n    \\ value: '0' },\\n  { \\n   name: 'extinfo',\\n   value: \\n     [\\n      'a2',\\n\\\n    \\      'app_id',\\n      'app_version',\\n      'Version app_version',\\n      'os_version',\\n\\\n    \\      'device_model',\\n      'language',\\n      '',\\n      '',\\n      '',\\n \\\n    \\     '',\\n      '',\\n      '',\\n      '',\\n      '',\\n      ''\\n    ]\\n  },\\n\\\n    \\  { name: 'campaign_ids', value: 'expected-campaign_ids' },\\n  { name: 'install_referrer',\\\n    \\ value: 'expected-install_referrer' },\\n  { name: 'installer_package', value:\\\n    \\ 'expected-installer_package' }, \\n  { name: 'url_schemes', value: ['foobar',\\\n    \\ 'abcdef'] },\\n  { name: 'vendor_id', value: 'expected-vendor_id' },\\n  { name:\\\n    \\ 'windows_attribution_id', value: 'expected-windows_attribution_id' }\\n];\\nmockData.eventName\\\n    \\ = 'custom';\\n\\nmock('getAllEventData', {});\\n\\nconst expectedRequestBody = {\\n\\\n    \\  data: [\\n    {\\n      event_name: 'test',\\n      action_source: 'app',\\n  \\\n    \\    event_time: 1747945830,\\n      custom_data: {},\\n      user_data: {},\\n \\\n    \\     app_data: {\\n        advertiser_tracking_enabled: '1',\\n        application_tracking_enabled:\\\n    \\ '0',\\n        extinfo: [\\n          'a2',\\n          'app_id',\\n          'app_version',\\n\\\n    \\          'Version app_version',\\n          'os_version',\\n          'device_model',\\n\\\n    \\          'language',\\n          '',\\n          '',\\n          '',\\n        \\\n    \\  '',\\n          '',\\n          '',\\n          '',\\n          '',\\n         \\\n    \\ ''\\n        ],\\n        campaign_ids: 'expected-campaign_ids',\\n        install_referrer:\\\n    \\ 'expected-install_referrer',\\n        installer_package: 'expected-installer_package',\\n\\\n    \\        url_schemes: ['foobar', 'abcdef'],\\n        vendor_id: 'expected-vendor_id',\\n\\\n    \\        windows_attribution_id: 'expected-windows_attribution_id'\\n      }\\n\\\n    \\    }\\n  ],\\n  partner_agent: expectedPartnerAgent\\n};\\n\\nmock('sendHttpRequest',\\\n    \\ (requestUrl, requestOptions, requestBody) => {\\n  const parsedBody = JSON.parse(requestBody);\\n\\\n    \\  assertThat(parsedBody).isEqualTo(expectedRequestBody);\\n  return Promise.create((resolve,\\\n    \\ reject) => {\\n    resolve({ statusCode: 200 });\\n  });    \\n});\\n\\nrunCode(mockData);\\n\\\n    \\ncallLater(() => {\\n  assertApi('gtmOnSuccess').wasCalled();\\n  assertApi('gtmOnFailure').wasNotCalled();\\n\\\n    });\"\n- name: '[Event = AppendValue] Request is sent successfully'\n  code: \"mockData.inheritEventName = 'override';\\nmockData.eventNameCustom = 'AppendValue';\\n\\\n    mockData.eventName = 'custom';\\nmockData.generateFbp = false;\\nmockData.actionSource\\\n    \\ = 'website';\\nmockData.userDataList = [\\n  { name: 'em', value: 'test' },\\n\\\n    \\  { name: 'ph', value: 'test' }\\n];\\nmockData.customDataList = [\\n  { name: 'currency',\\\n    \\ value: 'BRL' },\\n  { name: 'net_revenue', value: 123 }\\n];\\nmockData.originalEventDataList\\\n    \\ = [\\n  { name: 'event_name', value: 'Purchase' },\\n  { name: 'event_time', value:\\\n    \\ 17555555 },\\n  { name: 'order_id', value: 'foobar123' },\\n  { name: 'event_id',\\\n    \\ value: '1747945830' }\\n];\\n\\nmock('getAllEventData', {});\\n\\nconst expectedRequestBody\\\n    \\ = {\\n  data: [\\n    {\\n      event_name: 'AppendValue',\\n      event_time: 1747945830,\\n\\\n    \\      custom_data: { currency: 'BRL', net_revenue: 123 },\\n      user_data: {\\n\\\n    \\        em: '9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08',\\n\\\n    \\        ph: 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855'\\n\\\n    \\      },\\n      original_event_data: {\\n        event_name: 'Purchase',\\n   \\\n    \\     event_time: 17555555,\\n        order_id: 'foobar123',\\n        event_id:\\\n    \\ '1747945830'\\n      }\\n    }\\n  ],\\n  partner_agent: expectedPartnerAgent\\n\\\n    };\\n\\nmock('sendHttpRequest', (requestUrl, requestOptions, requestBody) => {\\n\\\n    \\  const parsedBody = JSON.parse(requestBody);\\n  assertThat(parsedBody).isEqualTo(expectedRequestBody);\\n\\\n    \\  return Promise.create((resolve, reject) => {\\n    resolve({ statusCode: 200\\\n    \\ });\\n  });    \\n});\\n\\nrunCode(mockData);\\n\\ncallLater(() => {\\n  assertApi('gtmOnSuccess').wasCalled();\\n\\\n    \\  assertApi('gtmOnFailure').wasNotCalled();\\n});\"\n- name: '[Parameters from Object or List] Parameters are read and sent succesfullly'\n  code: \"mockData.actionSource = 'app'; // Using 'app' just to have access to the\\\n    \\ App Data section.\\n\\n[\\n  // Object empty, list empty\\n  {\\n    mockDataObj:\\\n    \\ {\\n      appDataObject: undefined,\\n      appDataList: undefined,\\n      userDataObject:\\\n    \\ undefined,\\n      userDataList: undefined,\\n      customDataObject: undefined,\\n\\\n    \\      customDataList: undefined\\n    },\\n    expectedRequestBody: {\\n      appData:\\\n    \\ {\\n        advertiser_tracking_enabled: 0,\\n        application_tracking_enabled:\\\n    \\ 0,\\n        extinfo: ['', '', '', '', '', '', '', '', '', '', '', '', '', '',\\\n    \\ '', '']\\n      },\\n      userData: {},\\n      customData: {}\\n    }\\n  },\\n\\\n    \\  \\n  // Object empty, list not-empty\\n  {\\n    mockDataObj: {\\n      appDataObject:\\\n    \\ undefined,\\n      appDataList: [\\n        { name: 'vendor_id', value: 'vendor_id'\\\n    \\ },\\n        { name: 'campaign_ids', value: 'campaign_ids' }\\n      ],\\n    \\\n    \\  userDataObject: undefined,\\n      userDataList: [{ name: 'fn', value: 'test'\\\n    \\ }],\\n      customDataObject: undefined,\\n      customDataList: [\\n        {\\\n    \\ name: 'currency', value: 'BRL' },\\n        { name: 'net_revenue', value: 123\\\n    \\ },\\n        { name: 'test', value: 'test' }\\n      ]\\n    },\\n    expectedRequestBody:\\\n    \\ {\\n      appData: {\\n        advertiser_tracking_enabled: 0,\\n        application_tracking_enabled:\\\n    \\ 0,\\n        extinfo: ['', '', '', '', '', '', '', '', '', '', '', '', '', '',\\\n    \\ '', ''],\\n        vendor_id: 'vendor_id',\\n        campaign_ids: 'campaign_ids'\\n\\\n    \\      },\\n      userData: { fn: '9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08'\\\n    \\ },\\n      customData: { currency: 'BRL', net_revenue: 123, test: 'test' }\\n\\\n    \\    }\\n  },\\n  \\n  // Object not-empty, list empty\\n  {\\n    mockDataObj: {\\n\\\n    \\      appDataObject: { vendor_id: 'vendor_id_obj' },\\n      appDataList: undefined,\\n\\\n    \\      userDataObject: { em: 'test@example.com_obj' },\\n      userDataList: undefined,\\n\\\n    \\      customDataObject: { test: 'test_obj' },\\n      customDataList: undefined\\n\\\n    \\    },\\n    expectedRequestBody: {\\n      appData: {\\n        advertiser_tracking_enabled:\\\n    \\ 0,\\n        application_tracking_enabled: 0,\\n        extinfo: ['', '', '',\\\n    \\ '', '', '', '', '', '', '', '', '', '', '', '', ''],\\n        vendor_id: 'vendor_id_obj'\\n\\\n    \\      },\\n      userData: { em: '0217a86a7b92e2511273b0081bfc67f939b7f9a897d960849690056732795b3d'\\\n    \\ },\\n      customData: { test: 'test_obj' }\\n    }\\n  },\\n  \\n  // Object not-empty\\\n    \\ and list not-empty, with different values each.\\n  {\\n    mockDataObj: {\\n \\\n    \\     appDataObject: { vendor_id: 'vendor_id_obj' },\\n      appDataList: [\\n \\\n    \\       { name: 'campaign_ids', value: 'campaign_ids' }\\n      ],\\n      userDataObject:\\\n    \\ { em: 'test@example.com_obj' },\\n      userDataList: [{ name: 'fn', value: 'test'\\\n    \\ }],\\n      customDataObject: { test: 'test_obj' },\\n      customDataList: [\\n\\\n    \\        { name: 'currency', value: 'BRL' },\\n        { name: 'net_revenue', value:\\\n    \\ 123 }\\n      ],\\n    },\\n    expectedRequestBody: {\\n      appData: {\\n    \\\n    \\    advertiser_tracking_enabled: 0,\\n        application_tracking_enabled: 0,\\n\\\n    \\        extinfo: ['', '', '', '', '', '', '', '', '', '', '', '', '', '', '',\\\n    \\ ''],\\n        vendor_id: 'vendor_id_obj',\\n        campaign_ids: 'campaign_ids'\\n\\\n    \\      },\\n      userData: { em: '0217a86a7b92e2511273b0081bfc67f939b7f9a897d960849690056732795b3d',\\\n    \\ fn: '9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08' },\\n\\\n    \\      customData: { test: 'test_obj', currency: 'BRL', net_revenue: 123 }\\n \\\n    \\   }\\n  },\\n  \\n  // Object not-empty and list not-empty, with overlapping values.\\\n    \\ Should favor list.\\n  {\\n    mockDataObj: {\\n      appDataObject: { vendor_id:\\\n    \\ 'vendor_id_obj' },\\n      appDataList: [\\n        { name: 'vendor_id', value:\\\n    \\ 'vendor_id' },\\n        { name: 'campaign_ids', value: 'campaign_ids' }\\n  \\\n    \\    ],\\n      userDataObject: { em: 'test@example.com_obj' },\\n      userDataList:\\\n    \\ [{ name: 'fn', value: 'test' }, { name: 'em', value: 'test' }],\\n      customDataObject:\\\n    \\ { test: 'test_obj' },\\n      customDataList: [\\n        { name: 'currency',\\\n    \\ value: 'BRL' },\\n        { name: 'net_revenue', value: 123 },\\n        { name:\\\n    \\ 'test', value: 'test' }\\n      ],\\n    },\\n    expectedRequestBody: {\\n    \\\n    \\  appData: {\\n        advertiser_tracking_enabled: 0,\\n        application_tracking_enabled:\\\n    \\ 0,\\n        extinfo: ['', '', '', '', '', '', '', '', '', '', '', '', '', '',\\\n    \\ '', ''],\\n        vendor_id: 'vendor_id',\\n        campaign_ids: 'campaign_ids'\\n\\\n    \\      },\\n      userData: { em: '9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08',\\\n    \\ fn: '9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08' },\\n\\\n    \\      customData: { test: 'test', currency: 'BRL', net_revenue: 123 }\\n    }\\n\\\n    \\  }\\n].forEach((scenario, index) => {\\n  const copyMockData = JSON.parse(JSON.stringify(mockData));\\n\\\n    \\  mergeObj(copyMockData, scenario.mockDataObj);\\n  \\n  mock('sendHttpRequest',\\\n    \\ (requestUrl, requestOptions, requestBody) => {\\n    const parsedBody = JSON.parse(requestBody);\\n\\\n    \\    assertThat(parsedBody.data[0].app_data).isEqualTo(scenario.expectedRequestBody.appData);\\n\\\n    \\    assertThat(parsedBody.data[0].user_data).isEqualTo(scenario.expectedRequestBody.userData);\\n\\\n    \\    assertThat(parsedBody.data[0].custom_data).isEqualTo(scenario.expectedRequestBody.customData);\\n\\\n    \\    return Promise.create((resolve, reject) => {\\n      resolve({ statusCode:\\\n    \\ 200 });\\n    });\\n  });\\n  \\n  runCode(copyMockData);\\n  \\n  callLater(() =>\\\n    \\ {\\n    assertApi('gtmOnSuccess').wasCalled();\\n    assertApi('gtmOnFailure').wasNotCalled();\\n\\\n    \\  });\\n});\"\n- name: '[App Secret Proof] App Secret Proof is handled and sent succesfully'\n  code: \"mockData.useAppSecretProof = true;\\nmockData.appSecretProof = 'appSecretProof1';\\n\\\n    \\nmock('sendHttpRequest', (requestUrl, requestOptions, requestBody) => {\\n  const\\\n    \\ pixelId = mockData.pixelId;\\n  const accessToken = mockData.accessToken;\\n \\\n    \\ const appSecretProof = mockData.appSecretProof;\\n  \\n  assertThat(requestUrl).isEqualTo(\\n\\\n    \\    'https://graph.facebook.com/v' + expectedApiVersion + '/' + pixelId + \\n\\\n    \\    '/events?access_token=' + accessToken +\\n    '&appsecret_proof=' + appSecretProof\\n\\\n    \\  );\\n\\n  return Promise.create((resolve, reject) => {\\n    resolve({ statusCode:\\\n    \\ 200 });\\n  });  \\n});\\n\\nrunCode(mockData);\\n\\ncallLater(() => {\\n  assertApi('gtmOnSuccess').wasCalled();\\n\\\n    \\  assertApi('gtmOnFailure').wasNotCalled();\\n});\"\n- name: gtmOnFailure handler is called if a request fails, rejects, or Promise all\n    rejects\n  code: |-\n    [\n      // A request resolves with a non-200 status code.\n      () => {\n        let requestCount = 0;\n        mock('sendHttpRequest', (requestUrl, requestOptions, requestBody) => {\n          requestCount++;\n          const statusCode = requestCount === 1 ? 500 : 200;\n          return Promise.create((resolve, reject) => {\n            resolve({ statusCode: statusCode });\n          });\n        });\n      },\n      // A request rejects outright.\n      () => {\n        let requestCount = 0;\n        mock('sendHttpRequest', (requestUrl, requestOptions, requestBody) => {\n          requestCount++;\n          return Promise.create((resolve, reject) => {\n            if (requestCount === 1) reject({ reason: 'failed' });\n            else resolve({ statusCode: 200 });\n          });\n        });\n      },\n      // Every request succeeds, but Promise.all itself rejects.\n      () => {\n        mock('sendHttpRequest', (requestUrl, requestOptions, requestBody) => {\n          return Promise.create((resolve, reject) => {\n            resolve({ statusCode: 200 });\n          });\n        });\n        mockObject('Promise', {\n          all: () => Promise.create((resolve, reject) => reject({ reason: 'failed' }))\n        });\n      }\n    ].forEach((setupFailure) => {\n      mockData.enableMultipixelSetup = true;\n      mockData.pixelIdAndAccessTokenTable = [\n        {\n          pixelId: 'pixelId2',\n          accessToken: 'accessToken2',\n          appSecretProof: 'appSecretProof2'\n        }\n      ];\n\n      setupFailure();\n\n      runCode(mockData);\n\n      callLater(() => {\n        assertApi('gtmOnSuccess').wasNotCalled();\n        assertApi('gtmOnFailure').wasCalled();\n      });\n    });\n- name: '[Event Name] Resolves across setup-method, override and fallback scenarios'\n  code: |-\n    [\n      // Setup method unset: behaves as inherit.\n      { inheritEventName: undefined, eventData: { event_name: 'purchase' }, expected: 'Purchase' },\n      { inheritEventName: undefined, eventData: {}, expected: undefined },\n\n      // Explicit inherit with nothing to map.\n      { inheritEventName: 'inherit', eventData: {}, expected: undefined },\n\n      // Override, standard selected but left blank: falls back to the mapped incoming name.\n      {\n        inheritEventName: 'override',\n        eventName: 'standard',\n        eventData: { event_name: 'purchase' },\n        expected: 'Purchase'\n      },\n      // Override, custom selected but blank: falls back to the mapped incoming name.\n      {\n        inheritEventName: 'override',\n        eventName: 'custom',\n        eventNameCustom: '',\n        eventData: { event_name: 'add_to_cart' },\n        expected: 'AddToCart'\n      },\n      // Incomplete override with an incoming name outside the GA4 mapping table: forwarded as-is.\n      {\n        inheritEventName: 'override',\n        eventName: 'standard',\n        eventData: { event_name: 'session_start' },\n        expected: 'session_start'\n      },\n      // Incomplete override with no incoming name at all: still sent, unresolved.\n      { inheritEventName: 'override', eventName: 'standard', eventData: {}, expected: undefined },\n\n      // Override, standard event chosen: sent as chosen regardless of the incoming name.\n      {\n        inheritEventName: 'override',\n        eventName: 'standard',\n        eventNameStandard: 'PageView',\n        eventData: { event_name: 'purchase' },\n        expected: 'PageView'\n      },\n      // Incomplete override does not apply the view_item_list mapping, which is scoped to inherit.\n      {\n        inheritEventName: 'override',\n        eventName: 'standard',\n        mapViewItemListToViewContent: true,\n        eventData: { event_name: 'view_item_list' },\n        expected: 'view_item_list'\n      },\n      // Override switched to custom after a standard event was picked: the stale standard value is not reused.\n      {\n        inheritEventName: 'override',\n        eventName: 'custom',\n        eventNameStandard: 'PageView',\n        eventNameCustom: '',\n        eventData: { event_name: 'purchase' },\n        expected: 'Purchase'\n      },\n      // A sentinel string is not treated as a valid override name.\n      {\n        inheritEventName: 'override',\n        eventName: 'custom',\n        eventNameCustom: 'undefined',\n        eventData: {},\n        expected: undefined\n      }\n    ].forEach((scenario) => {\n      const copyMockData = JSON.parse(JSON.stringify(mockData));\n      copyMockData.inheritEventName = scenario.inheritEventName;\n      copyMockData.eventName = scenario.eventName;\n      copyMockData.eventNameStandard = scenario.eventNameStandard;\n      copyMockData.eventNameCustom = scenario.eventNameCustom;\n      copyMockData.mapViewItemListToViewContent = scenario.mapViewItemListToViewContent;\n\n      mock('getAllEventData', scenario.eventData);\n\n      let requestBody;\n      mock('sendHttpRequest', (requestUrl, requestOptions, body) => {\n        requestBody = JSON.parse(body);\n        return Promise.create((resolve) => resolve({ statusCode: 200 }));\n      });\n\n      runCode(copyMockData);\n\n      callLater(() => {\n        assertThat(requestBody.data[0].event_name).isEqualTo(scenario.expected);\n        assertThat(requestBody.data[0].action_source).isEqualTo('website');\n        assertApi('gtmOnSuccess').wasCalled();\n        assertApi('gtmOnFailure').wasNotCalled();\n      });\n    });\n- name: '[Event Name] An absent inherit setting still maps view_item_list to a product\n    group'\n  code: |-\n    mockData.inheritEventName = undefined;\n    mockData.eventNameCustom = undefined;\n    mockData.mapViewItemListToViewContent = true;\n\n    mock('getAllEventData', {\n      event_name: 'view_item_list',\n      items: [{ item_id: 'SKU_1' }, { item_id: 'SKU_2' }]\n    });\n\n    let requestBody;\n    mock('sendHttpRequest', (requestUrl, requestOptions, body) => {\n      requestBody = JSON.parse(body);\n      return Promise.create((resolve) => resolve({ statusCode: 200 }));\n    });\n\n    runCode(mockData);\n\n    callLater(() => {\n      assertThat(requestBody.data[0].event_name).isEqualTo('ViewContent');\n      assertThat(requestBody.data[0].custom_data.content_type).isEqualTo('product_group');\n      assertApi('gtmOnSuccess').wasCalled();\n      assertApi('gtmOnFailure').wasNotCalled();\n    });\n- name: '[Server Event Data] An empty value clears a field unless it is required'\n  code: |-\n    mock('getAllEventData', {\n      event_name: 'purchase',\n      page_location: 'https://example.com/checkout'\n    });\n\n    mockData.serverEventDataList = [\n      { name: 'event_source_url', value: undefined },\n      { name: 'action_source', value: 'undefined' },\n      { name: 'event_time', value: 'undefined' },\n      { name: 'event_id', value: 'order-1' }\n    ];\n\n    let requestBody;\n    mock('sendHttpRequest', (requestUrl, requestOptions, body) => {\n      requestBody = JSON.parse(body);\n      return Promise.create((resolve) => resolve({ statusCode: 200 }));\n    });\n\n    runCode(mockData);\n\n    callLater(() => {\n      assertThat(requestBody.data[0].event_source_url).isEqualTo(undefined);\n      assertThat(requestBody.data[0].action_source).isEqualTo(undefined);\n      assertThat(requestBody.data[0].event_id).isEqualTo('order-1');\n      assertThat(requestBody.data[0].event_time).isEqualTo(1747945830);\n    });\n- name: '[Event Enhancement] Non-scalar cookie values are ignored'\n  code: |-\n    mockData.enableEventEnhancement = true;\n\n    mock('getCookieValues', (name) => {\n      // {\"em\": {\"a\": 1}, \"ct\": \"paris\"}\n      if (name === '_gtmeec') return ['eyJlbSI6IHsiYSI6IDF9LCAiY3QiOiAicGFyaXMifQ=='];\n      return [];\n    });\n\n    let requestBody;\n    mock('sendHttpRequest', (requestUrl, requestOptions, body) => {\n      requestBody = JSON.parse(body);\n      return Promise.create((resolve) => resolve({ statusCode: 200 }));\n    });\n\n    runCode(mockData);\n\n    callLater(() => {\n      assertThat(requestBody.data[0].user_data.em).isUndefined();\n      assertThat(requestBody.data[0].user_data.ct).isDefined();\n    });\n- name: '[Currency] Currency is found on an item other than the first'\n  code: |-\n    mock('getAllEventData', {\n      items: [\n        { item_id: 'sku1', price: 5 },\n        { item_id: 'sku2', price: 7, currency: 'EUR' }\n      ]\n    });\n\n    let requestBody;\n    mock('sendHttpRequest', (requestUrl, requestOptions, body) => {\n      requestBody = JSON.parse(body);\n      return Promise.create((resolve) => resolve({ statusCode: 200 }));\n    });\n\n    runCode(mockData);\n\n    callLater(() => {\n      assertThat(requestBody.data[0].custom_data.currency).isEqualTo('EUR');\n    });\n- name: '[Currency] A price with no currency falls back to the existing default'\n  code: |-\n    mock('getAllEventData', {\n      items: [{ item_id: 'sku1', price: '9.99' }]\n    });\n\n    let requestBody;\n    mock('sendHttpRequest', (requestUrl, requestOptions, body) => {\n      requestBody = JSON.parse(body);\n      return Promise.create((resolve) => resolve({ statusCode: 200 }));\n    });\n\n    runCode(mockData);\n\n    callLater(() => {\n      const customData = requestBody.data[0].custom_data;\n      assertThat(customData.contents[0].id).isEqualTo('sku1');\n      assertThat(customData.contents[0].item_price).isEqualTo(9.99);\n      assertThat(customData.value).isEqualTo(9.99);\n      assertThat(customData.currency).isEqualTo('USD');\n    });\n- name: '[Click ID] A malformed fbclid is not written into the click ID'\n  code: |-\n    mock('getAllEventData', {\n      page_location: 'https://example.com/p?fbclid=%E0%A4%A'\n    });\n    mock('getCookieValues', () => []);\n\n    let requestBody;\n    mock('sendHttpRequest', (requestUrl, requestOptions, body) => {\n      requestBody = JSON.parse(body);\n      return Promise.create((resolve) => resolve({ statusCode: 200 }));\n    });\n\n    runCode(mockData);\n\n    callLater(() => {\n      assertThat(requestBody.data[0].user_data.fbc).isEqualTo(undefined);\n    });\n- name: '[Price] A blank item price still fills in a value on a Purchase event'\n  code: |-\n    mock('getAllEventData', {\n      event_name: 'purchase',\n      items: [{ item_id: 'sku1', price: ' ' }]\n    });\n\n    let requestBody;\n    mock('sendHttpRequest', (requestUrl, requestOptions, body) => {\n      requestBody = JSON.parse(body);\n      return Promise.create((resolve) => resolve({ statusCode: 200 }));\n    });\n\n    runCode(mockData);\n\n    callLater(() => {\n      const customData = requestBody.data[0].custom_data;\n      assertThat(customData.contents[0].item_price).isEqualTo(undefined);\n      // Facebook rejects a Purchase event with no value at all.\n      assertThat(customData.value).isEqualTo('0.00');\n      assertThat(customData.currency).isEqualTo('USD');\n    });\n- name: '[Contents] Mapping item data to content_ids only does not require contents'\n  code: |-\n    mock('getAllEventData', {\n      currency: 'USD',\n      items: [\n        { item_id: 'sku1', price: '12.50 USD' },\n        { item_name: 'no id or price' }\n      ]\n    });\n\n    let requestBody;\n    mock('sendHttpRequest', (requestUrl, requestOptions, body) => {\n      requestBody = JSON.parse(body);\n      return Promise.create((resolve) => resolve({ statusCode: 200 }));\n    });\n\n    runCode(mergeObj({ mapItemDataTo: 'content_ids' }, mockData));\n\n    callLater(() => {\n      const customData = requestBody.data[0].custom_data;\n      assertThat(customData.content_ids).isEqualTo(['sku1']);\n      assertThat(customData.contents).isEqualTo(undefined);\n      assertThat(customData.content_type).isEqualTo('product');\n    });\n- name: '[Price] A malformed price is still rejected'\n  code: |-\n    mock('getAllEventData', {\n      currency: 'EUR',\n      items: [\n        { item_id: 'sku1', price: '1.2.3' },\n        { item_id: 'sku2', price: '3 x 12.50' },\n        { item_id: 'sku3', price: '1,23,456' }\n      ]\n    });\n\n    let requestBody;\n    mock('sendHttpRequest', (requestUrl, requestOptions, body) => {\n      requestBody = JSON.parse(body);\n      return Promise.create((resolve) => resolve({ statusCode: 200 }));\n    });\n\n    runCode(mockData);\n\n    callLater(() => {\n      const contents = requestBody.data[0].custom_data.contents;\n      assertThat(contents[0].item_price).isEqualTo(undefined);\n      assertThat(contents[1].item_price).isEqualTo(undefined);\n      assertThat(contents[2].item_price).isEqualTo(undefined);\n    });\nsetup: \"const JSON = require('JSON');\\nconst Promise = require('Promise');\\nconst\\\n  \\ callLater = require('callLater');\\n\\nconst mergeObj = (target, source) => {\\n\\\n  \\  for (const key in source) {\\n    if (source.hasOwnProperty(key)) target[key]\\\n  \\ = source[key];\\n  }\\n  return target;\\n};\\n\\nconst expectedBigQuerySettings =\\\n  \\ {\\n  logBigQueryProjectId: 'logBigQueryProjectId',\\n  logBigQueryDatasetId: 'logBigQueryDatasetId',\\n\\\n  \\  logBigQueryTableId: 'logBigQueryTableId'\\n};\\n\\nconst requiredConsoleKeys = ['Type',\\\n  \\ 'TraceId', 'Name'];\\nconst requiredBqKeys = ['timestamp', 'type', 'trace_id',\\\n  \\ 'tag_name'];\\nconst expectedBqOptions = { ignoreUnknownValues: true };\\n\\nconst\\\n  \\ expectedValue = 'test';\\nconst expectedPixelId = '1111111111111';\\nconst expectedPartnerAgent\\\n  \\ = 'stape-gtmss-2.1.7';\\nconst expectedApiVersion = '26.0';\\n\\n\\nconst mockData\\\n  \\ = {\\n  pixelId: expectedPixelId,\\n  accessToken: expectedValue,\\n  inheritEventName:\\\n  \\ 'override',\\n  eventNameCustom: expectedValue,\\n  logBigQueryProjectId: expectedBigQuerySettings.logBigQueryProjectId,\\n\\\n  \\  logBigQueryDatasetId: expectedBigQuerySettings.logBigQueryDatasetId,\\n  logBigQueryTableId:\\\n  \\ expectedBigQuerySettings.logBigQueryTableId,\\n};\\n\\nmock('sendHttpRequest', (requestUrl,\\\n  \\ callback, requestOptions, requestBody) => {\\n  if (typeof callback === 'function')\\\n  \\ {\\n    callback(200);\\n  } else {\\n    requestBody = requestOptions;\\n    requestOptions\\\n  \\ = callback;\\n    return Promise.create((resolve, reject) => {\\n      resolve({\\\n  \\ statusCode: 200 });\\n    });  \\n  }\\n});\\n\\nmock('getRequestHeader', (header)\\\n  \\ => {\\n  if (header === 'trace-id') return 'expectedTraceId';\\n});\\n\\nmock('getTimestampMillis',\\\n  \\ 1747945830456);\"\n\n\n___NOTES___\n\n2026-09-02 - Change Notes:\n  - Empty or invalid values are no longer sent to Facebook for any field, preventing malformed requests\n  - Prices and quantities with unusual formatting (e.g. \"$1,234.56\") are no longer guessed at; only plain numbers are accepted, blank or invalid ones are safely skipped\n  - Simplified how the event name is resolved when no override is configured\n  - Bumped partner agent string to 2.1.7\n\n2026-09-01 - Change Notes:\n  - Bumped partner agent string to 2.1.6.\n\n2026-08-28 - Change Notes:\n  - Fix event name being silently blank when the setup method is left unset; it now inherits from the client, as intended\n  - Require a non-empty standard/custom event name on Override, and default the setup method to \"Inherit from client\"\n\n2026-08-25 Change Notes:\n - Add option to map item data to contents, content_ids or both.\n - Bump API version to 26.0.\n\n2026-05-25 Change Notes:\n - Logging removal.\n\n2026-05-20 - Change Notes:\n  - Add four automap toggle checkboxes (Server Event Data, User Data, App Data, Custom Data), each defaulting to true, allowing individual auto-mapping groups to be disabled without affecting manual overrides; existing configurations are unaffected via a hasOwnProperty fallback\n  - Add optional GA4 \"view_item_list\" → \"ViewContent\" mapping (sets content_type to \"product_group\") and move \"Use App Secret Proof\" into a new \"More Settings\" group\n  - Move \"Custom Item ID Key\" into the Custom Data section gated on automap being enabled; improve help texts for \"Inherit from client\" event name, HttpOnly cookies, and Test ID fields\n  - Refactor fbc/fbp resolution, cookie writing, and exit checks into dedicated functions; add page_referrer as a third URL fallback for subdomain index calculation\n  - Bump API version to 25.0 and partner agent to stape-gtmss-2.1.4\n\nCreated on 10/11/2020, 18:14:02\n\n\n",
                "galleryReference": {
                    "host": "github.com",
                    "owner": "stape-io",
                    "repository": "facebook-tag",
                    "version": "0c0e8cb5c299526bbf53649bcf2a28fa919320e4",
                    "signature": "80bac1cfb8796049c465bf1ac8f1125bf81ff263f06d7ef3057c5fad44f1af09",
                    "galleryTemplateId": "5TP8W"
                }
            },
            {
                "accountId": "6374306328",
                "containerId": "262778781",
                "templateId": "18",
                "name": "PixelFly COD Protection",
                "fingerprint": "1791000829716",
                "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\": \"pixelfly_cod_protection\",\n  \"version\": 1,\n  \"securityGroups\": [],\n  \"displayName\": \"PixelFly COD Protection\",\n  \"brand\": {\n    \"id\": \"brand_pixelfly\",\n    \"displayName\": \"PixelFly\",\n    \"thumbnail\": \"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAMAAABg3Am1AAAAIGNIUk0AAHomAACAhAAA+gAAAIDoAAB1MAAA6mAAADqYAAAXcJy6UTwAAAFQUExURfluS/luS/luS/luS/luS/luS/luS/ltSvhtSvlzUfl0U/l0UvluTPl1VPzJvP3f1/3e1v3e1/3Rxvl8XfhtSfl3V/3j3f////7v6/mBY/hsSfmBYvl3VvmAYvhrSPl7W/l6WvmDZf3c1P708f7z8P7z8f3m4PqKbvl4WPl5Wfuum/7q5f7o4v7o4/3j3Pqbg/mEZ/qGafmFaPqSeP3c0/7n4f7m4Py8rPhsSPy6qv729PqLb/hqRvhrR/l/YP7u6vzMv/739fqMcPmAYfzLv/uvnP7r5/7p5P3k3vqagfqRd/7r5vzGufmFZ/mEZvl8XPl7XP3a0f7x7v7y7/3k3funkvuzofl2Vf3i2/7t6fuii/7+/vl2VvuijPlyT/l1U/lyUPutmv3g2fy/sPy/r/7v7PqOc/l+X/y+rv7w7f7x7fuyn/78+/7t6Pl4V//+/rfPao4AAAAGdFJOU/T29/H8+fQOKpMAAAABYktHRBcL1piPAAAACXBIWXMAACxKAAAsSgF3enRNAAAAB3RJTUUH6gEYFA0caUbtKgAAACV0RVh0ZGF0ZTpjcmVhdGUAMjAyNi0wMS0yNFQyMDoxMzoyOCswMDowMBOfiR4AAAAldEVYdGRhdGU6bW9kaWZ5ADIwMjYtMDEtMjRUMjA6MTM6MjgrMDA6MDBiwjGiAAAAKHRFWHRkYXRlOnRpbWVzdGFtcAAyMDI2LTAxLTI0VDIwOjEzOjI4KzAwOjAwNdcQfQAAAXFJREFUSMft1dlTgkAcwHG7YCNJSwpdDaU0U9LoxlKs1LTTIi07DDutrPz/30KMmEYwqF6c+j4y8xmW2d8uFkuXmbp7LL2Iqfr+wTcACuQMAxTpxzBswAqMAoAP2uxDww7CMBgZJUnS6YImgdsYAAQBPTIYo4AaqgcA5vX66PEJf2AyOBVS8uEIqgNgmJmORGfY2bn5hcUlpcgyAnQAF5NWs7Iahwk+SaqtWduC9Q0OgalPwOwb0gBCCDS/IbOZZXJbNEtv25ms0s7u3j7LhoAGALgjf0Af+oWjQtCbV/IVBUEIHUMNIO/DSUlaxSlPEUrxs3PpSYzT2+kLGaTUnU6UOxs0Rs8MAJeiKFaKhgFKXF3bbHbGOIA3H/Px64CnpIGD1K1RcHdf5aWqD4/OZk812BY8J18aJWu8u5nrFbQF9XpzIeE4fE/zPLSCDIW09GMgpnPRaKkUbVQoc18CFME9ahXwJVCue6B763fAL+tvgDdnRI6o69eB+AAAAABJRU5ErkJggg==\"\n  },\n  \"description\": \"Hold COD purchases in PixelFly until approved. Posts to your first-party /cod/hold endpoint. Use on purchase events where payment_method is COD.\",\n  \"categories\": [\n    \"ANALYTICS\",\n    \"CONVERSIONS\",\n    \"MARKETING\"\n  ],\n  \"containerContexts\": [\n    \"SERVER\"\n  ]\n}\n\n\n___TEMPLATE_PARAMETERS___\n\n[\n  {\n    \"type\": \"GROUP\",\n    \"name\": \"connectionGroup\",\n    \"displayName\": \"Connection\",\n    \"groupStyle\": \"ZIPPY_OPEN\",\n    \"subParams\": [\n      {\n        \"type\": \"TEXT\",\n        \"name\": \"serverHost\",\n        \"displayName\": \"Server hostname / base URL\",\n        \"simpleValueType\": true,\n        \"valueValidators\": [\n          {\n            \"type\": \"NON_EMPTY\"\n          }\n        ],\n        \"help\": \"Your first-party tracking host from PixelFly (COD Power-up Hold URL without /cod/hold). Examples: https://server.bazarei.com or server.bazarei.com\"\n      },\n      {\n        \"type\": \"TEXT\",\n        \"name\": \"apiKey\",\n        \"displayName\": \"API Key (X-PF-Key)\",\n        \"simpleValueType\": true,\n        \"valueValidators\": [\n          {\n            \"type\": \"NON_EMPTY\"\n          }\n        ],\n        \"help\": \"Container API key from PixelFly dashboard (starts with pf_live_).\"\n      }\n    ]\n  },\n  {\n    \"type\": \"GROUP\",\n    \"name\": \"dataGroup\",\n    \"displayName\": \"Order data\",\n    \"groupStyle\": \"ZIPPY_OPEN\",\n    \"subParams\": [\n      {\n        \"type\": \"RADIO\",\n        \"name\": \"dataMode\",\n        \"displayName\": \"How to read order fields\",\n        \"radioItems\": [\n          {\n            \"value\": \"auto\",\n            \"displayValue\": \"Auto from event (Recommended)\"\n          },\n          {\n            \"value\": \"manual\",\n            \"displayValue\": \"Map fields manually\"\n          }\n        ],\n        \"simpleValueType\": true,\n        \"defaultValue\": \"auto\",\n        \"help\": \"Auto reads transaction_id, value, currency, email, phone, fbp, fbc from the GA4 / Data Client event.\"\n      },\n      {\n        \"type\": \"TEXT\",\n        \"name\": \"orderId\",\n        \"displayName\": \"Order ID\",\n        \"simpleValueType\": true,\n        \"help\": \"Usually {{Event Data - transaction_id}}\",\n        \"enablingConditions\": [\n          {\n            \"paramName\": \"dataMode\",\n            \"paramValue\": \"manual\",\n            \"type\": \"EQUALS\"\n          }\n        ]\n      },\n      {\n        \"type\": \"TEXT\",\n        \"name\": \"value\",\n        \"displayName\": \"Value\",\n        \"simpleValueType\": true,\n        \"enablingConditions\": [\n          {\n            \"paramName\": \"dataMode\",\n            \"paramValue\": \"manual\",\n            \"type\": \"EQUALS\"\n          }\n        ]\n      },\n      {\n        \"type\": \"TEXT\",\n        \"name\": \"currency\",\n        \"displayName\": \"Currency\",\n        \"simpleValueType\": true,\n        \"enablingConditions\": [\n          {\n            \"paramName\": \"dataMode\",\n            \"paramValue\": \"manual\",\n            \"type\": \"EQUALS\"\n          }\n        ]\n      },\n      {\n        \"type\": \"TEXT\",\n        \"name\": \"email\",\n        \"displayName\": \"Email\",\n        \"simpleValueType\": true,\n        \"enablingConditions\": [\n          {\n            \"paramName\": \"dataMode\",\n            \"paramValue\": \"manual\",\n            \"type\": \"EQUALS\"\n          }\n        ]\n      },\n      {\n        \"type\": \"TEXT\",\n        \"name\": \"phone\",\n        \"displayName\": \"Phone\",\n        \"simpleValueType\": true,\n        \"enablingConditions\": [\n          {\n            \"paramName\": \"dataMode\",\n            \"paramValue\": \"manual\",\n            \"type\": \"EQUALS\"\n          }\n        ]\n      },\n      {\n        \"type\": \"TEXT\",\n        \"name\": \"fbp\",\n        \"displayName\": \"fbp\",\n        \"simpleValueType\": true,\n        \"enablingConditions\": [\n          {\n            \"paramName\": \"dataMode\",\n            \"paramValue\": \"manual\",\n            \"type\": \"EQUALS\"\n          }\n        ]\n      },\n      {\n        \"type\": \"TEXT\",\n        \"name\": \"fbc\",\n        \"displayName\": \"fbc\",\n        \"simpleValueType\": true,\n        \"enablingConditions\": [\n          {\n            \"paramName\": \"dataMode\",\n            \"paramValue\": \"manual\",\n            \"type\": \"EQUALS\"\n          }\n        ]\n      },\n      {\n        \"type\": \"TEXT\",\n        \"name\": \"items\",\n        \"displayName\": \"Items / contents\",\n        \"simpleValueType\": true,\n        \"help\": \"Map to Event Data items (array). If empty, Auto/fallback still reads items or ecommerce.items from the event.\",\n        \"enablingConditions\": [\n          {\n            \"paramName\": \"dataMode\",\n            \"paramValue\": \"manual\",\n            \"type\": \"EQUALS\"\n          }\n        ]\n      },\n      {\n        \"type\": \"TEXT\",\n        \"name\": \"paymentMethod\",\n        \"displayName\": \"Payment method\",\n        \"simpleValueType\": true,\n        \"defaultValue\": \"cod\",\n        \"help\": \"Sent as payment_method. Default: cod. Leave as cod when this tag only fires on COD trigger.\"\n      },\n      {\n        \"type\": \"SIMPLE_TABLE\",\n        \"name\": \"additionalFields\",\n        \"displayName\": \"Additional fields to store\",\n        \"help\": \"Add any extra keys (name, city, content_ids, custom properties…). Click Add Row — like GA4/Meta parameter tables. These are merged into the /cod/hold JSON and saved in PixelFly.\",\n        \"simpleTableColumns\": [\n          {\n            \"defaultValue\": \"\",\n            \"displayName\": \"Field name\",\n            \"name\": \"name\",\n            \"type\": \"TEXT\"\n          },\n          {\n            \"defaultValue\": \"\",\n            \"displayName\": \"Value\",\n            \"name\": \"value\",\n            \"type\": \"TEXT\"\n          }\n        ],\n        \"newRowButtonText\": \"Add field\"\n      }\n    ]\n  },\n  {\n    \"type\": \"GROUP\",\n    \"name\": \"optionsGroup\",\n    \"displayName\": \"Options\",\n    \"groupStyle\": \"ZIPPY_CLOSED\",\n    \"subParams\": [\n      {\n        \"type\": \"CHECKBOX\",\n        \"name\": \"skipIfNotCod\",\n        \"checkboxText\": \"Skip request if payment_method is not COD\",\n        \"simpleValueType\": true,\n        \"defaultValue\": true,\n        \"help\": \"Safety net: if payment_method is present and not COD-like, tag succeeds without calling /cod/hold. Prefer a COD-only trigger as well.\"\n      },\n      {\n        \"type\": \"CHECKBOX\",\n        \"name\": \"includeEventSnapshot\",\n        \"checkboxText\": \"Also attach full event snapshot (event_snapshot)\",\n        \"simpleValueType\": true,\n        \"defaultValue\": false,\n        \"help\": \"Stores the whole sGTM event object under event_snapshot in the hold payload (useful for debugging / full raw data).\"\n      },\n      {\n        \"type\": \"CHECKBOX\",\n        \"name\": \"logToConsole\",\n        \"checkboxText\": \"Log request/response in Preview\",\n        \"simpleValueType\": true,\n        \"defaultValue\": false\n      }\n    ]\n  }\n]\n\n\n___SANDBOXED_JS_FOR_SERVER___\n\nconst getAllEventData = require('getAllEventData');\nconst getCookieValues = require('getCookieValues');\nconst getRequestHeader = require('getRequestHeader');\nconst getType = require('getType');\nconst JSON = require('JSON');\nconst logToConsole = require('logToConsole');\nconst makeNumber = require('makeNumber');\nconst makeString = require('makeString');\nconst sendHttpRequest = require('sendHttpRequest');\nconst getTimestampMillis = require('getTimestampMillis');\n\nconst eventData = getAllEventData() || {};\nconst TAG = 'PixelFly COD Protection';\n\nfunction isEmpty(v) {\n  return v === undefined || v === null || v === '';\n}\n\nfunction firstNonEmpty() {\n  for (let i = 0; i < arguments.length; i++) {\n    const v = arguments[i];\n    if (!isEmpty(v)) return v;\n  }\n  return undefined;\n}\n\nfunction nestGet(obj, path) {\n  if (!obj || getType(obj) !== 'object') return undefined;\n  const parts = path.split('.');\n  let cur = obj;\n  for (let i = 0; i < parts.length; i++) {\n    if (cur === undefined || cur === null || getType(cur) !== 'object') return undefined;\n    cur = cur[parts[i]];\n  }\n  return cur;\n}\n\nfunction normalizeHost(host) {\n  let h = makeString(host || '').trim();\n  if (!h) return '';\n  if (h.indexOf('http://') !== 0 && h.indexOf('https://') !== 0) {\n    h = 'https://' + h;\n  }\n  // strip trailing slash\n  while (h.length > 0 && h.charAt(h.length - 1) === '/') {\n    h = h.substring(0, h.length - 1);\n  }\n  // if user pasted full hold URL, keep as-is\n  if (h.indexOf('/cod/hold') !== -1) return h;\n  return h + '/cod/hold';\n}\n\nfunction isCodMethod(method) {\n  if (isEmpty(method)) return true; // treat missing as COD when tag is COD-triggered\n  const m = makeString(method).toLowerCase();\n  return m === 'cod' || m.indexOf('cash_on_delivery') !== -1 || m.indexOf('cash on delivery') !== -1;\n}\n\nfunction isJunk(v) {\n  if (isEmpty(v)) return true;\n  const s = makeString(v).trim().toLowerCase();\n  return s === 'undefined' || s === 'null' || s === 'nan' || s === 'none';\n}\n\nfunction queryParam(url, key) {\n  if (isEmpty(url)) return undefined;\n  const s = makeString(url);\n  const needle = key + '=';\n  let idx = s.indexOf('?' + needle);\n  if (idx === -1) idx = s.indexOf('&' + needle);\n  if (idx === -1) return undefined;\n  // skip the ? or &\n  let start = idx + 1 + needle.length;\n  let end = s.indexOf('&', start);\n  if (end === -1) end = s.indexOf('#', start);\n  if (end === -1) end = s.length;\n  const raw = s.substring(start, end);\n  if (!raw) return undefined;\n  return raw;\n}\n\nfunction clickIdFromEvent(key) {\n  return firstNonEmpty(\n    eventData[key],\n    nestGet(eventData, 'user_data.' + key),\n    queryParam(eventData.page_location, key),\n    queryParam(eventData.page_referrer, key),\n    queryParam(nestGet(eventData, 'event_source_url'), key)\n  );\n}\n\n// First value of a request cookie. On a first-party sGTM domain the browser sends\n// the shop's cookies, so _fbp / _fbc / Google click cookies are here even when the\n// web tag didn't copy them onto the event.\nfunction cookie(name) {\n  const values = getCookieValues(name);\n  if (values && values.length && !isJunk(values[0])) return values[0];\n  return undefined;\n}\n\n// gclid from Google's cookies: FPGCLAW is \"2.1.k<gclid>$i<time>\" (sGTM first-party),\n// _gcl_aw is \"GCL.<time>.<gclid>\" (web).\nfunction gclidFromCookies() {\n  const fp = cookie('FPGCLAW');\n  if (fp) {\n    const parts = makeString(fp).split('.');\n    if (parts.length >= 3 && parts[2].charAt(0) === 'k') {\n      const rest = parts.slice(2).join('.').substring(1);\n      const end = rest.indexOf('$i');\n      const id = end === -1 ? rest : rest.substring(0, end);\n      if (id) return id;\n    }\n  }\n  const aw = cookie('_gcl_aw');\n  if (aw) {\n    const parts = makeString(aw).split('.');\n    if (parts.length >= 3) return parts.slice(2).join('.');\n  }\n  return undefined;\n}\n\nfunction clean(v) {\n  return isEmpty(v) || isJunk(v) ? undefined : v;\n}\n\nfunction pickUserField(keys) {\n  for (let i = 0; i < keys.length; i++) {\n    const k = keys[i];\n    const direct = eventData[k];\n    if (!isEmpty(direct) && !isJunk(direct)) return direct;\n    const userData = nestGet(eventData, 'user_data.' + k);\n    if (!isEmpty(userData) && !isJunk(userData)) return userData;\n  }\n  return undefined;\n}\n\nconst holdUrl = normalizeHost(data.serverHost);\nconst apiKey = makeString(data.apiKey || '').trim();\n\nif (!holdUrl || !apiKey) {\n  if (data.logToConsole) logToConsole(TAG + ': missing serverHost or apiKey');\n  return data.gtmOnFailure();\n}\n\nlet orderId;\nlet value;\nlet currency;\nlet email;\nlet phone;\nlet fbp;\nlet fbc;\nlet fbclid;\nlet gclid;\nlet ttclid;\nlet msclkid;\nlet wbraid;\nlet gbraid;\nlet paymentMethod;\n\nif (data.dataMode === 'manual') {\n  orderId = firstNonEmpty(data.orderId, eventData.transaction_id, eventData.order_id);\n  value = firstNonEmpty(data.value, eventData.value);\n  currency = firstNonEmpty(data.currency, eventData.currency);\n  email = firstNonEmpty(data.email, pickUserField(['email', 'em', 'email_address']));\n  phone = firstNonEmpty(data.phone, pickUserField(['phone', 'phone_number', 'ph']));\n  fbp = firstNonEmpty(\n    data.fbp,\n    eventData.fbp,\n    nestGet(eventData, 'user_data.fbp'),\n    nestGet(eventData, 'x-fb-ck-fbp'),\n    cookie('_fbp')\n  );\n  fbc = firstNonEmpty(\n    data.fbc,\n    eventData.fbc,\n    nestGet(eventData, 'user_data.fbc'),\n    nestGet(eventData, 'x-fb-ck-fbc'),\n    cookie('_fbc')\n  );\n} else {\n  orderId = firstNonEmpty(\n    eventData.transaction_id,\n    eventData.order_id,\n    nestGet(eventData, 'ecommerce.transaction_id')\n  );\n  value = firstNonEmpty(eventData.value, nestGet(eventData, 'ecommerce.value'));\n  currency = firstNonEmpty(eventData.currency, nestGet(eventData, 'ecommerce.currency'));\n  email = pickUserField(['email', 'em', 'email_address']);\n  phone = pickUserField(['phone', 'phone_number', 'ph']);\n  fbp = firstNonEmpty(\n    eventData.fbp,\n    nestGet(eventData, 'user_data.fbp'),\n    nestGet(eventData, 'x-fb-ck-fbp'),\n    cookie('_fbp')\n  );\n  fbc = firstNonEmpty(\n    eventData.fbc,\n    nestGet(eventData, 'user_data.fbc'),\n    nestGet(eventData, 'x-fb-ck-fbc'),\n    cookie('_fbc')\n  );\n}\n\npaymentMethod = firstNonEmpty(\n  data.paymentMethod,\n  eventData.payment_method,\n  nestGet(eventData, 'ecommerce.payment_method'),\n  'cod'\n);\nfbclid = clickIdFromEvent('fbclid');\ngclid = firstNonEmpty(clickIdFromEvent('gclid'), gclidFromCookies());\nttclid = clickIdFromEvent('ttclid');\nmsclkid = clickIdFromEvent('msclkid');\nwbraid = clickIdFromEvent('wbraid');\ngbraid = clickIdFromEvent('gbraid');\nconst dclid = clickIdFromEvent('dclid');\nconst liFatId = clickIdFromEvent('li_fat_id');\nconst sccid = firstNonEmpty(clickIdFromEvent('sccid'), clickIdFromEvent('ScCid'));\nconst utmSource = firstNonEmpty(\n  eventData.utm_source,\n  nestGet(eventData, 'event_snapshot.utm_source'),\n  queryParam(eventData.page_location, 'utm_source'),\n  queryParam(eventData.page_referrer, 'utm_source')\n);\nconst utmMedium = firstNonEmpty(\n  eventData.utm_medium,\n  nestGet(eventData, 'event_snapshot.utm_medium'),\n  queryParam(eventData.page_location, 'utm_medium'),\n  queryParam(eventData.page_referrer, 'utm_medium')\n);\nconst utmCampaign = firstNonEmpty(\n  eventData.utm_campaign,\n  nestGet(eventData, 'event_snapshot.utm_campaign'),\n  queryParam(eventData.page_location, 'utm_campaign'),\n  queryParam(eventData.page_referrer, 'utm_campaign')\n);\nconst utmContent = firstNonEmpty(\n  eventData.utm_content,\n  nestGet(eventData, 'event_snapshot.utm_content'),\n  queryParam(eventData.page_location, 'utm_content'),\n  queryParam(eventData.page_referrer, 'utm_content')\n);\nconst utmTerm = firstNonEmpty(\n  eventData.utm_term,\n  nestGet(eventData, 'event_snapshot.utm_term'),\n  queryParam(eventData.page_location, 'utm_term'),\n  queryParam(eventData.page_referrer, 'utm_term')\n);\n\nif (data.skipIfNotCod && !isCodMethod(paymentMethod)) {\n  if (data.logToConsole) {\n    logToConsole(TAG + ': skipped non-COD payment_method=' + makeString(paymentMethod));\n  }\n  return data.gtmOnSuccess();\n}\n\nif (isEmpty(orderId)) {\n  // Still held: PixelFly names it after the event ID (NOID-...) and it's approved from\n  // the dashboard. Logged even with logging off (GTM shows console output only in\n  // Preview). Preview's Event Data is the event before Transformations, so a field it\n  // shows can still be missing here if an \"Exclude parameters\" transformation doesn't\n  // list this tag.\n  const keys = [];\n  for (let k in eventData) keys.push(k);\n  logToConsole(TAG + ': no order_id / transaction_id, holding it without one. If Preview\\'s ' +\n    'Event Data shows transaction_id, add this tag to the container\\'s Transformations that ' +\n    'exclude it. Fields this tag received: ' + keys.join(','));\n}\n\nconst clientIp = firstNonEmpty(\n  eventData.ip_override,\n  nestGet(eventData, 'context.ip'),\n  getRequestHeader('x-forwarded-for'),\n  getRequestHeader('cf-connecting-ip')\n);\nconst userAgent = firstNonEmpty(\n  eventData.user_agent,\n  nestGet(eventData, 'context.user_agent'),\n  getRequestHeader('user-agent')\n);\n\nlet eventTime = firstNonEmpty(eventData.event_time, eventData.timestamp);\nif (isEmpty(eventTime)) {\n  eventTime = makeNumber(getTimestampMillis() / 1000);\n} else {\n  eventTime = makeNumber(eventTime);\n  // if millis, convert to seconds\n  if (eventTime > 9999999999) eventTime = makeNumber(eventTime / 1000);\n}\n\nconst payload = {\n  event_name: 'Purchase',\n  payment_method: makeString(paymentMethod || 'cod'),\n  source: 'server_container',\n  event_time: eventTime\n};\nif (!isEmpty(orderId)) payload.order_id = makeString(orderId);\nconst holdEventId = firstNonEmpty(eventData.event_id, orderId);\nif (!isEmpty(holdEventId)) payload.event_id = makeString(holdEventId);\n\nif (!isEmpty(value)) payload.value = makeNumber(value);\nif (!isEmpty(currency)) payload.currency = makeString(currency);\nif (!isEmpty(email)) payload.email = makeString(email);\nif (!isEmpty(phone)) payload.phone = makeString(phone);\nconst customerFirst = firstNonEmpty(\n  pickUserField(['customerFirstName', 'customerBillingFirstName', 'fn', 'first_name']),\n  clean(nestGet(eventData, 'user_data.address.first_name'))\n);\nconst customerLast = firstNonEmpty(\n  pickUserField(['customerLastName', 'customerBillingLastName', 'ln', 'last_name']),\n  clean(nestGet(eventData, 'user_data.address.last_name'))\n);\nconst customerName = makeString(firstNonEmpty(\n  pickUserField(['name']),\n  customerFirst && customerLast ? makeString(customerFirst) + ' ' + makeString(customerLast) : undefined,\n  customerFirst,\n  customerLast\n)).trim();\nif (!isEmpty(customerName) && !isJunk(customerName)) payload.name = customerName;\nif (!isEmpty(fbp)) payload.fbp = makeString(fbp);\nif (!isEmpty(fbc)) payload.fbc = makeString(fbc);\nif (!isEmpty(fbclid)) payload.fbclid = makeString(fbclid);\nif (!isEmpty(gclid)) payload.gclid = makeString(gclid);\nif (!isEmpty(ttclid)) payload.ttclid = makeString(ttclid);\nif (!isEmpty(msclkid)) payload.msclkid = makeString(msclkid);\nif (!isEmpty(wbraid)) payload.wbraid = makeString(wbraid);\nif (!isEmpty(gbraid)) payload.gbraid = makeString(gbraid);\nif (!isEmpty(dclid)) payload.dclid = makeString(dclid);\nif (!isEmpty(liFatId)) payload.li_fat_id = makeString(liFatId);\nif (!isEmpty(sccid)) payload.sccid = makeString(sccid);\nif (!isEmpty(utmSource)) payload.utm_source = makeString(utmSource);\nif (!isEmpty(utmMedium)) payload.utm_medium = makeString(utmMedium);\nif (!isEmpty(utmCampaign)) payload.utm_campaign = makeString(utmCampaign);\nif (!isEmpty(utmContent)) payload.utm_content = makeString(utmContent);\nif (!isEmpty(utmTerm)) payload.utm_term = makeString(utmTerm);\nif (!isEmpty(clientIp)) payload.client_ip = makeString(clientIp).split(',')[0].trim();\nif (!isEmpty(userAgent)) payload.user_agent = makeString(userAgent);\nif (!isEmpty(eventData.page_location)) payload.event_source_url = makeString(eventData.page_location);\nif (!isEmpty(eventData.page_referrer)) payload.page_referrer = makeString(eventData.page_referrer);\nconst gaClientId = firstNonEmpty(eventData.client_id, nestGet(eventData, 'user_data.client_id'));\nif (!isEmpty(gaClientId)) payload.ga_client_id = makeString(gaClientId);\n// The GA4 session at checkout, so the confirmed purchase lands in the visit that came from the ad.\nif (!isEmpty(eventData.ga_session_id)) payload.ga_session_id = makeString(eventData.ga_session_id);\n// The id the shop's tags gave this shopper, so the confirmed Purchase matches them.\nconst externalId = firstNonEmpty(\n  clean(eventData['x-fb-ud-external_id']),\n  clean(nestGet(eventData, 'user_data.external_id')),\n  clean(eventData.external_id)\n);\nif (!isEmpty(externalId)) payload.external_id = makeString(externalId);\n\n// Items / contents\nconst itemsValue = firstNonEmpty(\n  data.dataMode === 'manual' ? data.items : undefined,\n  eventData.items,\n  nestGet(eventData, 'ecommerce.items'),\n  eventData.contents\n);\nif (!isEmpty(itemsValue)) {\n  // If mapped as a JSON string from a variable, try to parse\n  if (getType(itemsValue) === 'string') {\n    const parsed = JSON.parse(itemsValue);\n    payload.contents = parsed !== undefined ? parsed : itemsValue;\n  } else {\n    payload.contents = itemsValue;\n  }\n}\n\n// Extra rows (Add field table) — merge into payload\n// (GTM sandbox has no Object.keys — iterate the table rows directly)\nconst extraRows = data.additionalFields;\nif (getType(extraRows) === 'array') {\n  for (let i = 0; i < extraRows.length; i++) {\n    const row = extraRows[i];\n    if (!row) continue;\n    const key = makeString(row.name || '').trim();\n    if (!key) continue;\n    const val = row.value;\n    if (isEmpty(val)) continue;\n    if (getType(val) === 'string') {\n      const s = makeString(val);\n      const first = s.charAt(0);\n      if (first === '{' || first === '[') {\n        const parsed = JSON.parse(s);\n        payload[key] = parsed !== undefined ? parsed : val;\n      } else {\n        payload[key] = val;\n      }\n    } else {\n      payload[key] = val;\n    }\n  }\n}\n\nif (data.includeEventSnapshot) {\n  payload.event_snapshot = eventData;\n}\n\nconst body = JSON.stringify(payload);\n\nif (data.logToConsole) {\n  logToConsole(TAG + ' POST ' + holdUrl);\n  logToConsole(TAG + ' body ' + body);\n}\n\nsendHttpRequest(\n  holdUrl,\n  {\n    method: 'POST',\n    headers: {\n      'Content-Type': 'application/json',\n      'X-PF-Key': apiKey\n    },\n    timeout: 5000\n  },\n  body\n)\n  .then((result) => {\n    const code = result.statusCode;\n    if (data.logToConsole) {\n      logToConsole(TAG + ' status ' + code + ' response ' + makeString(result.body));\n    }\n    if (code >= 200 && code < 300) {\n      return data.gtmOnSuccess();\n    }\n    return data.gtmOnFailure();\n  })\n  .catch((err) => {\n    if (data.logToConsole) logToConsole(TAG + ' request failed');\n    return data.gtmOnFailure();\n  });\n\n\n___SERVER_PERMISSIONS___\n\n[\n  {\n    \"instance\": {\n      \"key\": {\n        \"publicId\": \"read_event_data\",\n        \"versionId\": \"1\"\n      },\n      \"param\": [\n        {\n          \"key\": \"eventDataAccess\",\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_request\",\n        \"versionId\": \"1\"\n      },\n      \"param\": [\n        {\n          \"key\": \"headerAccess\",\n          \"value\": {\n            \"type\": 1,\n            \"string\": \"any\"\n          }\n        },\n        {\n          \"key\": \"queryParameterAccess\",\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\": \"logging\",\n        \"versionId\": \"1\"\n      },\n      \"param\": [\n        {\n          \"key\": \"environments\",\n          \"value\": {\n            \"type\": 1,\n            \"string\": \"debug\"\n          }\n        }\n      ]\n    },\n    \"clientAnnotations\": {\n      \"isEditedByUser\": true\n    },\n    \"isRequired\": true\n  },\n  {\n    \"instance\": {\n      \"key\": {\n        \"publicId\": \"send_http\",\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\": \"_fbp\"\n              },\n              {\n                \"type\": 1,\n                \"string\": \"_fbc\"\n              },\n              {\n                \"type\": 1,\n                \"string\": \"FPGCLAW\"\n              },\n              {\n                \"type\": 1,\n                \"string\": \"_gcl_aw\"\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\nPixelFly COD Protection — sGTM tag template\nVersion 1.1.0\n\nPosts COD purchases to {firstPartyHost}/cod/hold with X-PF-Key.\n\nSetup:\n1. Import this .tpl in sGTM → Templates → Tag Templates → Import\n2. Create tag from \"PixelFly COD Protection\"\n3. Server hostname = Hold URL host from COD Power-up (e.g. https://server.example.com)\n4. API Key = container pf_live_... key\n5. Trigger: purchase AND payment_method equals cod\n6. Pause Meta/Google/TikTok Purchase tags for COD\n\nv1.1.0:\n- Added Items field (manual mode)\n- Added \"Additional fields to store\" table (Add field rows, like GA4/Meta)\n- Added optional full event_snapshot checkbox\n\nDocs: https://pixelfly.io\n"
            },
            {
                "accountId": "6374306328",
                "containerId": "262778781",
                "templateId": "19",
                "name": "Data Client",
                "fingerprint": "1791000829716",
                "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\": \"CLIENT\",\n  \"id\": \"cvt_temp_public_id\",\n  \"version\": 1,\n  \"securityGroups\": [],\n  \"displayName\": \"Data Client\",\n  \"brand\": {\n    \"id\": \"brand_dummy\",\n    \"displayName\": \"Stape\",\n    \"thumbnail\": \"data:image/png;base64,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\"\n  },\n  \"description\": \"Use this Client as a mapper from Request Data to Event Data.\",\n  \"containerContexts\": [\n    \"SERVER\"\n  ]\n}\n\n\n___TEMPLATE_PARAMETERS___\n\n[\n  {\n    \"type\": \"CHECKBOX\",\n    \"name\": \"exposeFPIDCookie\",\n    \"checkboxText\": \"Expose GA4 FPID Cookie\",\n    \"simpleValueType\": true,\n    \"help\": \"If enabled, the \\u003ci\\u003eFPID\\u003c/i\\u003e cookie only accessible by the server and generated by the GA4 Client, will be duplicated to \\u003ci\\u003eFPIDP\\u003c/i\\u003e cookie, which will be accessible in the browser by JavaScript. \\n\\u003cbr/\\u003e\\nIt\\u0027s highly recommend using this option only in case it is necessary.\\n\\u003cbr/\\u003e\\u003cbr/\\u003e\\nThe cookie won\\u0027t be stored if the \\u003ci\\u003eCookie Storage Mode\\u003c/i\\u003e under the \\u003ci\\u003eCookie Consent Settings\\u003c/i\\u003e section receives \\u003ci\\u003edenied\\u003c/i\\u003e.\"\n  },\n  {\n    \"type\": \"CHECKBOX\",\n    \"name\": \"generateClientId\",\n    \"checkboxText\": \"Generate the \\\"client_id\\\" parameter and store it as the \\\"_dcid\\\" cookie\",\n    \"simpleValueType\": true,\n    \"help\": \"If enabled, a \\u003ci\\u003eclient_id\\u003c/i\\u003e will be generated when the request doesn\\u0027t already include one, and stored in the \\u003ci\\u003e_dcid\\u003c/i\\u003e cookie. The \\u003ci\\u003eclient_id\\u003c/i\\u003e can come from the event parameters, the \\u003ci\\u003e_dcid\\u003c/i\\u003e cookie, a temporary client ID (from Data Tag), or a newly generated random value, checked in that order.\\n\\u003cbr/\\u003e\\nThe \\u003ci\\u003eclient_id\\u003c/i\\u003e parameter is required by GA4 tags.\\n\\u003cbr/\\u003e\\u003cbr/\\u003e\\nThe cookie won\\u0027t be stored if the \\u003ci\\u003eCookie Storage Mode\\u003c/i\\u003e under the \\u003ci\\u003eCookie Consent Settings\\u003c/i\\u003e section receives \\u003ci\\u003edenied\\u003c/i\\u003e.\",\n    \"defaultValue\": true,\n    \"subParams\": [\n      {\n        \"type\": \"CHECKBOX\",\n        \"name\": \"httpOnlyCookie\",\n        \"checkboxText\": \"Write the \\\"_dcid\\\" cookie as HttpOnly\",\n        \"simpleValueType\": true,\n        \"help\": \"If enabled, the \\u003ci\\u003e_dcid\\u003c/i\\u003e cookie will be written with the HttpOnly flag, making it non-accessible in the browser by JavaScript.\",\n        \"defaultValue\": false,\n        \"enablingConditions\": [\n          {\n            \"paramName\": \"generateClientId\",\n            \"paramValue\": true,\n            \"type\": \"EQUALS\"\n          }\n        ]\n      }\n    ]\n  },\n  {\n    \"type\": \"CHECKBOX\",\n    \"name\": \"prolongCookies\",\n    \"checkboxText\": \"Prolong Data Tag \\\"stape\\\" cookie\",\n    \"simpleValueType\": true,\n    \"help\": \"If enabled, the \\u003ci\\u003estape\\u003c/i\\u003e cookie generated by Data Tag will be reset from the server with an expiration time of 2 years. It\\u0027s useful if you use the store functionality of Data Tag.\\n\\u003cbr/\\u003e\\u003cbr/\\u003e\\nThe cookie won\\u0027t be stored if the \\u003ci\\u003eCookie Storage Mode\\u003c/i\\u003e under the \\u003ci\\u003eCookie Consent Settings\\u003c/i\\u003e section receives \\u003ci\\u003edenied\\u003c/i\\u003e.\",\n    \"defaultValue\": true\n  },\n  {\n    \"type\": \"CHECKBOX\",\n    \"name\": \"acceptMultipleEvents\",\n    \"checkboxText\": \"Accept Multiple Events\",\n    \"simpleValueType\": true,\n    \"help\": \"When the Accept Multiple Events is set to true, the Data Client will parse an array of objects, in the request body, as separate events.\\n\\u003cbr/\\u003e\\nExample:\\n\\u003cbr/\\u003e\\n[\\n  {\\\"event\\\":\\\"page_view\\\"},\\n  {\\\"event\\\":\\\"view_item\\\"}\\n]\",\n    \"defaultValue\": false\n  },\n  {\n    \"type\": \"GROUP\",\n    \"name\": \"responseSettings\",\n    \"displayName\": \"Response Settings\",\n    \"groupStyle\": \"ZIPPY_CLOSED\",\n    \"subParams\": [\n      {\n        \"type\": \"SELECT\",\n        \"name\": \"responseStatusCode\",\n        \"displayName\": \"Response Status Code\",\n        \"selectItems\": [\n          {\n            \"value\": 200,\n            \"displayValue\": \"200\"\n          },\n          {\n            \"value\": 201,\n            \"displayValue\": \"201\"\n          },\n          {\n            \"value\": 301,\n            \"displayValue\": \"301\"\n          },\n          {\n            \"value\": 302,\n            \"displayValue\": \"302\"\n          },\n          {\n            \"value\": 403,\n            \"displayValue\": \"403\"\n          },\n          {\n            \"value\": 404,\n            \"displayValue\": \"404\"\n          }\n        ],\n        \"simpleValueType\": true,\n        \"defaultValue\": 200\n      },\n      {\n        \"type\": \"GROUP\",\n        \"name\": \"regularResponseSettings\",\n        \"groupStyle\": \"NO_ZIPPY\",\n        \"subParams\": [\n          {\n            \"type\": \"SELECT\",\n            \"name\": \"responseBody\",\n            \"displayName\": \"Response Body\",\n            \"macrosInSelect\": false,\n            \"selectItems\": [\n              {\n                \"value\": \"timestamp\",\n                \"displayValue\": \"JSON Object with timestamp (recommended)\"\n              },\n              {\n                \"value\": \"eventData\",\n                \"displayValue\": \"JSON Object with Event Data\"\n              },\n              {\n                \"value\": \"empty\",\n                \"displayValue\": \"Empty\"\n              }\n            ],\n            \"simpleValueType\": true,\n            \"defaultValue\": \"timestamp\"\n          },\n          {\n            \"type\": \"CHECKBOX\",\n            \"name\": \"responseBodyGet\",\n            \"checkboxText\": \"Send Response Body for GET request\",\n            \"simpleValueType\": true,\n            \"help\": \"By default, for the GET request type, the answer is image pixel.  \\u003ca target\\u003d\\\"_blank\\\" href\\u003d\\\"https://developers.google.com/tag-manager/serverside/api#setpixelresponse\\\"\\u003eMore Info\\u003c/a\\u003e.\"\n          }\n        ],\n        \"enablingConditions\": [\n          {\n            \"paramName\": \"responseStatusCode\",\n            \"paramValue\": 200,\n            \"type\": \"EQUALS\"\n          },\n          {\n            \"paramName\": \"responseStatusCode\",\n            \"paramValue\": 201,\n            \"type\": \"EQUALS\"\n          }\n        ]\n      },\n      {\n        \"type\": \"GROUP\",\n        \"name\": \"redirectResponseSettings\",\n        \"groupStyle\": \"NO_ZIPPY\",\n        \"subParams\": [\n          {\n            \"type\": \"TEXT\",\n            \"name\": \"redirectTo\",\n            \"displayName\": \"Redirect To\",\n            \"simpleValueType\": true,\n            \"valueValidators\": [\n              {\n                \"type\": \"NON_EMPTY\"\n              },\n              {\n                \"type\": \"REGEX\",\n                \"args\": [\n                  \"^https?:\\\\/\\\\/.*\"\n                ]\n              }\n            ]\n          },\n          {\n            \"type\": \"CHECKBOX\",\n            \"name\": \"lookupForRedirectToParam\",\n            \"checkboxText\": \"Try to find redirect destination in query params\",\n            \"simpleValueType\": true,\n            \"help\": \"Override destination URL with query param from request url\"\n          },\n          {\n            \"type\": \"TEXT\",\n            \"name\": \"redirectToQueryParamName\",\n            \"displayName\": \"Query Param Name\",\n            \"simpleValueType\": true,\n            \"enablingConditions\": [\n              {\n                \"paramName\": \"lookupForRedirectToParam\",\n                \"paramValue\": true,\n                \"type\": \"EQUALS\"\n              }\n            ],\n            \"valueValidators\": [\n              {\n                \"type\": \"NON_EMPTY\"\n              }\n            ]\n          }\n        ],\n        \"enablingConditions\": [\n          {\n            \"paramName\": \"responseStatusCode\",\n            \"paramValue\": 301,\n            \"type\": \"EQUALS\"\n          },\n          {\n            \"paramName\": \"responseStatusCode\",\n            \"paramValue\": 302,\n            \"type\": \"EQUALS\"\n          }\n        ]\n      },\n      {\n        \"type\": \"GROUP\",\n        \"name\": \"clientErrorResponseSettings\",\n        \"groupStyle\": \"NO_ZIPPY\",\n        \"subParams\": [\n          {\n            \"type\": \"TEXT\",\n            \"name\": \"clientErrorResponseMessage\",\n            \"displayName\": \"Client Error Response Message\",\n            \"simpleValueType\": true,\n            \"valueValidators\": [\n              {\n                \"type\": \"NON_EMPTY\"\n              }\n            ]\n          }\n        ],\n        \"enablingConditions\": [\n          {\n            \"paramName\": \"responseStatusCode\",\n            \"paramValue\": 403,\n            \"type\": \"EQUALS\"\n          },\n          {\n            \"paramName\": \"responseStatusCode\",\n            \"paramValue\": 404,\n            \"type\": \"EQUALS\"\n          }\n        ]\n      }\n    ]\n  },\n  {\n    \"type\": \"GROUP\",\n    \"name\": \"pathSettings\",\n    \"displayName\": \"Accepted Path Settings\",\n    \"groupStyle\": \"ZIPPY_CLOSED\",\n    \"subParams\": [\n      {\n        \"type\": \"SIMPLE_TABLE\",\n        \"name\": \"path\",\n        \"displayName\": \"Type additional paths that will be claimed by this client\",\n        \"simpleTableColumns\": [\n          {\n            \"defaultValue\": \"\",\n            \"displayName\": \"For example: /callback\",\n            \"name\": \"path\",\n            \"type\": \"TEXT\",\n            \"isUnique\": true,\n            \"valueValidators\": [\n              {\n                \"type\": \"NON_EMPTY\"\n              }\n            ]\n          }\n        ],\n        \"newRowButtonText\": \"Add path\",\n        \"help\": \"By default path \\u003cb\\u003e/data\\u003c/b\\u003e will be claimed. But you can add more paths that will be claimed by this client.\"\n      }\n    ]\n  },\n  {\n    \"type\": \"GROUP\",\n    \"name\": \"cookieConsentSettingsGroup\",\n    \"displayName\": \"Cookie Consent Settings\",\n    \"groupStyle\": \"ZIPPY_CLOSED\",\n    \"subParams\": [\n      {\n        \"type\": \"SELECT\",\n        \"name\": \"cookieStorageMode\",\n        \"macrosInSelect\": false,\n        \"selectItems\": [\n          {\n            \"value\": \"auto\",\n            \"displayValue\": \"Store cookies based on Consent Status from Stape\\u0027s Data Tag\"\n          },\n          {\n            \"value\": \"manual\",\n            \"displayValue\": \"Store cookies based on manual Consent Status\"\n          }\n        ],\n        \"simpleValueType\": true,\n        \"subParams\": [\n          {\n            \"type\": \"SELECT\",\n            \"name\": \"cookieConsentAutoParameter\",\n            \"displayName\": \"Consent Status Parameter\",\n            \"selectItems\": [\n              {\n                \"value\": \"analytics_storage\",\n                \"displayValue\": \"analytics_storage\"\n              },\n              {\n                \"value\": \"ad_storage\",\n                \"displayValue\": \"ad_storage\"\n              }\n            ],\n            \"simpleValueType\": true,\n            \"help\": \"If you are using Stape\\u0027s Data Tag to transmit consent to the server, choose parameter corresponding to the consent category to which the cookies set by Data Client were allocated in your Consent Management Platform.\\n\\u003cbr/\\u003e\\nBe sure to enable the \\u003ci\\u003eAdd consent state\\u003c/i\\u003e option in the Data Tag.\",\n            \"enablingConditions\": [\n              {\n                \"paramName\": \"cookieStorageMode\",\n                \"paramValue\": \"auto\",\n                \"type\": \"EQUALS\"\n              }\n            ],\n            \"valueValidators\": [\n              {\n                \"type\": \"NON_EMPTY\"\n              }\n            ]\n          },\n          {\n            \"type\": \"TEXT\",\n            \"name\": \"cookieConsentManualValue\",\n            \"displayName\": \"Consent Status Manual\",\n            \"simpleValueType\": true,\n            \"help\": \"Use this field if you are not using Google Consent Mode.\\n\\u003cbr/\\u003e\\nThis field allows you to specify the user consent status using a custom variable.\\n\\u003cbr/\\u003e\\u003cbr/\\u003e\\nAccepted values:\\n\\u003cul\\u003e\\n\\u003cli\\u003efor Denied: \\u003ci\\u003e0\\u003c/i\\u003e, \\u003ci\\u003efalse\\u003c/i\\u003e and \\u003ci\\u003edenied\\u003c/i\\u003e\\u003c/li\\u003e\\n\\u003cli\\u003efor Granted: \\u003ci\\u003e1\\u003c/i\\u003e, \\u003ci\\u003etrue\\u003c/i\\u003e and \\u003ci\\u003egranted\\u003c/i\\u003e\\u003c/li\\u003e\\n\\u003c/ul\\u003e\\n\\u003cbr/\\u003e\\nIf any other values are passed, or the field is left blank, the tag will assume \\u003ci\\u003egranted\\u003c/i\\u003e was specified.\",\n            \"enablingConditions\": [\n              {\n                \"paramName\": \"cookieStorageMode\",\n                \"paramValue\": \"manual\",\n                \"type\": \"EQUALS\"\n              }\n            ]\n          }\n        ],\n        \"notSetText\": \"Always store cookies\",\n        \"displayName\": \"Cookie Storage Mode\",\n        \"help\": \"Use this option to conditionally control whether the Data Client will store cookies based on consent signals that are present in the incoming request or based on manual input.\\n\\u003cbr/\\u003e\\nBy default, it always store cookies.\"\n      }\n    ]\n  }\n]\n\n\n___SANDBOXED_JS_FOR_SERVER___\n\nconst computeEffectiveTldPlusOne = require('computeEffectiveTldPlusOne');\nconst createRegex = require('createRegex');\nconst decodeUriComponent = require('decodeUriComponent');\nconst fromBase64 = require('fromBase64');\nconst generateRandom = require('generateRandom');\nconst getCookieValues = require('getCookieValues');\nconst getRemoteAddress = require('getRemoteAddress');\nconst getRequestBody = require('getRequestBody');\nconst getRequestHeader = require('getRequestHeader');\nconst getRequestMethod = require('getRequestMethod');\nconst getRequestPath = require('getRequestPath');\nconst getRequestQueryParameter = require('getRequestQueryParameter');\nconst getRequestQueryParameters = require('getRequestQueryParameters');\nconst getTimestampMillis = require('getTimestampMillis');\nconst getType = require('getType');\nconst JSON = require('JSON');\nconst makeInteger = require('makeInteger');\nconst makeString = require('makeString');\nconst Object = require('Object');\nconst returnResponse = require('returnResponse');\nconst runContainer = require('runContainer');\nconst setCookie = require('setCookie');\nconst setPixelResponse = require('setPixelResponse');\nconst setResponseBody = require('setResponseBody');\nconst setResponseHeader = require('setResponseHeader');\nconst setResponseStatus = require('setResponseStatus');\n\n/*==============================================================================\n==============================================================================*/\n\nconst requestMethod = getRequestMethod();\nconst path = getRequestPath();\nlet isClientUsed = false;\nlet isEventModelsWrappedInArray = false;\n\nif (path === '/data') {\n  runClient();\n}\n\nif (data.path && !isClientUsed) {\n  for (let key in data.path) {\n    if (!isClientUsed && data.path[key].path === path) {\n      runClient();\n    }\n  }\n}\n\n/*==============================================================================\n  Vendor related functions\n==============================================================================*/\n\nfunction runClient() {\n  isClientUsed = true;\n  require('claimRequest')();\n\n  if (requestMethod === 'OPTIONS') {\n    setCommonResponseHeaders(200);\n    returnResponse();\n    return;\n  }\n  const baseEventModel = getBaseEventModelWithQueryParameters();\n  let eventModels = getEventModels(baseEventModel);\n  const clientId = getClientId(eventModels);\n  eventModels = eventModels.map((eventModel) => {\n    eventModel = addRequiredParametersToEventModel(eventModel);\n    eventModel = addCommonParametersToEventModel(eventModel);\n    eventModel = addClientIdToEventModel(eventModel, clientId);\n    if (eventModel._dcid_temp) Object.delete(eventModel, '_dcid_temp');\n    return eventModel;\n  });\n\n  const consentDeclined = isConsentDeclined(data, eventModels[0]);\n  storeClientId(eventModels[0], consentDeclined);\n  exposeFPIDCookie(eventModels[0], consentDeclined);\n  prolongDataTagCookies(eventModels[0], consentDeclined);\n\n  const responseStatusCode = makeInteger(data.responseStatusCode || 200);\n  setCommonResponseHeaders(responseStatusCode);\n\n  let counter = 0;\n  eventModels.forEach((event) => {\n    runContainer(event, () => {\n      if (++counter === eventModels.length) {\n        switch (responseStatusCode) {\n          case 200:\n          case 201:\n            if (requestMethod === 'POST' || data.responseBodyGet) {\n              prepareResponseBody(eventModels);\n            } else {\n              setPixelResponse();\n            }\n            break;\n          case 301:\n          case 302:\n            setRedirectLocation();\n            break;\n          case 403:\n          case 404:\n            setClientErrorResponseMessage();\n            break;\n        }\n\n        returnResponse();\n      }\n    });\n  });\n}\n\nfunction addCommonParametersToEventModel(eventModel) {\n  if (!eventModel.ip_override) {\n    const ipOverride = eventModel.ip || eventModel.ipOverride || getRemoteAddress();\n    eventModel.ip_override = ipOverride;\n  }\n\n  if (!eventModel.user_agent) {\n    const userAgent = eventModel.userAgent || getRequestHeader('User-Agent');\n    if (userAgent) eventModel.user_agent = userAgent;\n  }\n\n  if (!eventModel.language) {\n    const acceptLanguageHeader = getRequestHeader('Accept-Language');\n    if (acceptLanguageHeader) {\n      eventModel.language = acceptLanguageHeader.split(';')[0].substring(0, 2).toLowerCase();\n    }\n  }\n\n  if (!eventModel.page_hostname) {\n    const pageHostname = eventModel.pageHostname || eventModel.hostname;\n    if (pageHostname) eventModel.page_hostname = pageHostname;\n  }\n\n  if (!eventModel.page_location) {\n    const pageLocation = eventModel.pageLocation || eventModel.url || eventModel.href;\n    if (pageLocation) eventModel.page_location = pageLocation;\n  }\n\n  if (!eventModel.page_referrer) {\n    const pageReferrer = eventModel.pageReferrer || eventModel.referrer || eventModel.urlref;\n    if (pageReferrer) eventModel.page_referrer = pageReferrer;\n  }\n\n  if (!eventModel.value && eventModel.e_v) eventModel.value = eventModel.e_v;\n\n  if (getType(eventModel.items) === 'array' && eventModel.items.length) {\n    const firstItem = eventModel.items[0];\n    if (!eventModel.currency && firstItem.currency) eventModel.currency = firstItem.currency;\n    if (eventModel.items.length === 1) {\n      if (!eventModel.item_id && firstItem.item_id) eventModel.item_id = firstItem.item_id;\n      if (!eventModel.item_name && firstItem.item_name) eventModel.item_name = firstItem.item_name;\n      if (!eventModel.item_brand && firstItem.item_brand)\n        eventModel.item_brand = firstItem.item_brand;\n      if (!eventModel.item_quantity && firstItem.quantity)\n        eventModel.item_quantity = firstItem.quantity;\n      if (!eventModel.item_category && firstItem.item_category)\n        eventModel.item_category = firstItem.item_category;\n      if (!eventModel.item_price && firstItem.price) eventModel.item_price = firstItem.price;\n    }\n    if (!eventModel.value) {\n      const valueFromItems = eventModel.items.reduce((acc, item) => {\n        if (!item.price) return acc;\n        const quantity = item.quantity ? item.quantity : 1;\n        return acc + quantity * item.price;\n      }, 0);\n      if (valueFromItems) eventModel.value = valueFromItems;\n    }\n  }\n\n  const ecommerceAction = getEcommerceAction(eventModel);\n\n  if (ecommerceAction) {\n    if (!eventModel['x-ga-mp1-pa']) eventModel['x-ga-mp1-pa'] = ecommerceAction;\n\n    if (ecommerceAction === 'purchase' && eventModel.ecommerce.purchase.actionField) {\n      if (!eventModel['x-ga-mp1-tr'])\n        eventModel['x-ga-mp1-tr'] = eventModel.ecommerce.purchase.actionField.revenue;\n      if (!eventModel.revenue)\n        eventModel.revenue = eventModel.ecommerce.purchase.actionField.revenue;\n      if (!eventModel.affiliation)\n        eventModel.affiliation = eventModel.ecommerce.purchase.actionField.affiliation;\n      if (!eventModel.tax) eventModel.tax = eventModel.ecommerce.purchase.actionField.tax;\n      if (!eventModel.shipping)\n        eventModel.shipping = eventModel.ecommerce.purchase.actionField.shipping;\n      if (!eventModel.coupon) eventModel.coupon = eventModel.ecommerce.purchase.actionField.coupon;\n      if (!eventModel.transaction_id)\n        eventModel.transaction_id = eventModel.ecommerce.purchase.actionField.id;\n    }\n  }\n\n  if (!eventModel.page_encoding && eventModel.pageEncoding)\n    eventModel.page_encoding = eventModel.pageEncoding;\n  if (!eventModel.page_path && eventModel.pagePath) eventModel.page_path = eventModel.pagePath;\n  if (!eventModel.page_title && eventModel.pageTitle) eventModel.page_title = eventModel.pageTitle;\n  if (!eventModel.screen_resolution && eventModel.screenResolution)\n    eventModel.screen_resolution = eventModel.screenResolution;\n  if (!eventModel.viewport_size && eventModel.viewportSize)\n    eventModel.viewport_size = eventModel.viewportSize;\n  if (!eventModel.user_id && eventModel.userId) eventModel.user_id = eventModel.userId;\n\n  if (!eventModel.user_data) {\n    let userData = {};\n    let userAddressData = {};\n\n    if (!userData.email_address) {\n      const emailAddress =\n        eventModel.userEmail || eventModel.email_address || eventModel.email || eventModel.mail;\n      if (emailAddress) userData.email_address = emailAddress;\n    }\n\n    if (!userData.phone_number) {\n      const phoneNumber =\n        eventModel.userPhoneNumber ||\n        eventModel.phone_number ||\n        eventModel.phoneNumber ||\n        eventModel.phone;\n      if (phoneNumber) userData.phone_number = phoneNumber;\n    }\n\n    if (!userAddressData.street && eventModel.street) userAddressData.street = eventModel.street;\n    if (!userAddressData.city && eventModel.city) userAddressData.city = eventModel.city;\n    if (!userAddressData.region && eventModel.region) userAddressData.region = eventModel.region;\n    if (!userAddressData.country && eventModel.country)\n      userAddressData.country = eventModel.country;\n\n    if (!userAddressData.first_name) {\n      const firstName =\n        eventModel.userFirstName ||\n        eventModel.first_name ||\n        eventModel.firstName ||\n        eventModel.name;\n      if (firstName) userAddressData.first_name = firstName;\n    }\n\n    if (!userAddressData.last_name) {\n      const lastName =\n        eventModel.userLastName ||\n        eventModel.last_name ||\n        eventModel.lastName ||\n        eventModel.surname ||\n        eventModel.family_name ||\n        eventModel.familyName;\n      if (lastName) userAddressData.last_name = lastName;\n    }\n\n    if (!userAddressData.region) {\n      if (eventModel.region) userAddressData.region = eventModel.region;\n      else if (eventModel.state) userAddressData.region = eventModel.state;\n    }\n\n    if (!userAddressData.postal_code) {\n      const postalCode = eventModel.postal_code || eventModel.postalCode || eventModel.zip;\n      if (postalCode) userAddressData.postal_code = postalCode;\n    }\n\n    if (getObjectLength(userAddressData) !== 0) {\n      userData.address = userAddressData;\n    }\n\n    if (!eventModel.user_data && getObjectLength(userData) !== 0) {\n      eventModel.user_data = userData;\n    }\n  }\n\n  return eventModel;\n}\n\nfunction getBaseEventModelWithQueryParameters() {\n  const requestQueryParameters = getRequestQueryParameters();\n  const eventModel = {};\n\n  if (requestQueryParameters) {\n    for (let queryParameterKey in requestQueryParameters) {\n      if (\n        (queryParameterKey === 'dtcd' || queryParameterKey === 'dtdc') &&\n        requestMethod === 'GET'\n      ) {\n        let dt =\n          queryParameterKey === 'dtcd'\n            ? JSON.parse(requestQueryParameters[queryParameterKey])\n            : JSON.parse(fromBase64(requestQueryParameters[queryParameterKey]));\n\n        for (let dtKey in dt) {\n          eventModel[dtKey] = dt[dtKey];\n        }\n      } else {\n        eventModel[queryParameterKey] = requestQueryParameters[queryParameterKey];\n      }\n    }\n  }\n\n  return eventModel;\n}\n\nfunction addClientIdToEventModel(eventModel, clientId) {\n  eventModel.client_id = clientId;\n  return eventModel;\n}\n\nfunction prolongDataTagCookies(eventModel, consentDeclined) {\n  if (consentDeclined || !data.prolongCookies) return;\n\n  const stapeData = getCookieValues('stape');\n  if (stapeData.length) {\n    setCookie('stape', stapeData[0], {\n      domain: 'auto',\n      path: '/',\n      samesite: getCookieType(eventModel),\n      secure: true,\n      'max-age': 63072000, // 2 years\n      httpOnly: false\n    });\n  }\n}\n\nfunction addRequiredParametersToEventModel(eventModel) {\n  if (!eventModel.event_name) {\n    const eventName = eventModel.eventName || eventModel.event || eventModel.e_n || 'Data';\n    eventModel.event_name = eventName;\n  }\n\n  return eventModel;\n}\n\nfunction exposeFPIDCookie(eventModel, consentDeclined) {\n  if (consentDeclined || !data.exposeFPIDCookie) return;\n\n  const fpid = getCookieValues('FPID');\n  if (fpid.length) {\n    setCookie('FPIDP', fpid[0], {\n      domain: 'auto',\n      path: '/',\n      samesite: getCookieType(eventModel),\n      secure: true,\n      'max-age': 63072000, // 2 years\n      httpOnly: false\n    });\n  }\n}\n\nfunction storeClientId(eventModel, consentDeclined) {\n  if (consentDeclined || !data.generateClientId) return;\n\n  setCookie('_dcid', eventModel.client_id, {\n    domain: 'auto',\n    path: '/',\n    samesite: getCookieType(eventModel),\n    secure: true,\n    'max-age': 63072000, // 2 years\n    httpOnly: data.httpOnlyCookie || false\n  });\n}\n\nfunction setCommonResponseHeaders(statusCode) {\n  setResponseHeader('Access-Control-Max-Age', '600');\n  setResponseHeader('Access-Control-Allow-Origin', getRequestHeader('origin'));\n  setResponseHeader('Access-Control-Allow-Methods', 'GET,POST,PUT,DELETE,OPTIONS');\n  setResponseHeader(\n    'Access-Control-Allow-Headers',\n    'content-type,set-cookie,x-robots-tag,x-gtm-server-preview,x-stape-preview,x-stape-app-version'\n  );\n  setResponseHeader('Access-Control-Allow-Credentials', 'true');\n  setResponseStatus(statusCode);\n}\n\nfunction getCookieType(eventModel) {\n  if (!eventModel.page_location) {\n    return 'Lax';\n  }\n\n  const host = getRequestHeader('host');\n  const effectiveTldPlusOne = computeEffectiveTldPlusOne(eventModel.page_location);\n\n  if (!host || !effectiveTldPlusOne) {\n    return 'Lax';\n  }\n\n  if (host && host.indexOf(effectiveTldPlusOne) !== -1) {\n    return 'Lax';\n  }\n\n  return 'None';\n}\n\nfunction prepareResponseBody(eventModels) {\n  if (data.responseBody === 'empty') {\n    return;\n  }\n\n  const responseModel = isEventModelsWrappedInArray ? eventModels[0] : eventModels;\n\n  setResponseHeader('Content-Type', 'application/json');\n\n  if (data.responseBody === 'eventData') {\n    setResponseBody(JSON.stringify(responseModel));\n\n    return;\n  }\n\n  if (isEventModelsWrappedInArray) {\n    setResponseBody(\n      JSON.stringify({\n        timestamp: responseModel.timestamp,\n        unique_event_id: responseModel.unique_event_id\n      })\n    );\n    return;\n  }\n\n  setResponseBody(\n    JSON.stringify(\n      eventModels.map((eventModel) => {\n        return {\n          timestamp: eventModel.timestamp,\n          unique_event_id: eventModel.unique_event_id\n        };\n      })\n    )\n  );\n}\n\nfunction getEcommerceAction(eventModel) {\n  if (eventModel.ecommerce) {\n    const actions = [\n      'detail',\n      'click',\n      'add',\n      'remove',\n      'checkout',\n      'checkout_option',\n      'purchase',\n      'refund'\n    ];\n\n    for (let index = 0; index < actions.length; ++index) {\n      const action = actions[index];\n\n      if (eventModel.ecommerce[action]) {\n        return action;\n      }\n    }\n  }\n\n  return null;\n}\n\nfunction setRedirectLocation() {\n  let location = data.redirectTo;\n  if (data.lookupForRedirectToParam && data.redirectToQueryParamName) {\n    const param = getRequestQueryParameter(data.redirectToQueryParamName);\n    if (param && param.startsWith('http')) {\n      location = param;\n    }\n  }\n  setResponseHeader('location', location);\n}\n\nfunction setClientErrorResponseMessage() {\n  if (data.clientErrorResponseMessage) {\n    setResponseBody(data.clientErrorResponseMessage);\n  }\n}\n\nfunction getEventModels(baseEventModel) {\n  const body = getRequestBody();\n\n  if (body) {\n    const contentType = getRequestHeader('content-type');\n    const isFormUrlEncoded =\n      !!contentType && contentType.indexOf('application/x-www-form-urlencoded') !== -1;\n    let bodyJson = isFormUrlEncoded ? parseUrlEncoded(body) : JSON.parse(body);\n    if (bodyJson) {\n      const bodyType = getType(bodyJson);\n      const shouldUseOriginalBody = data.acceptMultipleEvents && bodyType === 'array';\n      if (!shouldUseOriginalBody) {\n        bodyJson = [bodyJson];\n        isEventModelsWrappedInArray = true;\n      }\n\n      return bodyJson.map((bodyItem) => {\n        const eventModel = assign(\n          {\n            timestamp: makeInteger(getTimestampMillis() / 1000),\n            unique_event_id: getTimestampMillis() + '_' + generateRandom(100000000, 999999999)\n          },\n          baseEventModel\n        );\n        for (let bodyItemKey in bodyItem) {\n          eventModel[bodyItemKey] = bodyItem[bodyItemKey];\n        }\n        return eventModel;\n      });\n    }\n  }\n\n  return [\n    assign(\n      {\n        timestamp: makeInteger(getTimestampMillis() / 1000),\n        unique_event_id: getTimestampMillis() + '_' + generateRandom(100000000, 999999999)\n      },\n      baseEventModel\n    )\n  ];\n}\n\nfunction getClientId(eventModels) {\n  for (let i = 0; i < eventModels.length; i++) {\n    const eventModel = eventModels[i];\n    const clientId = eventModel.client_id || eventModel.data_client_id || eventModel._dcid;\n    if (clientId) return clientId;\n  }\n\n  const dcid = getCookieValues('_dcid');\n  if (dcid && dcid[0]) return dcid[0];\n\n  if (data.generateClientId) {\n    for (let i = 0; i < eventModels.length; i++) {\n      const eventModel = eventModels[i];\n      const tempClientId = eventModel._dcid_temp;\n      if (tempClientId) return tempClientId;\n    }\n\n    return 'dcid.1.' + getTimestampMillis() + '.' + generateRandom(100000000, 999999999);\n  }\n\n  return '';\n}\n\nfunction isConsentDeclined(data, eventData) {\n  const cookieStorageMode = data.cookieStorageMode;\n  if (!cookieStorageMode) return false;\n\n  if (cookieStorageMode === 'auto' && getType(eventData.consent_state) === 'object') {\n    // Check consent state from Stape's Data Tag\n    return eventData.consent_state[data.cookieConsentAutoParameter] === false;\n  } else if (cookieStorageMode === 'manual') {\n    // Check template field specific consent signal\n    return ['0', 0, 'false', false, 'denied'].indexOf(data.cookieConsentManualValue) !== -1;\n  }\n\n  return false;\n}\n\n/*==============================================================================\n  Helpers\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 assign() {\n  const target = arguments[0];\n  for (let i = 1; i < arguments.length; i++) {\n    for (let key in arguments[i]) {\n      target[key] = arguments[i][key];\n    }\n  }\n  return target;\n}\n\nfunction parseUrlEncoded(data) {\n  const pairs = data.split('&');\n  const parsedData = {};\n  const regex = createRegex('\\\\+', 'g');\n  for (const pair of pairs) {\n    const pairValue = pair.split('=');\n    const key = pairValue[0];\n    const value = pairValue[1];\n    const keys = key.split('.').map((k) => decodeUriComponent(k.replace(regex, ' ')));\n\n    let currentObject = parsedData;\n\n    for (let i = 0; i < keys.length - 1; i++) {\n      const currentKey = keys[i];\n\n      if (!currentObject[currentKey]) {\n        const nextKey = keys[i + 1];\n        const nextKeyIsNumber = makeString(makeInteger(nextKey)) === nextKey;\n        currentObject[currentKey] = nextKeyIsNumber ? [] : {};\n      }\n\n      currentObject = currentObject[currentKey];\n    }\n\n    const lastKey = keys[keys.length - 1];\n    const decodedValue = decodeUriComponent(value.replace(regex, ' '));\n    const parsedValue = JSON.parse(decodedValue) || decodedValue;\n\n    if (getType(currentObject) === 'array') {\n      currentObject.push(parsedValue);\n    } else {\n      currentObject[lastKey] = parsedValue;\n    }\n  }\n\n  return parsedData;\n}\n\n\n___SERVER_PERMISSIONS___\n\n[\n  {\n    \"instance\": {\n      \"key\": {\n        \"publicId\": \"return_response\",\n        \"versionId\": \"1\"\n      },\n      \"param\": []\n    },\n    \"isRequired\": true\n  },\n  {\n    \"instance\": {\n      \"key\": {\n        \"publicId\": \"access_response\",\n        \"versionId\": \"1\"\n      },\n      \"param\": [\n        {\n          \"key\": \"writeResponseAccess\",\n          \"value\": {\n            \"type\": 1,\n            \"string\": \"any\"\n          }\n        },\n        {\n          \"key\": \"writeHeaderAccess\",\n          \"value\": {\n            \"type\": 1,\n            \"string\": \"specific\"\n          }\n        }\n      ]\n    },\n    \"clientAnnotations\": {\n      \"isEditedByUser\": true\n    },\n    \"isRequired\": true\n  },\n  {\n    \"instance\": {\n      \"key\": {\n        \"publicId\": \"run_container\",\n        \"versionId\": \"1\"\n      },\n      \"param\": []\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\": \"_dcid\"\n              },\n              {\n                \"type\": 1,\n                \"string\": \"FPIDP\"\n              },\n              {\n                \"type\": 1,\n                \"string\": \"FPID\"\n              }\n            ]\n          }\n        }\n      ]\n    },\n    \"clientAnnotations\": {\n      \"isEditedByUser\": true\n    },\n    \"isRequired\": true\n  },\n  {\n    \"instance\": {\n      \"key\": {\n        \"publicId\": \"read_request\",\n        \"versionId\": \"1\"\n      },\n      \"param\": [\n        {\n          \"key\": \"requestAccess\",\n          \"value\": {\n            \"type\": 1,\n            \"string\": \"any\"\n          }\n        },\n        {\n          \"key\": \"headerAccess\",\n          \"value\": {\n            \"type\": 1,\n            \"string\": \"any\"\n          }\n        },\n        {\n          \"key\": \"queryParameterAccess\",\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\": \"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                \"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\": \"_dcid\"\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                \"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\": \"FPIDP\"\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\n\n___TESTS___\n\nscenarios:\n- name: runContainer is called succesfully for a single event and response is sent\n    back once\n  code: \"mock('getRequestPath', '/data');\\nmock('getRequestMethod', 'POST');\\nmock('getRequestBody',\\\n    \\ '{\\\"event\\\":\\\"page_view\\\",\\\"client_id\\\":\\\"client_id\\\"}');\\n\\n/* \\n  For some\\\n    \\ reason when we use \\\"assertApi('claimRequest').wasCalled()\\\" AND we run all\\\n    \\ the tests,\\n  it produces the following error \\\"Tried to claim a request after\\\n    \\ a Client had returned. Calling claimRequest from a callback is not supported.\\\"\\\n    \\n  If we run only this single test, the error does not occur.\\n  A workaround\\\n    \\ is to mock 'claimRequest' API and make a dummy assertion in the mocked function.\\\n    \\ This way we make sure it's been called.\\n*/\\nlet claimRequestWasCalled;\\nmock('claimRequest',\\\n    \\ () => {\\n  claimRequestWasCalled = true;\\n});\\n\\nlet runContainerExecutions\\\n    \\ = 0;\\nconst runContainerExpectedExecutions = 1;\\nmock('runContainer', (eventData,\\\n    \\ onCompleteCallback, onStartCallback) => {\\n  assertThat(eventData).isObject();\\n\\\n    \\  runContainerExecutions++;\\n  assertThat(onCompleteCallback).isFunction();\\n\\\n    \\  onCompleteCallback();\\n});\\n\\nmock('returnResponse', () => {\\n  if (runContainerExecutions\\\n    \\ !== runContainerExpectedExecutions) {\\n    fail('returnResponse should be called\\\n    \\ by the last runContainer onComplete callback execution only.');\\n    return;\\n\\\n    \\  }\\n  assertThat(true).isTrue(); // Dummy to cover the case when runContainerExecutions\\\n    \\ === runContainerExpectedExecutions.\\n});\\n\\nrunCode(mockData);\\n\\ncallLater(()\\\n    \\ => {\\n  assertThat(claimRequestWasCalled).isTrue();\\n  assertApi('setResponseStatus').wasCalledWith(200);\\n\\\n    \\  assertThat(runContainerExecutions).isEqualTo(runContainerExpectedExecutions);\\n\\\n    });\"\n- name: runContainer is called succesfully for multiple events and response is sent\n    back once\n  code: \"mockData.acceptMultipleEvents = true;\\n\\nmock('getRequestPath', '/data');\\n\\\n    mock('getRequestMethod', 'POST');\\nmock('getRequestBody', '[{\\\"event\\\":\\\"page_view\\\"\\\n    ,\\\"client_id\\\":\\\"client_id\\\"},{\\\"event\\\":\\\"view_item\\\",\\\"client_id\\\":\\\"client_id\\\"\\\n    }]');\\n\\n/* \\n  For some reason when we use \\\"assertApi('claimRequest').wasCalled()\\\"\\\n    \\ AND we run all the tests,\\n  it produces the following error \\\"Tried to claim\\\n    \\ a request after a Client had returned. Calling claimRequest from a callback\\\n    \\ is not supported.\\\"\\n  If we run only this single test, the error does not occur.\\n\\\n    \\  A workaround is to mock 'claimRequest' API and make a dummy assertion in the\\\n    \\ mocked function. This way we make sure it's been called.\\n*/\\nlet claimRequestWasCalled;\\n\\\n    mock('claimRequest', () => {\\n  claimRequestWasCalled = true;\\n});\\n\\nlet runContainerExecutions\\\n    \\ = 0;\\nconst runContainerExpectedExecutions = 2;\\nmock('runContainer', (eventData,\\\n    \\ onCompleteCallback, onStartCallback) => {\\n  assertThat(eventData).isObject();\\n\\\n    \\  runContainerExecutions++;\\n  assertThat(onCompleteCallback).isFunction();\\n\\\n    \\  onCompleteCallback();\\n});\\n\\nmock('returnResponse', () => {\\n  if (runContainerExecutions\\\n    \\ !== runContainerExpectedExecutions) {\\n    fail('returnResponse should be called\\\n    \\ by the last runContainer onComplete callback execution only.');\\n    return;\\n\\\n    \\  }\\n  assertThat(true).isTrue(); // Dummy to cover the case when runContainerExecutions\\\n    \\ === runContainerExpectedExecutions.\\n});\\n\\nrunCode(mockData);\\n\\ncallLater(()\\\n    \\ => {\\n  assertThat(claimRequestWasCalled).isTrue();\\n  assertApi('setResponseStatus').wasCalledWith(200);\\n\\\n    \\  assertThat(runContainerExecutions).isEqualTo(runContainerExpectedExecutions);\\n\\\n    });\"\n- name: Should fallback to 200 if Response Status Code is absent from the data object\n  code: \"mockData.acceptMultipleEvents = true;\\n\\nObject.delete(mockData, 'responseStatusCode');\\n\\\n    \\nmock('getRequestPath', '/data');\\nmock('getRequestMethod', 'POST');\\nmock('getRequestBody',\\\n    \\ '[{\\\"event\\\":\\\"page_view\\\",\\\"client_id\\\":\\\"client_id\\\"},{\\\"event\\\":\\\"view_item\\\"\\\n    ,\\\"client_id\\\":\\\"client_id\\\"}]');\\n\\n/* \\n  For some reason when we use \\\"assertApi('claimRequest').wasCalled()\\\"\\\n    \\ AND we run all the tests,\\n  it produces the following error \\\"Tried to claim\\\n    \\ a request after a Client had returned. Calling claimRequest from a callback\\\n    \\ is not supported.\\\"\\n  If we run only this single test, the error does not occur.\\n\\\n    \\  A workaround is to mock 'claimRequest' API and make a dummy assertion in the\\\n    \\ mocked function. This way we make sure it's been called.\\n*/\\nlet claimRequestWasCalled;\\n\\\n    mock('claimRequest', () => {\\n  claimRequestWasCalled = true;\\n});\\n\\nmock('setResponseStatus',\\\n    \\ (responseStatus) => {\\n  assertThat(responseStatus).isEqualTo(200);\\n});\\n\\n\\\n    /*\\n  For some reason when we mock 'claimRequest', the following error is shown\\\n    \\ when the test is run: 'Request must be claimed before calling runContainer.'\\n\\\n    \\  A workaround is to mock 'runContainer' and simply call its callbacks.\\n*/\\n\\\n    mock('runContainer', (eventData, onCompleteCallback, onStartCallback) => {\\n \\\n    \\ onCompleteCallback();\\n});\\n\\nrunCode(mockData);\\n\\ncallLater(() => {\\n  assertThat(claimRequestWasCalled).isTrue();\\n\\\n    \\  assertApi('returnResponse').wasCalled();\\n});\"\n- name: Client ID retrieval and generation (from _dcid cookie, from Event Data pre-defined\n    keys and from Temporary Client ID)\n  code: \"const originalMockData = mockData;\\n\\nmock('getRequestPath', '/data');\\n\\\n    mock('getRequestMethod', 'POST');\\n\\n[\\n  {\\n    description: 'Should use Client\\\n    \\ ID from Event Model if one is present',\\n    mockData: {\\n      generateClientId:\\\n    \\ true,\\n      acceptMultipleEvents: true\\n    },\\n    mock: () => {\\n      mock('getRequestBody',\\\n    \\ '[{\\\"event\\\":\\\"page_view\\\",\\\"client_id\\\":\\\"client_id\\\",\\\"_dcid_temp\\\":\\\"_dcid_temp\\\"\\\n    },{\\\"event\\\":\\\"view_item\\\",\\\"_dcid\\\":\\\"_dcid\\\",\\\"_dcid_temp\\\":\\\"_dcid_temp\\\"}]');\\n\\\n    \\      mock('getCookieValues', []);\\n    },\\n    assert: (eventData) => {\\n  \\\n    \\    assertThat(eventData.client_id).isEqualTo('client_id'); // The first found\\\n    \\ Client ID is used for all events in the payload.\\n    }\\n  },\\n  {\\n    description:\\\n    \\ 'Should use Client ID from _dcid cookie if present and no Client ID is present\\\n    \\ in Event Model',\\n    mockData: {\\n      generateClientId: true,\\n      acceptMultipleEvents:\\\n    \\ true\\n    }, \\n    mock: () => {\\n      mock('getRequestBody', '[{\\\"event\\\"\\\n    :\\\"page_view\\\",\\\"_dcid_temp\\\":\\\"_dcid_temp\\\"},{\\\"event\\\":\\\"view_item\\\",\\\"_dcid_temp\\\"\\\n    :\\\"_dcid_temp\\\"}]');\\n      mock('getCookieValues', ['_dcid_from_cookie']);\\n\\\n    \\    },\\n    assert: (eventData) => {\\n      assertThat(eventData.client_id).isEqualTo('_dcid_from_cookie');\\n\\\n    \\    }\\n  },\\n  { \\n    description: 'Should use Client ID from temporary Client\\\n    \\ ID if option is enabled, and it is present in Event Model and, _dcid cookie\\\n    \\ or Client ID in Event Data do not exist',\\n    mockData: {\\n      generateClientId:\\\n    \\ true,\\n      acceptMultipleEvents: true\\n    },\\n    mock: () => {\\n      mock('getRequestBody',\\\n    \\ '[{\\\"event\\\":\\\"page_view\\\",\\\"_dcid_temp\\\":\\\"_dcid_temp\\\"},{\\\"event\\\":\\\"view_item\\\"\\\n    ,\\\"_dcid_temp\\\":\\\"_dcid_temp\\\"}]');\\n      mock('getCookieValues', []);\\n    },\\n\\\n    \\    assert: (eventData) => {\\n      assertThat(eventData.client_id).isEqualTo('_dcid_temp');\\n\\\n    \\    }\\n  },\\n  { \\n    description: 'Should generate a random Client ID if option\\\n    \\ is enabled, and _dcid cookie or Client ID in Event Data or temporary Client\\\n    \\ ID do not exist',\\n    mockData: {\\n      generateClientId: true,\\n      acceptMultipleEvents:\\\n    \\ true\\n    },\\n    mock: () => {\\n      mock('getRequestBody', '[{\\\"event\\\":\\\"\\\n    page_view\\\"},{\\\"event\\\":\\\"view_item\\\"}]');\\n      mock('getCookieValues', []);\\n\\\n    \\    },\\n    assert: (eventData) => {\\n      assertThat(eventData.client_id).isEqualTo('dcid.1.1747945830456.123456789');\\n\\\n    \\    }\\n  },\\n  { \\n    description: 'Should NOT generate a random Client ID or\\\n    \\ use temporary Client ID if option is disabled',\\n    mockData: {\\n      generateClientId:\\\n    \\ false,\\n      acceptMultipleEvents: true\\n    },\\n    mock: () => {\\n      mock('getRequestBody',\\\n    \\ '[{\\\"event\\\":\\\"page_view\\\"},{\\\"event\\\":\\\"view_item\\\"}]');\\n      mock('getCookieValues',\\\n    \\ []);\\n    },\\n    assert: (eventData) => {\\n      assertThat(eventData.client_id).isFalsy();\\n\\\n    \\    }\\n  }\\n].forEach(scenario => {\\n  const copyMockData = JSON.parse(JSON.stringify(originalMockData));\\n\\\n    \\  mergeObj(copyMockData, scenario.mockData);\\n  \\n  scenario.mock();\\n  \\n  /*\\\n    \\ \\n    For some reason when we use \\\"assertApi('claimRequest').wasCalled()\\\"\\\n    \\ AND we run all the tests,\\n    it produces the following error \\\"Tried to claim\\\n    \\ a request after a Client had returned. Calling claimRequest from a callback\\\n    \\ is not supported.\\\"\\n    If we run only this single test, the error does not\\\n    \\ occur.\\n    A workaround is to mock 'claimRequest' API and make a dummy assertion\\\n    \\ in the mocked function. This way we make sure it's been called.\\n  */\\n  let\\\n    \\ claimRequestWasCalled;\\n  mock('claimRequest', () => {\\n    claimRequestWasCalled\\\n    \\ = true;\\n  });\\n  \\n  mock('setResponseStatus', (responseStatus) => {\\n    assertThat(responseStatus).isEqualTo(200);\\n\\\n    \\  });\\n  \\n  /*\\n    For some reason when we mock 'claimRequest', the following\\\n    \\ error is shown when the test is run: 'Request must be claimed before calling\\\n    \\ runContainer.'\\n    A workaround is to mock 'runContainer' and simply call its\\\n    \\ callbacks.\\n  */\\n  mock('runContainer', (eventData, onCompleteCallback, onStartCallback)\\\n    \\ => {\\n    assertThat(eventData.hasOwnProperty('_temp_dcid')).isFalse();\\n  \\\n    \\  scenario.assert(eventData);\\n    onCompleteCallback();  \\n  });\\n  \\n  runCode(copyMockData);\\n\\\n    \\  \\n  callLater(() => {\\n    assertThat(claimRequestWasCalled).isTrue();\\n  \\\n    \\  assertApi('returnResponse').wasCalled();\\n  });\\n});\"\n- name: '[Cookie Consent] Consent declined scenarios - setCookie is not called'\n  code: \"mockData.prolongCookies = true;\\nmockData.generateClientId = true;\\nmockData.exposeFPIDCookie\\\n    \\ = true;\\n\\nmock('getRequestPath', '/data');\\nmock('getRequestMethod', 'POST');\\n\\\n    \\nconst cleanup = () => {\\n  mock('getCookieValues', () => []);\\n};\\n\\n[\\n  {\\n\\\n    \\    description: 'auto mode - consent_state analytics_storage declined',\\n  \\\n    \\  dataOverrides: { cookieStorageMode: 'auto', cookieConsentAutoParameter: 'analytics_storage'\\\n    \\ },\\n    body: '{\\\"event\\\":\\\"page_view\\\",\\\"client_id\\\":\\\"cid_123\\\",\\\"consent_state\\\"\\\n    :{\\\"analytics_storage\\\":false}}'\\n  },\\n  {\\n    description: 'manual mode - denied\\\n    \\ value 0 (string)',\\n    dataOverrides: { cookieStorageMode: 'manual', cookieConsentManualValue:\\\n    \\ '0' },\\n    body: '{\\\"event\\\":\\\"page_view\\\",\\\"client_id\\\":\\\"cid_123\\\"}'\\n  },\\n\\\n    \\  {\\n    description: 'manual mode - denied value false (string)',\\n    dataOverrides:\\\n    \\ { cookieStorageMode: 'manual', cookieConsentManualValue: 'false' },\\n    body:\\\n    \\ '{\\\"event\\\":\\\"page_view\\\",\\\"client_id\\\":\\\"cid_123\\\"}'\\n  },\\n  {\\n    description:\\\n    \\ 'manual mode - denied value denied',\\n    dataOverrides: { cookieStorageMode:\\\n    \\ 'manual', cookieConsentManualValue: 'denied' },\\n    body: '{\\\"event\\\":\\\"page_view\\\"\\\n    ,\\\"client_id\\\":\\\"cid_123\\\"}'\\n  }\\n].forEach(scenario => {\\n  cleanup();\\n\\n \\\n    \\ const copyMockData = JSON.parse(JSON.stringify(mockData));\\n  mergeObj(copyMockData,\\\n    \\ scenario.dataOverrides);\\n\\n  mock('getRequestBody', scenario.body);\\n\\n  let\\\n    \\ claimRequestWasCalled;\\n  mock('claimRequest', () => { claimRequestWasCalled\\\n    \\ = true; });\\n  mock('runContainer', (eventData, onCompleteCallback) => { onCompleteCallback();\\\n    \\ });\\n  \\n  runCode(copyMockData);\\n\\n  callLater(() => {\\n    assertThat(claimRequestWasCalled).isTrue();\\n\\\n    \\    assertApi('setCookie').wasNotCalled();\\n    assertApi('returnResponse').wasCalled();\\n\\\n    \\  });\\n});\"\n- name: '[Cookie Consent] Consent granted scenarios - setCookie is called'\n  code: |-\n    mockData.prolongCookies = true;\n    mockData.generateClientId = true;\n    mockData.exposeFPIDCookie = true;\n\n    mock('getRequestPath', '/data');\n    mock('getRequestMethod', 'POST');\n\n    const cleanup = () => {\n      mock('getCookieValues', () => []);\n    };\n\n    [\n      {\n        description: 'no cookieStorageMode - consent not declined',\n        dataOverrides: {},\n        body: '{\"event\":\"page_view\",\"client_id\":\"cid_123\"}'\n      },\n      {\n        description: 'auto mode - consent_state analytics_storage granted',\n        dataOverrides: { cookieStorageMode: 'auto', cookieConsentAutoParameter: 'analytics_storage' },\n        body: '{\"event\":\"page_view\",\"client_id\":\"cid_123\",\"consent_state\":{\"analytics_storage\":true}}'\n      },\n      {\n        description: 'auto mode - no autoConsentParameter - consent not declined',\n        dataOverrides: { cookieStorageMode: 'auto' },\n        body: '{\"event\":\"page_view\",\"client_id\":\"cid_123\",\"consent_state\":{\"analytics_storage\":false}}'\n      },\n      {\n        description: 'manual mode - granted value',\n        dataOverrides: { cookieStorageMode: 'manual', cookieConsentManualValue: 'granted' },\n        body: '{\"event\":\"page_view\",\"client_id\":\"cid_123\"}'\n      }\n    ].forEach(scenario => {\n      cleanup();\n\n      const copyMockData = JSON.parse(JSON.stringify(mockData));\n      mergeObj(copyMockData, scenario.dataOverrides);\n\n      mock('getRequestBody', scenario.body);\n\n      let claimRequestWasCalled;\n      mock('claimRequest', () => { claimRequestWasCalled = true; });\n      mock('runContainer', (eventData, onCompleteCallback) => { onCompleteCallback(); });\n\n      runCode(copyMockData);\n\n      callLater(() => {\n        assertThat(claimRequestWasCalled).isTrue();\n        assertApi('setCookie').wasCalled();\n        assertApi('returnResponse').wasCalled();\n      });\n    });\nsetup: |-\n  const JSON = require('JSON');\n  const Object = require('Object');\n  const callLater = require('callLater');\n\n  function mergeObj(target, source) {\n    for (const key in source) {\n      if (source.hasOwnProperty(key)) target[key] = source[key];\n    }\n    return target;\n  }\n\n  const mockData = {\n    responseStatusCode: 200,\n    generateClientId: true,\n    responseBody: 'timestamp',\n    prolongCookies: true,\n    httpOnlyCookie: false,\n    responseBodyGet: false,\n    acceptMultipleEvents: false,\n    exposeFPIDCookie: false\n  };\n\n  mock('getRequestHeader', (header) => {\n    if (header === 'trace-id') return 'expectedTraceId';\n  });\n\n  mock('getTimestampMillis', 1747945830456);\n\n  mock('generateRandom', 123456789);\n\n\n___NOTES___\n\n2026-08-12 - Change Notes:\n  - Improve \"Generate Client ID\" field help text.\n\n2026-05-22 - Change Notes:\n  - Add cookie consent gating: new \"Cookie Consent Settings\" parameter group lets users skip all setCookie calls when consent is denied, using either auto-detection (via Data Tag's consent_state) or a manual GTM variable\n  - Refactor property fallback chains from if/else to || short-circuit for cleaner code; behavior is unchanged\n  - Fix broken test mock: mock('requestMethod') corrected to mock('getRequestMethod') across existing test scenarios\n\nCreated on 21/03/2021, 11:24:30\n\n\n"
            }
        ],
        "client": [
            {
                "accountId": "6374306328",
                "containerId": "262778781",
                "clientId": "7",
                "name": "GA4",
                "type": "gaaw_client",
                "parameter": [
                    {
                        "type": "TEMPLATE",
                        "key": "cookieDomain",
                        "value": "auto"
                    },
                    {
                        "type": "TEMPLATE",
                        "key": "cookieMaxAgeInSec",
                        "value": "63072000"
                    },
                    {
                        "type": "BOOLEAN",
                        "key": "activateDefaultPaths",
                        "value": "true"
                    },
                    {
                        "type": "TEMPLATE",
                        "key": "cookiePath",
                        "value": "/"
                    },
                    {
                        "type": "BOOLEAN",
                        "key": "migrateFromJsClientId",
                        "value": "false"
                    },
                    {
                        "type": "TEMPLATE",
                        "key": "cookieManagement",
                        "value": "server"
                    },
                    {
                        "type": "TEMPLATE",
                        "key": "cookieName",
                        "value": "FPID"
                    }
                ],
                "fingerprint": "1788192494720"
            },
            {
                "accountId": "6374306328",
                "containerId": "262778781",
                "clientId": "8",
                "name": "Data Client",
                "type": "cvt_262778781_19",
                "parameter": [
                    {
                        "type": "INTEGER",
                        "key": "responseStatusCode",
                        "value": "200"
                    },
                    {
                        "type": "LIST",
                        "key": "path",
                        "list": [
                            {
                                "type": "MAP",
                                "map": [
                                    {
                                        "type": "TEMPLATE",
                                        "key": "path",
                                        "value": "/data"
                                    }
                                ]
                            }
                        ]
                    },
                    {
                        "type": "BOOLEAN",
                        "key": "generateClientId",
                        "value": "true"
                    },
                    {
                        "type": "TEMPLATE",
                        "key": "responseBody",
                        "value": "timestamp"
                    },
                    {
                        "type": "BOOLEAN",
                        "key": "prolongCookies",
                        "value": "true"
                    },
                    {
                        "type": "BOOLEAN",
                        "key": "httpOnlyCookie",
                        "value": "false"
                    },
                    {
                        "type": "BOOLEAN",
                        "key": "responseBodyGet",
                        "value": "false"
                    },
                    {
                        "type": "BOOLEAN",
                        "key": "acceptMultipleEvents",
                        "value": "false"
                    },
                    {
                        "type": "BOOLEAN",
                        "key": "exposeFPIDCookie",
                        "value": "false"
                    }
                ],
                "fingerprint": "1791000829716"
            }
        ],
        "transformation": [
            {
                "accountId": "6374306328",
                "containerId": "262778781",
                "transformationId": "11",
                "name": "For Tiktok",
                "type": "tf_exclude_params",
                "parameter": [
                    {
                        "type": "LIST",
                        "key": "excludedParamsTable",
                        "list": [
                            {
                                "type": "MAP",
                                "map": [
                                    {
                                        "type": "TEMPLATE",
                                        "key": "excludedParams",
                                        "value": "ttclid"
                                    }
                                ]
                            },
                            {
                                "type": "MAP",
                                "map": [
                                    {
                                        "type": "TEMPLATE",
                                        "key": "excludedParams",
                                        "value": "ttp"
                                    }
                                ]
                            }
                        ]
                    },
                    {
                        "type": "BOOLEAN",
                        "key": "matchingConditionsEnabled",
                        "value": "false"
                    },
                    {
                        "type": "BOOLEAN",
                        "key": "allTagsExcept",
                        "value": "true"
                    },
                    {
                        "type": "TEMPLATE",
                        "key": "booleanExpressionString"
                    },
                    {
                        "type": "LIST",
                        "key": "affectedTags",
                        "list": [
                            {
                                "type": "MAP",
                                "map": [
                                    {
                                        "type": "TAG_REFERENCE",
                                        "key": "tagReference",
                                        "value": "TikTok Events API",
                                        "isWeakReference": true
                                    }
                                ]
                            },
                            {
                                "type": "MAP",
                                "map": [
                                    {
                                        "type": "TAG_REFERENCE",
                                        "key": "tagReference",
                                        "value": "PixelFly COD Protection (hold)",
                                        "isWeakReference": true
                                    }
                                ]
                            },
                            {
                                "type": "MAP",
                                "map": [
                                    {
                                        "type": "TAG_REFERENCE",
                                        "key": "tagReference",
                                        "value": "Google Ads Conversion (COD confirmed)",
                                        "isWeakReference": true
                                    }
                                ]
                            }
                        ]
                    },
                    {
                        "type": "LIST",
                        "key": "affectedTagTypes"
                    }
                ],
                "fingerprint": "1791000829716"
            },
            {
                "accountId": "6374306328",
                "containerId": "262778781",
                "transformationId": "16",
                "name": "For Facebook",
                "type": "tf_exclude_params",
                "parameter": [
                    {
                        "type": "LIST",
                        "key": "excludedParamsTable",
                        "list": [
                            {
                                "type": "MAP",
                                "map": [
                                    {
                                        "type": "TEMPLATE",
                                        "key": "excludedParams",
                                        "value": "x-fb-ck-fbp"
                                    }
                                ]
                            },
                            {
                                "type": "MAP",
                                "map": [
                                    {
                                        "type": "TEMPLATE",
                                        "key": "excludedParams",
                                        "value": "x-fb-ck-fbc"
                                    }
                                ]
                            },
                            {
                                "type": "MAP",
                                "map": [
                                    {
                                        "type": "TEMPLATE",
                                        "key": "excludedParams",
                                        "value": "first_party_collection"
                                    }
                                ]
                            },
                            {
                                "type": "MAP",
                                "map": [
                                    {
                                        "type": "TEMPLATE",
                                        "key": "excludedParams",
                                        "value": "x-fb-ud-external_id"
                                    }
                                ]
                            },
                            {
                                "type": "MAP",
                                "map": [
                                    {
                                        "type": "TEMPLATE",
                                        "key": "excludedParams",
                                        "value": "x-fb-cd-content_name"
                                    }
                                ]
                            },
                            {
                                "type": "MAP",
                                "map": [
                                    {
                                        "type": "TEMPLATE",
                                        "key": "excludedParams",
                                        "value": "x-fb-cd-content_type"
                                    }
                                ]
                            },
                            {
                                "type": "MAP",
                                "map": [
                                    {
                                        "type": "TEMPLATE",
                                        "key": "excludedParams",
                                        "value": "x-fb-cd-content_ids"
                                    }
                                ]
                            },
                            {
                                "type": "MAP",
                                "map": [
                                    {
                                        "type": "TEMPLATE",
                                        "key": "excludedParams",
                                        "value": "items"
                                    }
                                ]
                            },
                            {
                                "type": "MAP",
                                "map": [
                                    {
                                        "type": "TEMPLATE",
                                        "key": "excludedParams",
                                        "value": "x-fb-cd-num_items"
                                    }
                                ]
                            },
                            {
                                "type": "MAP",
                                "map": [
                                    {
                                        "type": "TEMPLATE",
                                        "key": "excludedParams",
                                        "value": "transaction_id"
                                    }
                                ]
                            },
                            {
                                "type": "MAP",
                                "map": [
                                    {
                                        "type": "TEMPLATE",
                                        "key": "excludedParams",
                                        "value": "shipping"
                                    }
                                ]
                            }
                        ]
                    },
                    {
                        "type": "BOOLEAN",
                        "key": "matchingConditionsEnabled",
                        "value": "false"
                    },
                    {
                        "type": "BOOLEAN",
                        "key": "allTagsExcept",
                        "value": "true"
                    },
                    {
                        "type": "TEMPLATE",
                        "key": "booleanExpressionString"
                    },
                    {
                        "type": "LIST",
                        "key": "affectedTags",
                        "list": [
                            {
                                "type": "MAP",
                                "map": [
                                    {
                                        "type": "TAG_REFERENCE",
                                        "key": "tagReference",
                                        "value": "Facebook CAPI",
                                        "isWeakReference": true
                                    }
                                ]
                            },
                            {
                                "type": "MAP",
                                "map": [
                                    {
                                        "type": "TAG_REFERENCE",
                                        "key": "tagReference",
                                        "value": "GA4-Server Side",
                                        "isWeakReference": true
                                    }
                                ]
                            },
                            {
                                "type": "MAP",
                                "map": [
                                    {
                                        "type": "TAG_REFERENCE",
                                        "key": "tagReference",
                                        "value": "Facebook Conversion API Tag",
                                        "isWeakReference": true
                                    }
                                ]
                            },
                            {
                                "type": "MAP",
                                "map": [
                                    {
                                        "type": "TAG_REFERENCE",
                                        "key": "tagReference",
                                        "value": "PixelFly COD Protection (hold)",
                                        "isWeakReference": true
                                    }
                                ]
                            },
                            {
                                "type": "MAP",
                                "map": [
                                    {
                                        "type": "TAG_REFERENCE",
                                        "key": "tagReference",
                                        "value": "Google Ads Conversion (COD confirmed)",
                                        "isWeakReference": true
                                    }
                                ]
                            }
                        ]
                    },
                    {
                        "type": "LIST",
                        "key": "affectedTagTypes"
                    }
                ],
                "fingerprint": "1791000829716"
            }
        ]
    }
}